Criando Entidade como uma Agregação

10

Recentemente, perguntei sobre como separar as entidades de seu comportamento e a principal resposta vinculada a este artigo: http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/

O conceito final escrito aqui é o de: OBJETO COMO UMA AGREGAÇÃO PURA.

Eu estou pensando como eu poderia criar entidades de jogos como agregação pura usando C #. Ainda não compreendi o conceito de como isso pode funcionar. (Talvez a entidade seja uma matriz de objetos implementando uma certa interface ou tipo de base?)

Meu pensamento atual ainda envolve ter uma classe concreta para cada tipo de entidade que implementa as interfaces relevantes (IMoveable, ICollectable, ISpeakable etc.).

Como posso criar uma entidade puramente como uma agregação sem ter nenhum tipo concreto para essa entidade?

Jamie Dixon
fonte
Se você ainda estiver interessado, posso enviar meu pequeno sistema de entidades em C #. Não é incrível , mas funciona.
The Duck comunista

Respostas:

6

A abordagem de "agregação pura" descrita por West nesse artigo vinculado evita completamente um objeto "entidade". Existem componentes flutuando na memória, mas eles são unidos apenas por relacionamentos implícitos, se é que existem.

Uma maneira de fazer isso é a chamada abordagem externa . Nesse sistema, os componentes são mantidos por sistemas que os gerenciam ou, de outra forma, os controlam (eu uso o termo "gerenciar" aqui, mas você não deve considerar que isso significa que estou sugerindo que você tenha várias classes * Manager para realizar tipos de componentes). Por exemplo, seu sistema de física pode se apegar a várias coisas que representam cada corpo rígido em seu mundo de simulação e pode expor essas coisas como Componentes Físicos. Os componentes podem ser os objetos reais manipulados pelo subsistema em questão ou podem ser proxies para esses objetos, conforme necessário.

Nesse sistema, não há necessariamente a necessidade de uma classe "Entity" manter uma coleção de referências aos componentes que a compõem; em vez disso, é emitida uma notificação sobre a criação ou destruição de uma "entidade" e cada subsistema que manipula componentes analisa a descrição da entidade criada / destruída (que normalmente é carregada de alguns dados) e determina se um componente é necessário para ela.

Uma das vantagens dessa abordagem é que você obtém uma boa localidade de referência para cada componente. Infelizmente, é um pouco estranho, no geral, e não é o sabor mais amigável das entidades baseadas em componentes que encontrei. Às vezes, é realmente conveniente ter um objeto real que represente uma entidade, mesmo que esse objeto faça pouco mais do que agregar referências fracas a componentes que ainda são mantidos por outros subsistemas (se nada mais, ele fornece uma maneira fácil de rotear mensagens entre componentes) .

Existem várias maneiras de implementar sistemas de objetos de jogo orientados a componentes; -lo realmente, realmente, realmente ajuda se você tem uma idéia sólida dos requisitos que você quer fora de seu sistema - você pode olhar para o que os quadros populares como Unidade fazer por exemplos. Sem definir requisitos rigorosos para você, você pode se deparar com o problema de "projetar" infinitamente o sistema sem realmente construí-lo, tentando em vão encontrar a implementação perfeita. Por alguma razão, eu já vi isso muito com sistemas de componentes.


fonte
3

A maneira como o Unity faz é que todos os scripts (no seu caso, código de jogo específico para um tipo de objeto de jogo) derivem de uma classe base MonoBehaviour, que por sua vez deriva da classe mais relevante para o seu caso Component. Você nunca edita (e não tem acesso ao código) a classe GameObject.

O objeto do jogo é responsável por conter todos esses Components. Também é ostensivamente encarregado de chamar as funções relevantes sobre eles (ie Update). O Unity usa a reflexão para determinar para quais funções chamar (consulte a seção "Funções substituíveis" nesta página ), mas você provavelmente desejaria torná-las virtuais.

Portanto, um dos mecanismos que você usa no Unity é obter componentes no seu objeto de jogo atual (ou em seus filhos) por tipo. Existem algumas propriedades auxiliares que envolvem algumas das coisas comuns. Por exemplo, se você deseja acessar o Transformcomponente do objeto do jogo (para controlar a posição / rotação / escala do objeto do jogo), normalmente seria necessário fazer algo parecido this.GetComponent<Transform>().position, mas eles o envolvem em uma this.transform.positionchamada auxiliar . Outro padrão comum é acessar o Renderercomponente atual do objeto do jogo . Portanto, se você quiser fazer algo como alterar o material atual do objeto do jogo, de outro script, faça algo como this.renderer.material = someOtherMaterial, e o objeto do jogo será atualizado adequadamente.

Uma das maneiras pelas quais isso funciona no Unity é que o editor deles é configurado para que você possa criar objetos de jogo em sua cena que possuam componentes já conectados. No caso do Unity, todos os objetos do jogo têm um Transformcomponente, mas também podem conter tipos internos como AudioListenerou Renderer, que fazem o que você esperaria. Ou você pode adicionar seus próprios componentes que fazem o que você deseja que eles façam. O editor também expõe campos públicos / serializáveis ​​em seus componentes para que você não precise criar scripts diferentes se quiser usar o mesmo código básico, mas alterar alguns números mágicos.

Em suma, é muito esperto, e eu sugiro baixar a versão gratuita do Unity e brincar com a forma como o sistema de script deles é configurado como uma prova bastante decente do conceito do que você deseja alcançar.

Tetrad
fonte