Como evitar "Blob-Systems" em um sistema de componentes de entidade?

10

Atualmente, estou enfrentando o seguinte problema:

Estou tentando escrever um clone de pong usando um sistema de componentes de entidade (ECS). Eu escrevi a "estrutura" sozinha. Portanto, há uma classe que gerencia as entidades com todos os componentes. Depois, existem as próprias classes de componentes. E por último, existem os meus sistemas que apenas obtêm todas as entidades que possuem componentes de que o sistema precisa.

Por exemplo, meu sistema de movimento procura todas as entidades que possuem um componente de posição e um componente de movimento. O componente de posição mantém apenas a posição e o componente de movimento mantém a velocidade.

Mas o problema real é o meu sistema de colisão. Essa classe é como um blob lógico. Eu tenho muitos casos especiais nesta classe.

Por exemplo: Meus remos podem colidir com as bordas. Se isso acontecer, a velocidade é ajustada para zero. Minha bola também pode colidir com as fronteiras. Mas, neste caso, sua velocidade é espelhada no normal da borda e, portanto, é refletida. Para fazer isso, dei à bola um componente extra de física que diz: "Ei, isso não para, reflete". Então, na verdade, o componente físico não possui dados reais. É uma classe vazia que existe apenas para informar ao sistema se um objeto reflete ou para.

Aí vem o seguinte: quero renderizar algumas partículas quando a bola colidir com os remos ou as bordas. Então eu acho que a bola precisa pegar outro componente que diga ao sistema de colisão para criar partículas em colisão.
Então eu quero ter power-ups que podem colidir com os remos, mas não com as fronteiras. Se isso acontecer, os power-ups terão que desaparecer. Então, eu precisaria de muito mais casos e componentes (para dizer ao sistema que algumas entidades só podem colidir com outras, mas não todas, mesmo que outras possam realmente colidir, além disso, o sistema de colisão teve que aplicar os power-ups para as pás, etc., etc., etc.).

Vejo que o sistema de componentes da entidade é uma coisa boa porque é flexível e você não tem problemas com herança. Mas estou totalmente preso atualmente.

Estou pensando muito complicado? Como devo lidar com esse problema?

Claro, eu tenho que criar sistemas que são realmente responsáveis ​​pela "pós-colisão", para que o sistema de colisão diga apenas "Sim, temos uma colisão no último quadro" e, em seguida, há um monte de sistemas "pós-colisão" que todos exigem componentes diferentes (combinações de) e depois os alteram. Por exemplo, haveria um sistema de movimento pós-colisão que interrompe coisas que precisam parar quando a colisão acontece. Em seguida, um sistema de pós-colisão físico que reflete coisas, etc.

Mas isso também não parece ser uma solução adequada para mim, porque, por exemplo:

  1. Meu sistema pós-colisão de movimento precisaria de entidades que tenham um componente de posição, um componente de movimento e um componente de colisão. Em seguida, definiria a velocidade da entidade como zero.
  2. O sistema de pós-colisão da física precisaria de entidades que tenham um componente de posição, um componente de movimento, um componente de colisão e um componente de física. Em seguida, refletiria o vetor de velocidade.

O problema é óbvio: o movimento pós-colisão precisa de entidades que são um subconjunto das entidades no sistema de pós-colisão da física. Portanto, dois sistemas pós-colisão operariam com os mesmos dados, o efeito sendo: Embora uma entidade tenha um componente de física, sua velocidade seria zero após uma colisão.

Como esses problemas são resolvidos em geral em um sistema de componentes da entidade? Esses problemas são comuns ou estou fazendo algo errado? Se sim, o que e como deve ser feito?

M0rgenstern
fonte

Respostas:

11

Sim, você está pensando muito complicado.

Parece que muitos dos seus problemas poderiam ser resolvidos com um sistema de mensagens e alguns atributos adicionais que permitem especificar alguns filtros e, finalmente, não se preocupar em ser tão rigoroso com entidades / componentes.

O sistema de mensagens ajudará você em alguns aspectos, como acionar partículas, upgrades etc. Por exemplo, você pode ter um objeto mundial que assine eventos de partículas e crie partículas na posição descrita no evento.

Os filtros o ajudarão muito em colisões. Os filtros podem definir se um objeto colide com outro e qual resposta ele terá. Você adiciona alguns atributos ao seu componente físico que define com que tipo de corpo físico ele é, quais outros tipos de corpos físicos ele colide e qual deve ser a resposta. Por exemplo, um objeto de física da bola colide com um objeto de física da raquete e responde com reflexão e partículas.

Por fim, não seja tão rigoroso com sua implementação. Se você puder encontrar uma maneira de fazê-lo funcionar, mas não for realmente um sistema CE, faça-o. Como no meu exemplo acima, as partículas não precisam ser gerenciadas por um sistema ou parte do sistema CE. É mais importante terminar o jogo do que seguir estritamente um método que já está bem definido.

MichaelHouse
fonte
Muito obrigado. Eu queria criar um jogo usando um ECS apenas para ver como ele é dimensionado e se é realmente tão bom de usar como eu li em artigos e tutoriais. Meu problema era que eu pensava: "Eu tenho um ECS agora e tudo tem que ser gerenciado por isso". Então planejei também escrever o sistema de partículas em conexão com o ECS. Além disso, li em alguns artigos que cada componente deve realmente ter apenas alguns dados básicos e nada mais. Esse costuma ser o meu problema ... acho muito complicado.
precisa saber é o seguinte
Eu queria criar um jogo usando um ECS apenas para ver como ele é dimensionado e se é realmente tão bom de usar como eu li em artigos e tutoriais . Se esse é seu objetivo, recomendo que você analise os sistemas de componentes / entidades existentes em vez de criar seus próprios. Baixe o Unity3D, que é provavelmente "o mais puro possível" e brinque por aí. Insights muito mais rápidos, IMHO.
Imi
3
@lmi: O Unity não é um sistema de componentes de entidades, embora seja baseado em componentes. O ECS tem algumas diretrizes mais rígidas ( nunca pense em um padrão como regras) do que simplesmente ter e usar componentes de objetos do jogo. Devido a uma série de artigos, o ECS é popular atualmente em alguns segmentos de desenvolvedores de jogos, então há muitas perguntas sobre o ECS especificamente, em vez do design baseado em componentes em geral.
Sean Middleditch
12

Você está complicando demais as coisas. Eu diria que mesmo usar o design baseado em componentes é apenas um exagero para um jogo tão simples. Faça as coisas da maneira que torna seu jogo rápido e fácil de desenvolver. Os componentes ajudam na iteração em projetos maiores, com uma enorme variedade de comportamentos e configurações de objetos do jogo, mas seus benefícios para um jogo tão simples e bem definido são mais questionáveis. Fiz uma palestra no ano passado sobre isso: você pode criar joguinhos divertidos em poucas horas se se concentrar em fazer um jogo em vez de aderir a uma arquitetura . A herança é interrompida quando você tem 100 ou até 20 tipos diferentes de objetos, mas funciona muito bem se você tiver apenas um punhado.

Supondo que você queira continuar usando componentes para fins de aprendizado, há alguns problemas óbvios em sua abordagem que se destacam.

Primeiro, não faça seus componentes tão pequenos. Não há razão para ter componentes refinados como 'movimento'. Não há movimento genérico no seu jogo. Você tem remos, cujo movimento está intimamente ligado à entrada ou à IA (e realmente não usa velocidade, aceleração, restituição etc.), e você tem a bola, que possui um algoritmo de movimento bem definido. Basta ter um componente PaddleController e um componente BouncingBall ou algo nesse sentido. Se / quando você tiver um jogo mais complicado, poderá se preocupar em ter um componente PhysicsBody mais genérico (que em mecanismos 'reais' é basicamente apenas um link entre o objeto do jogo e qualquer objeto interno da API usado pelo Havok / PhysX / Bullet / Box2D / etc.) Que lida com uma variedade maior de situações.

Mesmo um componente de 'posição' é questionável, mas certamente não incomum. Os mecanismos de física geralmente têm sua própria idéia interna de onde está um objeto, os gráficos podem ter uma representação interpolada e a IA pode ter ainda outra representação dos mesmos dados em um estado diferente. Pode ser vantajoso permitir que cada sistema gerencie sua própria idéia da transformação nos próprios componentes do sistema e depois garantir uma comunicação suave entre o sistema. Veja a publicação do blog BitSquid nos fluxos de eventos .

Para mecanismos físicos personalizados, lembre-se de que você pode ter dados sobre seus componentes. Talvez um componente genérico de física de Pong possua dados indicando em quais eixos ele pode se mover (por exemplo, vec2(0,1)como um multiplicador para pás que só podem se mover no eixo Y e vec2(1,1)para a bola indicando que ele pode se mover no entanto), uma bandeira ou um flutuador indicando a flutuação (a bola seria tipicamente em 1.0e remos em0.0), características de aceleração, velocidade e assim por diante. Tentar dividir isso em um zilhão de microcomponentes diferentes para cada pedaço de dados altamente relacionados é contrário ao que o ECS deveria originalmente fazer. Mantenha as coisas que são usadas juntas no mesmo componente sempre que possível e divida-as apenas quando houver uma grande diferença em como cada objeto do jogo usa esses dados. Há um argumento para argumentar que, para Pong, a física entre a bola e os remos é diferente o suficiente para ser componentes separados, mas para um jogo maior, há poucas razões para tentar fazer 20 componentes para fazer o que funciona bem em 1-3.

Lembre-se, se / quando sua versão do ECS atrapalhar, faça o que você realmente precisa para fazer seu jogo e esqueça a aderência a um padrão / arquitetura de design.

Sean Middleditch
fonte
1
Realmente obrigado! Eu sei que um ECS não escala muito bem para um pequeno jogo como o pong. Mas usei apenas para ver como uma coisa dessas é realmente implementada e como funciona. Fiz os componentes tão pequenos, porque era o que eu lia principalmente em alguns artigos. Ter muitos componentes e cada componente contém apenas dados elementares. Então, eu entendo você corretamente, que você sugere usar uma mistura entre herança e ECS? Como você diz "a bola e os remos são diferentes o suficiente para serem componentes separados". Assim, por exemplo, eu dar-lhes tanto um componente Movimento / Posição (talvez como um componente) e
M0rgenstern
1
O que quer que funcione. Concentre-se em fazer o jogo. Eu literalmente teria apenas um componente chamado Ballque contém toda a lógica da bola, como movimento, salto, etc. e um Paddlecomponente que recebe informações, mas esse sou eu. Tudo o que faz mais sentido para você, sai do seu caminho e permite que você faça o jogo é a "maneira correta" de fazer as coisas.
Sean Middleditch
3
Eu literalmente teria apenas um componente chamado Ball que contém toda a lógica da bola, como movimento, salto, etc., e um componente Paddle que recebe entrada, mas esse sou eu. E é por isso que existe uma opinião para cada programador sobre "sobre o que é um sistema de componentes". Eu recomendo NÃO fazer isso dessa sugestão, exceto que você está totalmente pensando nos sistemas clássicos de entidades e é forçado a usar um sistema de componentes, mas não quer ver quais são realmente as diferenças.
Imi
2
@lmi: trabalhar em alguns grandes jogos / mecanismos com componentes e ver em primeira mão por que usamos componentes, não, componentes excessivamente granulares são apenas mais problemas do que valem. Componentes não são uma bala mágica; elas são uma das muitas ferramentas na caixa de ferramentas de um desenvolvedor de jogos. Use-os de uma maneira e local que eles ajudem, e não de maneiras que apenas adicionem mais sobrecarga mental e de tempo de execução ao sistema. Se a única coisa que tem bola-física é a bola, não é de zero vantagem para separá-lo de outras propriedades de esferas. Se e quando isso mudar, divida-o apenas nesse momento.
Sean Middleditch
1
Eu concordo com o princípio de ser pragmático e não deixar que um padrão particular atrapalhe seu caminho. MAS, se o ECS não puder lidar com esse jogo trivial sem desvio, que esperança existe para um jogo grande? Também estou tentando aprender a usar o ECS de maneira eficaz, mas estou tentando ficar o mais próximo possível da filosofia do ECS; caso contrário, assim que começar a criar exceções e casos especiais, sei que acabarei com uma bagunça insustentável.
Ken
-2

Na minha opinião *), seu maior problema com os componentes é este: os componentes NÃO estão aqui para dizer a outras pessoas o que fazer. Os componentes estão aqui para fazer as coisas. Você não tem um componente apenas para armazenar a memória de alguma coisa e, em seguida, tem outros componentes operando nisso. Você deseja componentes que fazem coisas com os dados que eles obtiveram.

Se você se vê testando a presença de outros componentes (e depois chama funções aqui), esse é um sinal claro de que uma das duas coisas é verdadeira:

  • Você realmente deseja inverter a dependência: O outro componente deve ouvir eventos / mensagens / transmissões / ganchos / no entanto, para executá-los em resposta ao seu componente atual. O componente atual nem precisa saber que existe um "outro" componente. Geralmente, esse é o caso, se você estiver chamando componentes diferentes (mesmo em outros blocos de maiúsculas / minúsculas) com funcionalidade que não está realmente conectada ao seu método atual. Pense em tudo isso Invalidate()ou SetDirty()ligue para outros componentes.
  • Você pode ter muitos componentes. Se dois componentes simplesmente não conseguem viver um sem o outro e precisam constantemente recuperar dados e chamar métodos um para o outro, basta mesclá-los. Obviamente, a funcionalidade que eles fornecem é tão emaranhada, que na verdade é apenas uma coisa.

A propósito, isso se aplica a todos os tipos de sistemas, não apenas aos sistemas de entidade / componente, mas também à herança clássica com simples "GameObject" ou até mesmo funções de biblioteca.

*) Realmente só meu . As opiniões variam bastante sobre o Whats Da Real Component Systemz (TM)

Imi
fonte