O objeto da arquitetura do Entity Component System é orientado por definição?

20

O objeto da arquitetura do Entity Component System é orientado, por definição? Parece mais processual ou funcional para mim. Minha opinião é que isso não o impede de implementá-lo em uma linguagem OO, mas não seria idiomático fazê-lo de uma maneira OO firme.

Parece que o ECS separa dados (E & C) do comportamento (S). Como evidência :

A ideia é não ter métodos de jogo embutidos na entidade.

E :

O componente consiste em um conjunto mínimo de dados necessários para uma finalidade específica

Sistemas são funções de propósito único que utilizam um conjunto de entidades que possuem um componente específico


Eu acho que isso não é orientado a objetos, porque grande parte de ser orientado a objetos está combinando seus dados e comportamento. Como evidência :

Por outro lado, a abordagem orientada a objetos incentiva o programador a colocar dados onde eles não são diretamente acessíveis pelo restante do programa. Em vez disso, os dados são acessados ​​chamando funções especialmente escritas, geralmente chamadas de métodos, que são incorporadas aos dados.

O ECS, por outro lado, parece ter tudo a ver com separar seus dados do seu comportamento.

Daniel Kaplan
fonte

Respostas:

21

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, Velocitye KeyboardControlledcomponentes, que fazem as coisas óbvias.

entity Player:
  Position
  Velocity
  KeyboardControlled

Sabemos que Positiondeve ser afetado por Velocitye Velocitypor 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 Physicssistema externo percorre todos os Velocitycomponentes e atualiza o Positionda entidade correspondente; um Inputsistema percorre todos os KeyboardControlledcomponentes e atualiza o Velocity.

          Player
         +--------------------+
         | Position           | \
         |                    |  Physics
       / | Velocity           | /
  Input  |                    |
       \ | KeyboardControlled |
         +--------------------+

Isso satisfaz os critérios:

  • Nenhuma lógica de jogo / negócios é expressa pela entidade.

  • Os componentes armazenam dados que descrevem o comportamento.

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. Velocityresponderia às atualizações e KeyboardControlledresponderia à entrada. Isso ainda satisfaz nossos critérios:

  • A entidade é um contêiner "burro" que apenas encaminha eventos para componentes.

  • Cada componente representa seu próprio comportamento.

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 Playercolide com um Enemy...") ou no nível de componentes individuais ("quando uma entidade com Lifecolide 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 Tagcomponente que nos permita fazer exatamente isso:

function Player():
  t = Tag("Player")
  p = Position()
  v = Velocity(p)
  c = KeyboardControlled(v)
  return {t, p, v, c}
  • As entidades são tão burras quanto podem ser - são apenas conjuntos de componentes.

  • Os componentes respondem diretamente aos eventos como antes.

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 Tagdados 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.

Jon Purdy
fonte
2
A principal alternativa ao OO baseado em classe, OO baseado em protótipo, também parece acoplar dados e comportamento. Na verdade, parece diferir do ECS tanto quanto o OO baseado em classe. Então você poderia elaborar o que você quer dizer com OO?
Para adicionar à pergunta de @ delnan, você está discordando do trecho do artigo da OO na wikipedia que citei?
Daniel Kaplan
@tieTYT: A citação da Wikipedia está falando sobre encapsulamento e ocultação de informações. Eu não acho que seja evidência de que o acoplamento dados-comportamento seja necessário, apenas que seja comum.
Jon Purdy
@ delnan: Eu não quero dizer nada por OO. A programação orientada a objetos, para mim, é exatamente o que ela diz: programar com "objetos" (em oposição a funções, regras, atores, combinadores de fluxo de dados, etc.) onde a definição específica de objeto é definida pela implementação.
Jon Purdy
1
@tieTYT: Acabei de descrever as implementações que vi na natureza, para demonstrar que é um termo amplo - não contraditório, mas certamente mais amplo que a descrição da Wikipedia.
Jon Purdy
20

NÃO.E estou surpreso com quantas pessoas votaram de outra forma!

Paradigma

É orientado a dados, também conhecido como orientado a dados, porque estamos falando sobre a arquitetura e não a linguagem em que está escrita. As arquiteturas são realizações de estilos ou paradigmas de programação , que geralmente podem ser imprevisivelmente contornados em uma determinada linguagem.


Funcional?

Sua comparação com a programação funcional / processual é uma comparação relevante e significativa. Observe, no entanto, que uma linguagem "Funcional" é diferente do paradigma "Procedimental" . E você pode implementar um ECS em uma linguagem funcional como Haskell , o que as pessoas fizeram.


Onde a coesão acontece

Sua observação é relevante e direta :

"... [o ECS] não impede que você o implemente em uma linguagem OO, mas não seria idiomático fazê-lo de maneira OO firme"


ECS / ES não é EC / CE

Há uma diferença entre as arquiteturas baseadas em componentes, "Entity-Component" e "Entity-Component-System". Como esse é um padrão de design em evolução, vi essas definições usadas de forma intercambiável. As arquiteturas "CE" ou "CE" ou "Entidade-componente" colocam o comportamento em componentes , enquanto as arquiteturas "ES" ou "ECS" colocam o comportamento em sistemas . Aqui estão alguns artigos da ECS, os quais usam nomenclatura enganosa, mas transmitem a ideia geral:

Se você estiver tentando entender esses termos em 2015, verifique se a referência de alguém ao "Sistema de componentes de entidades" não significa "Arquitetura de componentes de entidades".

filhote
fonte
1
Essa é a resposta correta. O ECS não se encaixa muito bem com os paradigmas de POO, porque o ECS trata de separar dados e comportamento, enquanto o OOP é o contrário.
Nax 'vi-vim-nvim'
"enquanto OOP é o contrário" Não há uma definição aceita do que é OOP, a menos que definições acadêmicas inúteis, como SmallTalk, que nunca sejam usadas na prática.
Jean-Michaël Celerier
10

Os sistemas de componentes de entidade (ECSs) podem ser programados de maneira OOP ou funcional, dependendo de como o sistema está definido.

Maneira OOP:

Eu trabalhei em jogos em que uma entidade era um objeto composto de vários componentes. A entidade possui uma função de atualização que modifica o objeto em vigor, chamando atualização em todos os seus componentes. Isso é claramente OOP em estilo - o comportamento está vinculado aos dados e os dados são mutáveis. Entidades são objetos com construtores / destruidores / atualizações.

Maneira mais funcional:

Uma alternativa é a entidade ser dados sem nenhum método. Essa entidade pode existir por si só ou simplesmente ser um ID vinculado a vários componentes. Dessa forma, é possível (mas não é comumente feito) ser totalmente funcional e ter entidades imutáveis ​​e sistemas puros que geram novos estados de componentes.

Parece (por experiência pessoal) que o último caminho está ganhando mais força e por boas razões. A separação dos dados da entidade do comportamento resulta em um código mais flexível e reutilizável (imo). Em particular, o uso de sistemas para atualizar componentes / entidades em lotes pode ter maior desempenho e evitar completamente as complexidades das mensagens entre entidades que afetam muitos ECSs de OOP.

TLDR: Você pode fazê-lo de qualquer maneira, mas eu argumentaria que os benefícios de bons sistemas de componentes de entidades derivam de sua natureza mais funcional.

AGD
fonte
Mais tração, especialmente porque todo o objetivo dos componentes era fugir das hierarquias intratáveis ​​do POO, boa descrição do benefício.
Patrick Hughes
2

Os sistemas de componentes de entidades orientadas a dados podem coexistir com os paradigmas orientados a objetos: - Os sistemas de componentes se prestam ao polimorfismo. - Os componentes podem ser POD (dados antigos simples) e também objetos (com uma classe e métodos), e a coisa toda ainda é 'orientada a dados', desde que os métodos de classe de componente manipulem apenas os dados pertencentes ao objeto local.

Se você escolher esse caminho, eu recomendo que você evite usar Métodos Virtuais, porque, se os tiver, seu componente não será mais apenas dados de componentes, além disso, esses métodos custarão mais para chamar - isso não é COM. Mantenha suas classes de componentes limpas de qualquer referência a algo externo, como regra.

Exemplo seria vec2 ou vec3, um contêiner de dados com alguns métodos para tocar esses dados e nada mais.

Homer
fonte
2
é difícil ler este post (parede de texto). Você se importaria de editá -lo em uma forma melhor? Além disso, seria bom se você explicar aos leitores por que eles podem encontrar ligados blog artigo útil e relevante para a pergunta feita ...
mosquito
... no caso, se você está de alguma forma relacionado com o blog (? é você), seria também desejável divulgar filiação
mosquito
Sim, esse é o meu blog, estou intimamente afiliado ao meu blog público, que divulga detalhes de um sistema de componente de entidade orientado a objetos com base em princípios de design orientado a dados, que eu acredito que sejam relevantes e possivelmente úteis, removi o link para remova qualquer viés.
Homer
2

Penso que o ECS é fundamentalmente distinto do POO e tende a vê-lo da mesma maneira que você, mais próximo da natureza funcional ou especialmente processual, com uma separação muito distinta dos dados da funcionalidade. Há também alguma aparência de programação de um tipo que lida com bancos de dados centrais. Claro que sou a pior pessoa quando se trata de definições formais. Estou preocupado apenas com como as coisas tendem a ser, não com o que elas são definidas conceitualmente.

Estou assumindo um tipo de ECS em que os componentes agregam campos de dados e os tornam acessíveis ao público / globalmente, as entidades agregam componentes e os sistemas fornecem funcionalidade / comportamento nesses dados. Isso leva a características arquitetônicas radicalmente difíceis do que normalmente chamamos de base de código orientada a objetos.

E, é claro, há um pouco de confusão nos limites da maneira como as pessoas projetam / implementam um ECS, e há um debate sobre o que exatamente constitui um ECS em primeiro lugar. No entanto, esses limites também são embaçados no código escrito no que chamamos de linguagens funcionais ou processuais. Entre toda essa imprecisão, a constante fundamental de um ECS com uma separação de dados da funcionalidade parece muito mais próxima da programação funcional ou processual do que OOP.

Uma das principais razões pelas quais não acho útil considerar o ECS pertencer a uma classe de OOP é que a maioria das práticas de SE associadas ao OOP giram em torno da estabilidade da interface pública, com funções de modelagem de interfaces públicas , não dados. A idéia fundamental é que a maior parte das dependências públicas flua para funções abstratas, não para dados concretos. E por causa disso, o OOP tende a tornar muito caro alterar os comportamentos fundamentais do projeto, ao mesmo tempo em que torna muito barato alterar detalhes concretos (como dados e código necessários para implementar a funcionalidade).

O ECS é radicalmente diferente nesse aspecto, considerando como as coisas são acopladas à medida que a maior parte das dependências públicas flui em direção a dados concretos: dos sistemas aos componentes. Como resultado, quaisquer práticas de SE associadas ao ECS girariam em torno da estabilidade dos dados , porque as interfaces (componentes) mais públicas e amplamente usadas são na verdade apenas dados.

Como resultado, um ECS facilita muito a substituição de um mecanismo de renderização OpenGL por um DirectX, mesmo que os dois sejam implementados com funcionalidades radicalmente diferentes e não compartilhem os mesmos designs, desde que os mecanismos DX e GL ter acesso aos mesmos dados estáveis. Enquanto isso, seria muito caro e exigiria a reescrita de vários sistemas para alterar, por exemplo, a representação de dados de a MotionComponent.

Isso é muito oposto ao que tradicionalmente associamos ao OOP, pelo menos em termos de características de acoplamento e o que constitui "interface pública" versus "detalhes de implementação privada". É claro que nos dois casos os "detalhes da implementação" são fáceis de alterar, mas no ECS é o design de dados que é caro mudar (dados não são um detalhe de implementação no ECS), e no OOP é o design da funcionalidade que é caro mudar (o design das funções não é um detalhe de implementação no OOP). Portanto, essa é uma ideia muito diferente de "detalhes de implementação", e um dos principais recursos para mim de um ECS do ponto de vista de manutenção era o que, em meu domínio, os dados necessários para fazer as coisas eram mais fáceis de estabilizar e projetar corretamente de uma vez por todas, com antecedência, do que todas as várias coisas que poderíamos fazer com esses dados (o que mudava o tempo todo à medida que os clientes mudavam de idéia e novas sugestões de usuários apareciam). Como resultado, achei os custos de manutenção em queda quando começamos a direcionar as dependências para longe das funções abstratas em direção a dados brutos e centrais (mas ainda com cuidado com os sistemas que acessam quais componentes para permitir a manutenção de invariantes em um nível são, apesar de todos os dados serem conceitualmente acessível globalmente).

E, no meu caso, pelo menos, o ECS SDK com a API e todos os componentes são realmente implementados em C e não tem nenhuma semelhança com OOP. Eu achei C mais do que adequado para esse propósito, dada a falta inerente de OO nas arquiteturas do ECS e o desejo de ter uma arquitetura de plug-in que possa ser usada pela maior variedade de idiomas e compiladores. Os sistemas ainda são implementados em C ++, já que o C ++ torna as coisas muito convenientes lá e os sistemas modelam a maior parte da complexidade, e acho isso útil para muitas coisas que podem ser consideradas mais próximas do OOP, mas isso é para detalhes de implementação. O projeto arquitetônico em si ainda se parece muito com o procedimento C.

Então eu acho que é um pouco confuso, no mínimo, tentar dizer que um ECS é OO por definição. No mínimo, os fundamentos fazem coisas que são uma volta completa de 180 graus a partir de muitos dos princípios fundamentais geralmente associados ao POO, começando com o encapsulamento e talvez terminando com o que seria considerado as características de acoplamento desejadas.


fonte