Passei as últimas 48 horas lendo sistemas de componentes de objetos e sinto que estou pronto o suficiente para começar a implementá-lo. Criei as classes Object e Component de base, mas agora que preciso começar a criar os componentes reais, estou um pouco confuso. Quando penso neles em termos de HealthComponent ou algo que basicamente seria apenas uma propriedade, faz todo o sentido. Quando é algo mais geral como componente de Física / Gráficos, fico um pouco confuso.
Minha classe Object se parece com isso até agora (se você perceber alguma alteração que eu deva fazer, por favor me avise, ainda é novo nisso) ...
typedef unsigned int ID;
class GameObject
{
public:
GameObject(ID id, Ogre::String name = "");
~GameObject();
ID &getID();
Ogre::String &getName();
virtual void update() = 0;
// Component Functions
void addComponent(Component *component);
void removeComponent(Ogre::String familyName);
template<typename T>
T* getComponent(Ogre::String familyName)
{
return dynamic_cast<T*>(m_components[familyName]);
}
protected:
// Properties
ID m_ID;
Ogre::String m_Name;
float m_flVelocity;
Ogre::Vector3 m_vecPosition;
// Components
std::map<std::string,Component*> m_components;
std::map<std::string,Component*>::iterator m_componentItr;
};
Agora, o problema que estou enfrentando é o que a população em geral colocaria em componentes como Física / Gráficos? Para o Ogre (meu mecanismo de renderização), os Objetos visíveis consistirão em vários Ogre :: SceneNode (possivelmente múltiplos) para anexá-lo à cena, Ogre :: Entity (possivelmente múltiplos) para mostrar as malhas visíveis, e assim por diante. Seria melhor adicionar vários GraphicComponent ao objeto e permitir que cada GraphicComponent lidasse com um SceneNode / Entity ou é a idéia de ter um de cada componente necessário?
Para a física, estou ainda mais confuso. Suponho que talvez esteja criando um RigidBody e mantendo o controle de massa / interia / etc. faria sentido. Mas estou tendo problemas para pensar em como realmente colocar detalhes em um componente.
Depois de concluir alguns desses componentes "Necessários", acho que fará muito mais sentido. A partir de agora, ainda estou um pouco perplexo.
fonte
A arquitetura do componente é uma alternativa para evitar as grandes hierarquias que são obtidas herdando todos os elementos de um mesmo nó e os problemas de acoplamento que levam.
Você está mostrando uma arquitetura de componentes com componentes "genéricos". Você tem a lógica básica para anexar e desanexar componentes "genéricos". Uma arquitetura com componentes genéricos é mais difícil de obter porque você não sabe qual é o componente. Os benefícios é que essa abordagem é extensível.
Uma arquitetura de componente válida é alcançada com componentes definidos. Com definido, quero dizer, a interface é definida, não a implementação. Por exemplo, GameObject pode ter um IPhysicInstance, Transformation, IMesh, IAnimationController. Isso tem o benefício de que você conhece a interface e o GameObject sabe como lidar com cada componente.
Respondendo ao termo generalização excessiva
Eu acho que os conceitos não são claros. Quando digo componente, não significa que todo componente de um objeto de jogo deva herdar de uma interface de componente ou algo semelhante. No entanto, essa é a abordagem para componentes genéricos, acho que é o conceito que você nomeia como componente.
A arquitetura do componente é outra das arquiteturas existentes para o modelo de objeto de tempo de execução. Não é o único e não é o melhor para todos os casos, mas a experiência demonstrou que possui muitos benefícios, como baixo acoplamento.
O principal recurso que distingue a arquitetura do componente é converter a relação is-a em has-a. Por exemplo, uma arquitetura de objeto é-a:
Em vez de uma arquitetura de objeto has-a (componentes):
Também há arquiteturas centradas em propriedades:
Por exemplo, uma arquitetura de objeto normal é assim:
Objeto1
Objeto2
Uma arquitetura centrada em propriedades:
Posição
Orientação
É melhor a arquitetura do modelo de objeto? Na perspectiva do desempenho, é melhor centrar-se na propriedade porque é mais amigável ao cache.
O componente é referido à relação é-a em vez de tem-a. Um componente pode ser uma matriz de transformação, um quaternion etc. Mas a relação com o objeto do jogo é uma relação é-a, o objeto do jogo não tem a transformação porque é herdado. O objeto do jogo tem (a relação tem-a) a transformação. A transformação é então um componente.
O objeto do jogo é como um hub. se você deseja um componente que sempre está lá, talvez o componente (como a matriz) deva estar dentro do objeto e não um ponteiro.
Não existe um objeto de jogo perfeito para todos os casos, depende do mecanismo, das bibliotecas que o mecanismo usa. Talvez eu queira uma câmera que não tenha uma malha. O problema da arquitetura is-a é que, se o objeto do jogo possui uma malha, a câmera que herda do objeto do jogo deve ter uma malha. Com os componenets, a câmera tem uma transformação, um controlador para o movimento e tudo o que você precisa.
Para obter mais informações, o capítulo "14.2. Arquitetura de modelo de objeto de tempo de execução" do livro "Game Engine Architecture" de "Jason Gregory" trata especificamente desse assunto.
Os diagramas UML são extraídos de lá
fonte