Estoy creando un juego que utiliza objetos de juego basados en componentes, y estoy teniendo dificultades para implementar una forma para que cada componente se comunique con su objeto de juego. En lugar de explicar todo de una vez, explicaré cada parte del código de muestra relevante:
class GameObjectManager {
    public:
        //Updates all the game objects
        void update(Time dt);
        //Sends a message to all game objects
        void sendMessage(Message m);
    private:
        //Vector of all the game objects
        std::vector<GameObject> gameObjects;
        //vectors of the different types of components
        std::vector<InputComponent> input;
        std::vector<PhysicsComponent> ai;
        ...
        std::vector<RenderComponent> render;
}
El GameObjectManagertiene todos los objetos del juego y sus componentes. También es responsable de actualizar los objetos del juego. Lo hace actualizando los vectores componentes en un orden específico. Utilizo vectores en lugar de matrices para que prácticamente no haya límite en la cantidad de objetos de juego que pueden existir a la vez.
class GameObject {
    public:
        //Sends a message to the components in this game object
        void sendMessage(Message m);
    private:
        //id to keep track of components in the manager
        const int id;
        //Pointers to components in the game object manager
        std::vector<Component*> components;
}
La GameObjectclase sabe cuáles son sus componentes y puede enviarles mensajes.
class Component {
    public:
        //Receives messages and acts accordingly
        virtual void handleMessage(Message m) = 0;
        virtual void update(Time dt) = 0;
    protected:
        //Calls GameObject's sendMessage
        void sendMessageToObject(Message m);
        //Calls GameObjectManager's sendMessage
        void sendMessageToWorld(Message m);
}
La Componentclase es puramente virtual, de modo que las clases para los diferentes tipos de componentes pueden implementar cómo manejar los mensajes y actualizarlos. También puede enviar mensajes.
Ahora surge el problema de cómo los componentes pueden llamar a las sendMessagefunciones en GameObjecty GameObjectManager. Se me ocurrieron dos posibles soluciones:
- Dar Componentun puntero a suGameObject.
Sin embargo, dado que los objetos del juego están en un vector, los punteros podrían invalidarse rápidamente (lo mismo podría decirse del vector en GameObject, pero es de esperar que la solución a este problema también pueda resolverlo). Podría poner los objetos del juego en una matriz, pero luego tendría que pasar un número arbitrario para el tamaño, que fácilmente podría ser innecesariamente alto y desperdiciar memoria.
- Dar Componentun puntero a laGameObjectManager.
Sin embargo, no quiero que los componentes puedan llamar a la función de actualización del administrador. Soy la única persona que trabaja en este proyecto, pero no quiero acostumbrarme a escribir código potencialmente peligroso.
¿Cómo puedo resolver este problema mientras mantengo mi código seguro y amigable con la caché?

Ser 'amigable con el caché' es una preocupación que tienen los grandes juegos . Esto parece ser una optimización prematura para mí.
Una forma de resolver esto sin ser 'amigable con la caché' sería crear su objeto en el montón en lugar de en la pila: use
newpunteros (inteligentes) para sus objetos. De esta manera, podrá hacer referencia a sus objetos y su referencia no se invalidará.Para una solución más amigable con la memoria caché, puede administrar la desasignación / asignación de objetos usted mismo y usar controladores para estos objetos.
Básicamente, en la inicialización de su programa, un objeto reserva una porción de memoria en el montón (llamémoslo MemMan), luego, cuando desea crear un componente, le dice a MemMan que necesita un componente de tamaño X, ' Lo reservaremos para usted, creará un identificador y mantendremos internamente dónde en su asignación está el objeto para ese identificador. Devolverá el identificador, y eso es lo único que mantendrá sobre el objeto, nunca un puntero a su ubicación en la memoria.
Como necesita el componente, le pedirá a MemMan que acceda a este objeto, lo que con gusto lo hará. Pero no guardes la referencia porque ...
Uno de los trabajos de MemMan es mantener los objetos cerca uno del otro en la memoria. Una vez cada pocos fotogramas del juego, puede decirle a MemMan que reorganice los objetos en la memoria (o podría hacerlo automáticamente cuando cree / elimine objetos). Actualizará su mapa de ubicación de manejador a memoria. Sus identificadores siempre serán válidos, pero si mantuvo una referencia al espacio de memoria (un puntero o una referencia ), encontrará solo desesperación y desolación.
Los libros de texto dicen que esta forma de administrar su memoria tiene al menos 2 ventajas:
Tenga en cuenta que la forma en que usa MemMan y cómo organizará la memoria internamente depende realmente de cómo usará sus componentes. Si itera a través de ellos según su tipo, querrá mantener los componentes por tipo, si itera a través de ellos en función de su objeto de juego, deberá encontrar una manera de asegurarse de que estén cerca de uno otro basado en eso, etc.
fuente