Introdução
Os sistemas de componentes de entidade são uma técnica de arquitetura orientada a objetos.
Não há consenso universal sobre o que o termo significa, o mesmo que programação orientada a objetos. No entanto, é claro que os sistemas de entidade-componente são especificamente planejados como uma alternativa arquitetural à herança . Hierarquias de herança são naturais para expressar o que um objeto é , mas em certos tipos de software (como jogos), você prefere expressar o que um objeto faz .
É um modelo de objeto diferente daquele das “classes e herança” ao qual você provavelmente está acostumado a trabalhar em C ++ ou Java. As entidades são tão expressivas quanto as classes, assim como os protótipos, como no JavaScript ou no Self - todos esses sistemas podem ser implementados em termos um do outro.
Exemplos
Vamos dizer que Player
é uma entidade com Position
, Velocity
e KeyboardControlled
componentes, que fazem as coisas óbvias.
entity Player:
Position
Velocity
KeyboardControlled
Sabemos que Position
deve ser afetado por Velocity
e Velocity
por KeyboardControlled
. A questão é como gostaríamos de modelar esses efeitos.
Entidades, componentes e sistemas
Suponha que os componentes não tenham referências um ao outro; um Physics
sistema externo percorre todos os Velocity
componentes e atualiza o Position
da entidade correspondente; um Input
sistema percorre todos os KeyboardControlled
componentes e atualiza o Velocity
.
Player
+--------------------+
| Position | \
| | Physics
/ | Velocity | /
Input | |
\ | KeyboardControlled |
+--------------------+
Isso satisfaz os critérios:
Os sistemas agora são responsáveis por manipular eventos e aprovar o comportamento descrito pelos componentes. Eles também são responsáveis por lidar com interações entre entidades, como colisões.
Entidades e componentes
No entanto, suponha que os componentes fazem ter referências a um outro. Agora, a entidade é simplesmente um construtor que cria alguns componentes, os une e gerencia sua vida útil:
class Player:
construct():
this.p = Position()
this.v = Velocity(this.p)
this.c = KeyboardControlled(this.v)
A entidade agora pode enviar eventos de entrada e atualização diretamente para seus componentes. Velocity
responderia às atualizações e KeyboardControlled
responderia à entrada. Isso ainda satisfaz nossos critérios:
Aqui, as interações de componentes são explícitas, não impostas de fora por um sistema. Os dados que descrevem um comportamento (qual é a quantidade de velocidade?) E o código que o representa (o que é velocidade?) São acoplados, mas de maneira natural. Os dados podem ser vistos como parâmetros para o comportamento. E alguns componentes não agem de maneira alguma - a Position
é o comportamento de estar em um lugar .
As interações podem ser tratadas no nível da entidade ("quando uma Player
colide com um Enemy
...") ou no nível de componentes individuais ("quando uma entidade com Life
colide com uma entidade com Strength
...").
Componentes
Qual o motivo da existência da entidade? Se for apenas um construtor, podemos substituí-lo por uma função que retorna um conjunto de componentes. Se depois desejarmos consultar entidades por tipo, também podemos ter um Tag
componente que nos permita fazer exatamente isso:
function Player():
t = Tag("Player")
p = Position()
v = Velocity(p)
c = KeyboardControlled(v)
return {t, p, v, c}
Agora, as interações devem ser tratadas por consultas abstratas, dissociando completamente os eventos dos tipos de entidade. Não há mais tipos de entidades a serem consultados - os Tag
dados arbitrários provavelmente são mais usados para depuração do que a lógica do jogo.
Conclusão
Entidades não são funções, regras, atores ou combinadores de fluxo de dados. São substantivos que modelam fenômenos concretos - em outras palavras, são objetos. É como a Wikipedia diz - sistemas de componentes de entidades são um padrão de arquitetura de software para modelar objetos gerais.