Estou criando um jogo que usa objetos de jogo baseados em componentes e estou tendo dificuldades para implementar uma maneira de cada componente se comunicar com seu objeto de jogo. Em vez de explicar tudo de uma vez, explicarei cada parte do código de exemplo 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;
}
Ele GameObjectManager
contém todos os objetos do jogo e seus componentes. Também é responsável por atualizar os objetos do jogo. Isso é feito atualizando os vetores de componentes em uma ordem específica. Eu uso vetores em vez de matrizes para que praticamente não haja limite para o número de objetos do jogo que podem existir ao mesmo tempo.
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;
}
A GameObject
classe sabe quais são seus componentes e pode enviar mensagens para eles.
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);
}
o Component
classe é virtual pura, para que as classes dos diferentes tipos de componentes possam implementar como lidar com mensagens e atualizar. Também é capaz de enviar mensagens.
Agora, surge o problema de como os componentes podem chamar as sendMessage
funções em GameObject
e GameObjectManager
. Eu vim com duas soluções possíveis:
- Dê
Component
um ponteiro para o seuGameObject
.
No entanto, como os objetos do jogo estão em um vetor, os ponteiros podem rapidamente ser invalidados (o mesmo pode ser dito do vetor em GameObject
, mas espero que a solução para esse problema também possa resolver esse). Eu poderia colocar os objetos do jogo em uma matriz, mas teria que passar um número arbitrário para o tamanho, que poderia facilmente ser desnecessariamente alto e desperdiçar memória.
- Dê
Component
um ponteiro para oGameObjectManager
.
No entanto, não quero que os componentes possam chamar a função de atualização do gerente. Sou a única pessoa trabalhando nesse projeto, mas não quero adquirir o hábito de escrever códigos potencialmente perigosos.
Como posso resolver esse problema, mantendo meu código seguro e amigável ao cache?