¿El objeto de arquitectura del Sistema de componentes de la entidad está orientado por definición?

20

¿ La arquitectura del sistema de componentes de entidad está orientada a objetos, por definición? Me parece más procesal o funcional. Mi opinión es que no le impide implementarlo en un lenguaje OO, pero no sería idiota hacerlo de una manera OO incondicional.

Parece que ECS separa los datos (E y C) del comportamiento (S). Como evidencia :

La idea es no tener métodos de juego integrados en la entidad.

Y :

El componente consta de un conjunto mínimo de datos necesarios para un propósito específico

Los sistemas son funciones de un solo propósito que toman un conjunto de entidades que tienen un componente específico


Creo que esto no está orientado a objetos porque una gran parte de estar orientado a objetos es combinar sus datos y su comportamiento. Como evidencia :

Por el contrario, el enfoque orientado a objetos alienta al programador a colocar datos donde el resto del programa no puede acceder directamente a ellos. En cambio, se accede a los datos llamando a funciones especialmente escritas, comúnmente llamadas métodos, que se agrupan con los datos.

ECS, por otro lado, parece tener que ver con separar sus datos de su comportamiento.

Daniel Kaplan
fuente

Respuestas:

21

Introducción


Los sistemas de entidad-componente son una técnica arquitectónica orientada a objetos.

No existe un consenso universal de lo que significa el término, igual que la programación orientada a objetos. Sin embargo, está claro que los sistemas de entidad-componente están destinados específicamente como una alternativa arquitectónica a la herencia . Jerarquías de herencia son naturales para expresar lo que un objeto es , pero en ciertos tipos de software (como los juegos), que en lugar expresarían lo que un objeto hace .

Es un modelo de objeto diferente al de "clases y herencia", al que probablemente esté acostumbrado a trabajar en C ++ o Java. Las entidades son tan expresivas como las clases, al igual que los prototipos como en JavaScript o Self: todos estos sistemas se pueden implementar en términos unos de otros.

 

Ejemplos


Vamos a decir que Playeres una entidad con Position, Velocityy KeyboardControlledcomponentes, que hacen las cosas obvias.

entity Player:
  Position
  Velocity
  KeyboardControlled

Sabemos que Positiondebe verse afectado por Velocityy Velocitypor KeyboardControlled. La pregunta es cómo nos gustaría modelar esos efectos.

 

Entidades, Componentes y Sistemas


Supongamos que los componentes no tienen referencias entre sí; un Physicssistema externo atraviesa todos los Velocitycomponentes y actualiza los Positionde la entidad correspondiente; un Inputsistema atraviesa todos los KeyboardControlledcomponentes y actualiza el Velocity.

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

Esto satisface los criterios:

  • La entidad no expresa ninguna lógica de juego / negocio.

  • Los componentes almacenan datos que describen el comportamiento.

Los sistemas ahora son responsables de manejar eventos y promulgar el comportamiento descrito por los componentes. También son responsables de manejar las interacciones entre entidades, como las colisiones.

 

Entidades y Componentes


Sin embargo, supongamos que los componentes de hacerlo tienen referencias a los otros. Ahora la entidad es simplemente un constructor que crea algunos componentes, los une y gestiona sus vidas:

class Player:
  construct():
    this.p = Position()
    this.v = Velocity(this.p)
    this.c = KeyboardControlled(this.v)

La entidad ahora puede enviar eventos de entrada y actualización directamente a sus componentes. Velocityrespondería a las actualizaciones y KeyboardControlledrespondería a las entradas. Esto aún satisface nuestros criterios:

  • La entidad es un contenedor "tonto" que solo reenvía eventos a los componentes.

  • Cada componente representa su propio comportamiento.

Aquí las interacciones de los componentes son explícitas, no impuestas desde el exterior por un sistema. Los datos que describen un comportamiento (¿cuál es la cantidad de velocidad?) Y el código que lo promulga (¿qué es la velocidad?) Están acoplados, pero de manera natural. Los datos se pueden ver como parámetros para el comportamiento. Y algunos componentes no actúan en absoluto: a Positiones el comportamiento de estar en un lugar .

Las interacciones pueden manejarse a nivel de la entidad ("cuando una Playercolisión con un Enemy...") o al nivel de componentes individuales ("cuando una entidad con una Lifecolisión con una entidad con Strength...").

 

Componentes


¿Cuál es la razón por la cual la entidad existe? Si es simplemente un constructor, entonces podemos reemplazarlo con una función que devuelve un conjunto de componentes. Si luego queremos consultar entidades por su tipo, también podemos tener un Tagcomponente que nos permita hacer exactamente eso:

function Player():
  t = Tag("Player")
  p = Position()
  v = Velocity(p)
  c = KeyboardControlled(v)
  return {t, p, v, c}
  • Las entidades son tan tontas como pueden ser: son solo conjuntos de componentes.

  • Los componentes responden directamente a los eventos como antes.

Las interacciones ahora deben ser manejadas por consultas abstractas, desacoplando completamente los eventos de los tipos de entidad. No hay más tipos de entidades para consultar: los Tagdatos arbitrarios probablemente se usan mejor para la depuración que la lógica del juego.

 

Conclusión


Las entidades no son funciones, reglas, actores o combinadores de flujo de datos. Son sustantivos que modelan fenómenos concretos; en otras palabras, son objetos. Es como dice Wikipedia: los sistemas de entidad-componente son un patrón de arquitectura de software para modelar objetos generales.

Jon Purdy
fuente
2
La principal alternativa a la OO basada en clases, la OO basada en prototipos, también parece combinar datos y comportamiento. En realidad, parece diferir de ECS tanto como OO basado en clases. Entonces, ¿podrías explicar qué quieres decir con OO?
Para agregar a la pregunta de @ delnan, ¿estás en desacuerdo con el fragmento del artículo de OO wikipedia que cité?
Daniel Kaplan
@tieTYT: La cita de Wikipedia habla de encapsulación y ocultación de información. No creo que sea evidencia de que se requiera el acoplamiento de datos y comportamiento, solo que es común.
Jon Purdy
@delnan: No quiero decir nada con OO. Para mí, la programación orientada a objetos es exactamente lo que dice: programación con "objetos" (en oposición a funciones, reglas, actores, combinadores de flujo de datos, etc.) donde la definición particular de objeto está definida por la implementación.
Jon Purdy
1
@tieTYT: Estaba describiendo implementaciones que he visto en la naturaleza, para transmitir que es un término amplio, no contradictorio, pero ciertamente más amplio que la descripción de Wikipedia.
Jon Purdy
20

NO.¡Y estoy sorprendido de cuántas personas votaron de otra manera!

Paradigma

Está orientado a datos, también conocido como impulsado por datos, porque estamos hablando de la arquitectura y no del lenguaje en el que está escrito. Las arquitecturas son realizaciones de estilos o paradigmas de programación , que generalmente pueden ser desaconsejados en un lenguaje determinado.


¿Funcional?

Su comparación con la programación funcional / de procedimiento es una comparación relevante y significativa. Tenga en cuenta, sin embargo, que un lenguaje "funcional" es diferente del paradigma "procesal" . Y puede implementar un ECS en un lenguaje funcional como Haskell , que la gente ha hecho.


Donde ocurre la cohesión

Su observación es relevante y acertada :

"... [ECS] no impide que lo implementes en un lenguaje OO, pero no sería una idiotez hacerlo de una manera incondicional"


ECS / ES no es EC / CE

Hay una diferencia entre las arquitecturas basadas en componentes, "Entity-Component" y "Entity-Component-System". Como este es un patrón de diseño en evolución, he visto que estas definiciones se usan indistintamente. Las arquitecturas "EC" o "CE" o "Componente-entidad" ponen el comportamiento en los componentes , mientras que las arquitecturas "ES" o "ECS" ponen el comportamiento en los sistemas . Aquí hay algunos artículos de ECS, los cuales usan una nomenclatura engañosa, pero transmiten la idea general:

Si está tratando de entender estos términos en 2015, asegúrese de que la referencia de alguien al "Sistema de componentes de la entidad" no signifique "arquitectura de componentes de la entidad".

cachorro
fuente
1
Esta es la respuesta correcta. ECS no encaja muy bien con los paradigmas de OOP, porque ECS se trata de separar datos y comportamiento, mientras que OOP es todo lo contrario.
Nax 'vi-vim-nvim'
"mientras que OOP es casi lo contrario" No hay una definición aceptada de lo que se trata OOP, a menos que definiciones académicas inútiles como SmallTalk's que nunca se usen en la práctica.
Jean-Michaël Celerier
10

Los sistemas de componentes de entidad (ECS) se pueden programar de manera funcional o de OOP, dependiendo de cómo se defina el sistema.

OOP manera:

He trabajado en juegos donde una entidad era un objeto compuesto de varios componentes. La entidad tiene una función de actualización que modifica el objeto en su lugar llamando a la actualización en todos sus componentes a su vez. Este es claramente un estilo OOP: el comportamiento está vinculado a los datos y los datos son mutables. Las entidades son objetos con constructores / destructores / actualizaciones.

Forma más funcional:

Una alternativa es que la entidad sea datos sin ningún método. Esta entidad puede existir por derecho propio o simplemente ser una identificación que está vinculada a varios componentes. De esta manera es posible (pero no se hace comúnmente) ser completamente funcional y tener entidades inmutables y sistemas puros que generen nuevos estados componentes.

Parece (por experiencia personal) que esta última forma está ganando más tracción y por buenas razones. La separación de los datos de la entidad del comportamiento da como resultado un código más flexible y reutilizable (imo). En particular, el uso de sistemas para actualizar componentes / entidades en lotes puede ser más eficaz y evita por completo las complejidades de la mensajería entre entidades que afectan a muchos OOP ECS.

TLDR: puede hacerlo de cualquier manera, pero diría que los beneficios de los sistemas de componentes de buena entidad se derivan de su naturaleza más funcional.

AGD
fuente
Más tracción, especialmente dado que el objetivo de los componentes era alejarse de las jerarquías de OOP intratables, buena descripción del beneficio.
Patrick Hughes
2

Los sistemas de componentes orientados a datos pueden coexistir con paradigmas orientados a objetos: - Los sistemas de componentes se prestan al polimorfismo. - Los componentes pueden ser tanto POD (datos antiguos simples) como TAMBIÉN objetos (con una clase y métodos), y todo sigue estando 'orientado a datos', siempre que los métodos de clase de componentes solo manipulen datos propiedad del objeto local.

Si elige esta ruta, le recomiendo que evite el uso de métodos virtuales, porque si los tiene, su componente ya no es solo datos de componentes, además de que esos métodos cuestan más para llamar, esto no es COM. Mantenga sus clases de componentes limpias de cualquier referencia a cualquier cosa externa, como regla.

El ejemplo sería vec2 o vec3, un contenedor de datos con algunos métodos para tocar esos datos, y nada más.

Homero
fuente
2
esta publicación es bastante difícil de leer (muro de texto). ¿Te importaría editarlo en una mejor forma? Además, sería de ayuda si se le explica a los lectores por qué se puede encontrar vinculados artículo de blog útil y relevante a la pregunta ...
mosquito
... en caso de que de alguna manera estés relacionado con ese blog (¿lo estás?), también sería deseable revelar la afiliación
mosquito
Sí, ese es mi blog, estoy muy afiliado a mi blog público, que revela detalles de un sistema de componentes de entidad orientado a objetos basado en principios de diseño orientados a datos, lo que creo que es relevante y posiblemente útil, sin embargo, he eliminado el enlace a eliminar cualquier sesgo.
Homer
2

Pienso en ECS como fundamentalmente distinto de OOP y tiendo a verlo de la misma manera que usted, más cercano a la naturaleza funcional o especialmente de procedimiento con una separación muy clara de los datos de la funcionalidad. También hay algo parecido a la programación de un tipo que trata con bases de datos centrales. Por supuesto, soy la peor persona cuando se trata de definiciones formales. Solo me preocupa cómo tienden a ser las cosas, no cómo se definen conceptualmente.

Asumo un tipo de ECS donde los componentes agregan campos de datos y los hacen accesibles públicamente / globalmente, las entidades agregan componentes y los sistemas proporcionan funcionalidad / comportamiento en esos datos. Eso lleva a características arquitectónicas radicalmente difíciles de lo que normalmente llamaríamos una base de código orientada a objetos.

Y, por supuesto, hay un poco de confusión en los límites en la forma en que las personas diseñan / implementan un ECS, y hay un debate sobre qué constituye exactamente un ECS en primer lugar. Sin embargo, tales límites también están borrosos en el código escrito en lo que llamamos lenguajes funcionales o de procedimiento. Entre toda esta confusión, la constante fundamental de un ECS con una separación de datos de la funcionalidad me parece mucho más cercana a la programación funcional o de procedimiento que a la OOP.

Una de las principales razones por las que no creo que sea útil considerar que ECS pertenece a una clase de OOP es que la mayoría de las prácticas de SE asociadas con OOP giran en torno a la estabilidad de la interfaz pública, con funciones de modelado de interfaces públicas , no datos. La idea fundamental es que la mayor parte de las dependencias públicas fluyen hacia funciones abstractas, no hacia datos concretos. Y debido a eso, OOP tiende a hacer que sea muy costoso cambiar los comportamientos fundamentales de diseño, a la vez que es muy barato cambiar detalles concretos (como los datos y el código necesarios para implementar la funcionalidad).

ECS es radicalmente diferente a este respecto, considerando cómo se acoplan las cosas a medida que la mayor parte de las dependencias públicas fluyen hacia datos concretos: de sistemas a componentes. Como resultado, cualquier práctica de SE asociada con ECS giraría en torno a la estabilidad de los datos , porque las interfaces (componentes) más públicas y más utilizadas son en realidad solo datos.

Como resultado, un ECS hace que sea muy fácil hacer cosas como sustituir un motor de renderizado OpenGL por uno DirectX, incluso si los dos se implementan con una funcionalidad radicalmente diferente y no comparten los mismos diseños, siempre que el motor DX y GL tener acceso a los mismos datos estables. Mientras tanto, sería muy costoso y requeriría reescribir un montón de sistemas para cambiar, por ejemplo, la representación de datos de a MotionComponent.

Eso es muy opuesto a lo que tradicionalmente asociamos con OOP, al menos en términos de características de acoplamiento y lo que constituye "interfaz pública" frente a "detalles de implementación privada". Por supuesto, en ambos casos los "detalles de implementación" son fáciles de cambiar, pero en ECS el diseño de los datos es costoso de cambiar (los datos no son detalles de implementación en ECS), y en OOP es el diseño de la funcionalidad lo que es costoso cambiar (el diseño de funciones no es un detalle de implementación en OOP). Esa es una idea muy diferente de los "detalles de implementación", y uno de los principales atractivos para mí de un ECS desde una perspectiva de mantenimiento fue que en mi dominio, los datos requeridos para hacer las cosas fueron más fáciles de estabilizar y diseñar correctamente de una vez por todas que las diversas cosas que podríamos hacer con esos datos (lo que cambiaría todo el tiempo a medida que los clientes cambiaran de opinión y surgieran nuevas sugerencias de usuarios). Como resultado, descubrí que los costos de mantenimiento se desplomaron cuando comenzamos a desviar las dependencias de las funciones abstractas hacia los datos crudos y centrales (pero aún con cuidado sobre qué sistemas acceden a qué componentes para permitir mantener invariantes en un grado razonable a pesar de todos los datos conceptualmente globalmente accesible).

Y al menos en mi caso, el SDK de ECS con la API y todos los componentes se implementan realmente en C y no se parecen a OOP. He encontrado que C es más que adecuado para tal propósito dada la falta inherente de OO en las arquitecturas ECS y el deseo de tener una arquitectura de complementos que pueda ser utilizada por la más amplia gama de lenguajes y compiladores. Los sistemas todavía se implementan en C ++ ya que C ++ hace que las cosas sean muy convenientes allí y los sistemas modelan la mayor parte de la complejidad y allí encuentro uso para muchas cosas que podrían considerarse más cercanas a OOP, pero eso es para detalles de implementación. El diseño arquitectónico en sí todavía se parece a un procedimiento muy C.

Así que creo que es algo confuso, al menos, tratar de decir que un ECS es OO por definición. Como mínimo, los fundamentos hacen cosas que son un giro completo de 180 grados de muchos de los principios fundamentales generalmente asociados con la POO, comenzando con la encapsulación y tal vez terminando con lo que se considerarían características de acoplamiento deseadas.


fuente