Qual é o nível de granularidade apropriado para a arquitetura baseada em componentes?

26

Estou trabalhando em um jogo com uma arquitetura baseada em componentes. Um Entitypossui um conjunto de Componentinstâncias, cada uma com um conjunto de Slotinstâncias com as quais armazenar, enviar e receber valores. Funções de fábrica, como Playerproduzir entidades com os componentes e conexões de slot necessários.

Estou tentando determinar o melhor nível de granularidade para componentes. Por exemplo, agora Position, Velocitye Accelerationsão todos os componentes separados, conectados em série. Velocitye Accelerationpode ser facilmente reescrito num uniforme Deltacomponente, ou Position, Velocity, e Accelerationpoderia ser combinada juntamente com tais componentes, como Frictione Gravityem um monolítico Physicscomponente.

Um componente deve ter a menor responsabilidade possível (ao custo de muita interconectividade) ou os componentes relacionados devem ser combinados em componentes monolíticos (ao custo da flexibilidade)? Estou inclinado para o primeiro, mas eu poderia usar uma segunda opinião.

Jon Purdy
fonte
Você vai usar seu próprio mecanismo de física ou integrar um já existente?
Den
@ Den: eu estou escrevendo algum código de física , mas não é um mecanismo de forma alguma. Apenas cinemática 2D mundana.
9119 Jon Purdy

Respostas:

14

Há uma linha entre a granularidade completa, levando a nenhum desperdício de código ou estado do tipo blob (e é por isso que as arquiteturas de componentes são favorecidas) e usabilidade.

Obviamente, as coisas podem ter um Position, mas não são necessariamente dinâmicas (então, por que têm Velocitye Acceleration?). No entanto, algo com Velocitya será um objeto em movimento, por isso faz sentido também ter Accelerationagrupado.

Você vai ter um caso em que v e um vai ser necessário, mas você não quer uma simulação de física para eles? Da mesma forma, haverá um ponto em Gravityque não sejam objetos de física?

tl; dr Agrupe o que faz sentido.

O Pato Comunista
fonte
11
Parece justo. Meu sistema tem muito pouca centralização: se um Entitytem Positione alguns componentes que o fazem Positionparticipar da física, então Entityé de fato físico. Acho que o que posso fazer é adicionar alguns componentes para o agrupamento lógico e manter todos os componentes fundamentais em uma única responsabilidade. Assim, adicionando, digamos, um Movablea um Entityteria o mesmo efeito que a adição de um Position, Velocitye Acceleration.
9119 Jon Purdy
6

Para evitar a microgerenciamento de todas as variáveis ​​que eu sugeriria, começando pesado, escolha divisões em torno da responsabilidade e refatorar quando a situação se apresentar logicamente. Você pode iniciar os primeiros desenhos no papel. Em algum momento, essas divisões brutas de responsabilidade se tornarão os blocos de construção de suas entidades.

Então, para um exemplo apressado, você tem o Game. O jogo é dividido em Ambiente + Estado. O ambiente é dividido em StaticWorld + MovingStuff. O estado é dividido em AIControlled + PlayerControlled. A idéia grosseira de Dano se divide em TakesDamage + GivesDamage.

E assim por diante.

Muito parecido com o conselho comum de "Construir jogos, não mecanismos!" para novos profissionais, recomendo "Construir jogos, não sistemas de componentes elaborados!" porque somente com experiência pessoal em um jogo em execução você saberá se é necessário um sistema elaborado de componentes em trabalhos futuros.

Patrick Hughes
fonte
Eu não sou um novo desenvolvedor. Se eu tiver componentes baseados em conceitos e não em comportamento (de cima para baixo versus de baixo para cima), minha arquitetura não será mais frágil e mais elaborada? Posso implementar qualquer comportamento que desejar de pequenos componentes, mas nem sempre consigo o comportamento desejado dos pré-combinados. Sem mencionar que não posso prever tudo o que quero alcançar, mesmo no contexto de um jogo.
91111 Jon Purdy
A desvantagem de baixo para cima é que a comunicação entre os componentes se torna um problema, e as pessoas tendem a começar muito micro na escala do que estão modelando. Eu estava principalmente tentando me afastar do super-micro "xyz é um componente" "rotação é um componente" "rgb é um componente" de nível para alguém inexperiente.
Patrick Hughes
Justo. Eu só queria ter certeza de que entendi você corretamente. Com o sistema de slots que tenho, é simples e eficiente que os componentes se comuniquem, então não vejo nenhuma desvantagem na escala "super-micro". Não pretendo refatorar isso para um mecanismo independente, mas, se o fizer, sempre posso introduzir abstrações, como os grupos de componentes mencionados no meu comentário sobre a resposta do Pato Comunista.
91111 Jon Purdy
4

Meu palpite seria combinar componentes que tenham muita interação. No seu caso, eu manteria a posição em um único componente e manteria a velocidade e a aceleração juntas em um componente da física.

Mas isso depende muito de quais são os recursos do seu jogo (a menos que você esteja construindo uma estrutura sem nenhum jogo específico em mente).

XGouchet
fonte
2
O problema de combinar componentes com muita interação é que às vezes a outra parte não é necessária.
The Duck Comunista
4

Sei que essa é uma pergunta antiga, mas talvez alguém ache essa resposta útil.

eu acredito Systems isso ajudará você a entender melhor como construir componentes. Os sistemas existem em arquiteturas em que os componentes não contêm sua própria lógica, além de simples getter / setters e funções auxiliares. Os sistemas operam em entidades que atendem aos requisitos do componente. É por isso que é melhor separar os dados do componente, tanto quanto faz sentido que esses dados sejam processados ​​sem os outros dados.

Por exemplo, você pode ter um MovementSystemque atualize suas Entidades com Positionbase nas deles Velocity. Isso pode ser para entidades simples no jogo. Mas, para o Jogador e Inimigos, você pode querer um movimento que possui o Accelerationqual é processado AcceleratedMovementSystem. Mas para Obstáculos você pode querer Friction. O Terreno também pode ter atrito, mas não terá um componente de velocidade. Mas que tal Gravity? Apenas adicione Player, Inemy e Obstacle e crie um GravitySystempara processá-lo.

A linha inferior é que quanto mais dissociado seu Componentsfor, mais extensível o Entitiesserá quando usando Systems.

Edit: Tornou a última declaração mais clara.

Edit: Ok, eu tenho trabalhado no meu próprio sistema e chegou a essa conclusão. Um exemplo para dividir Position e Velocity é que manipular Velocity faz com que a Position mude com um MovementSystem. Como resultado, um 'InputMovementSystem' não precisa de uma posição para fazer com que o Player se mova da entrada do usuário porque o MovementSystem capta as alterações no Velocity para aplicar à posição. Concedido, ainda funcionaria bem para reuni-los, mas esse é um exemplo de por que não precisa ser.


Li recentemente um post no blog que dizia algo assim:

"Se você possui dados que podem ser agrupados com 2 componentes diferentes, é melhor criar um terceiro componente com esses dados."

Dan H.
fonte