domingo, 30 de maio de 2010

Detalhes de implementação

Após escolher a estrutura do jogo faltava definir como seria a implementação dos componentes e da classe GameObject. O decidido foi fazer uma classe Component e todas os componentes herdam essa classe. Além disso a Component tem um ponteiro de map de GameObjects.
Eu prefiri definir a classe GameObject apenas com os componentes e com um identificador.

class GameObject {
public:
typedef int ObjID;
GameObject();
virtual ~GameObject();
Collection components;
};

class Component {
//ID do objeto que contem o componente
GameObject::ObjID owner;
public:
//Contem todos os objetos do jogo
map *objs;
// Todo componente tem um tipo
virtual int getType(){
return -1;
}
GameObject::ObjID getOwner() const
{
return owner;
}
}

Qualquer atributo como nome do objeto ou outra funcionalidade será adicionada a classe na forma de um componente. Os componentes podem ser criados pelo objeto ou fora do objeto.
Dentro do objeto tem o problema de deixar o objeto mais difícil de reconfigurar e uma vez que uma das vantagens de usar componentes é deixar o objeto mais flexível, isso é um problema a ser considerado.
Fora do objeto o código externo passará o componente criado para o objeto e isso manterá a flexibilidade, já que o objeto poderá ser alterado completamente apenas alterando seus componentes. Outra vantagem é a de que, como o GameObject recebe os componentes criados como classes derivadas de Component e por isso ele só conhece essa classe, o código está mantendo um fraco encapsulamento.

O problema agora é como seria a comunicação entre os componentes, uma vez que o componente Movement precisa do componente Position, por exemplo. Há três formas:
Acesso direto aos outros componentes
Na minha opinião é maís fácil de se pensar uma vez que não é preciso realizar a comunicação implicitamente utilizando métodos da classe componente. Porém tem a desvantagem de aumentar o acoplamento. A grande vantagem é que é simples e rápida.
Modificando atributos do GameObject
Diminui o acoplamento porque os componentes não sabem da existência um do outro. E requer informações compatilhadas e isso pode causar uma sobrecarga da classe GameObject com informações que nem todo objeto do jogo vai precisar. Além disso a comunicação seria implícita, o que aumenta a dificuldade de projetar o jogo.
Por mensagens
É o mais complexo mas tem fraco acoplamento e a classe GameObject é mais simples. O acoplamento seria deixado para o valor das mensagens e da interpretação da mesma e não requer informação compartilhada porque a troca de informação é feita apenas entre componentes.

Não há resposta certa e é aconselhado usar um pouco de cada. Em alguns componentes muito relacionados como Movement e Position não seria tanto problema o acoplamento devido ao acesso direto porque eles já são acoplados por um depender tanto do outro. Caso todos os objetos tem alguma informação comum ela pode ser compartilhada entre os componentes.
As mensagens normalmente são usadas para comunicação menos importante, como uma comunicação entre o componente de áudio e o componente físico.

Na Action RPG Lib eu optei por começar usando o acesso direto dos componentes porque eu ainda não vou descrever todo o sistema antes de começar programar e é mais fácil de pensar. Se no meio do projeto eu perceber que seria melhor outras abordagens eu tento implementa-las ou anoto para implementar na versão 2(espero).

Fonte: Game Programming Patterns - Component

Nenhum comentário:

Postar um comentário

Related Posts Plugin for WordPress, Blogger...