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:
- 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.
- 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?
fonte
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 evec2(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 em1.0
e 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.
fonte
Ball
que contém toda a lógica da bola, como movimento, salto, etc. e umPaddle
componente 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.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:
Invalidate()
ouSetDirty()
ligue para outros componentes.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)
fonte