El sistema de entidad-componente ( ECS ) es un patrón de arquitectura de software que se utiliza principalmente en el desarrollo de videojuegos para la representación de objetos del mundo del juego. Un ECS comprende entidades compuestas por componentes de datos, con sistemas que operan sobre los componentes.
ECS sigue el principio de composición sobre herencia , lo que significa que cada entidad se define no por una jerarquía de tipos, sino por los componentes que están asociados a ella. Los sistemas actúan globalmente sobre todas las entidades que tienen los componentes requeridos.
Especialmente cuando se escribe “Sistema de componentes de entidad”, debido a una ambigüedad en el idioma inglés, una interpretación común del nombre es que un ECS es un sistema que comprende entidades y componentes. Por ejemplo, en la charla de 2013 en GDC, [1] Scott Bilas compara un sistema de objetos C++ y su nuevo sistema de componentes personalizado. Esto es coherente con un uso tradicional del término sistema en la ingeniería de sistemas general con el sistema de objetos Common Lisp y el sistema de tipos como ejemplos.
ECS combina ideas ortogonales bien establecidas en la ciencia informática general y la teoría de lenguajes de programación . Por ejemplo, los componentes pueden verse como un idioma mixto en varios lenguajes de programación. Los componentes son un caso especializado bajo el enfoque de delegación general y el protocolo de metaobjetos . Es decir, cualquier sistema de objetos de componentes completo puede expresarse con las plantillas y el modelo de empatía dentro de la visión de programación orientada a objetos del Tratado de Orlando [2] .
Entidad : una entidad representa un objeto de propósito general. En el contexto de un motor de juegos, por ejemplo, cada objeto de juego básico se representa como una entidad. Por lo general, solo consta de un identificador único. Las implementaciones suelen utilizar un entero simple para esto. [3]
Componente : un componente caracteriza a una entidad como poseedora de un aspecto particular y contiene los datos necesarios para modelar ese aspecto. Por ejemplo, cada objeto de juego que pueda sufrir daño podría tener un componente de Salud asociado con su entidad. Las implementaciones suelen utilizar estructuras , clases o matrices asociativas . [3]
Sistema : Un sistema es un proceso que actúa sobre todas las entidades con los componentes deseados. Por ejemplo, un sistema de física puede consultar entidades que tengan componentes de masa, velocidad y posición, e iterar sobre los resultados haciendo cálculos físicos sobre el conjunto de componentes para cada entidad.
El comportamiento de una entidad puede modificarse en tiempo de ejecución mediante sistemas que añaden, eliminan o modifican componentes. Esto elimina los problemas de ambigüedad de las jerarquías de herencia amplias y profundas que suelen encontrarse en las técnicas de programación orientada a objetos , que son difíciles de entender, mantener y ampliar. Los enfoques comunes de ECS son altamente compatibles con las técnicas de diseño orientadas a datos y, a menudo, se combinan con ellas . Los datos de todas las instancias de un componente se almacenan juntos de forma contigua en la memoria física, lo que permite un acceso eficiente a la memoria para los sistemas que operan sobre muchas entidades.
En 1998, Thief: The Dark Project fue pionero en el uso de un ECS. [4] El motor se utilizó posteriormente para su secuela, así como para System Shock 2 .
En 2002, Scott Bilas de Gas Powered Games (Dungeon Siege) dio una charla fundamental sobre ECS. [1] Esto inspiró numerosas implementaciones posteriores muy conocidas.
A principios de enero de 2007, Mick West , que trabajó en la serie Tony Hawk, compartió sus experiencias sobre el proceso de adopción de ECS en Neversoft. [5]
También en 2007, el equipo que trabajaba en Operation Flashpoint: Dragon Rising experimentó con diseños de ECS, incluidos aquellos inspirados en Bilas/ Dungeon Siege , y Adam Martin escribió posteriormente un relato detallado del diseño de ECS, [6] incluyendo definiciones de terminología y conceptos básicos. [7] En particular, el trabajo de Martin popularizó las ideas de los sistemas como un elemento de primera clase, las entidades como identificadores, los componentes como datos sin procesar y el código almacenado en sistemas, no en componentes o entidades.
En 2015, Apple Inc. presentó GameplayKit, un marco API para el desarrollo de juegos de iOS , macOS y tvOS que incluye una implementación de ECS. [8]
En agosto de 2018, Sander Mertens creó el popular marco ECS flecs. [9]
En octubre de 2018 [10], la empresa Unity lanzó su demostración de megaciudad que utilizaba una pila de tecnología construida sobre un ECS. El ECS de Unity se ejecuta en una poderosa arquitectura optimizada conocida como DOTS que "permite a los creadores escalar el procesamiento de una manera de alto rendimiento".
El diseño de datos de diferentes ECS puede diferir, así como también la definición de los componentes, cómo se relacionan con las entidades y cómo los sistemas acceden a los componentes de las entidades.
Adam Martin define en su serie de blogs lo que él considera un sistema entidad-componente. [7]
Una entidad solo consta de un ID para acceder a los componentes. Es una práctica común utilizar un ID único para cada entidad. Esto no es un requisito, pero tiene varias ventajas:
Algunas de estas ventajas también se pueden conseguir utilizando punteros inteligentes .
Los componentes no tienen código de juego (comportamiento) en su interior. No es necesario que estén ubicados físicamente junto con la entidad, pero deben ser fáciles de encontrar y acceder mediante la entidad.
"Cada sistema se ejecuta de forma continua (como si cada sistema tuviera su propio hilo privado) y realiza acciones globales en cada entidad que posee un componente o componentes que coinciden con la consulta de ese sistema".
El diseño de Unity tiene tablas, cada una con columnas de componentes. En este sistema, un tipo de entidad se basa en los componentes que contiene. Para cada tipo de entidad, hay una tabla (llamada arquetipo ) que contiene columnas de componentes que coinciden con los componentes utilizados en la entidad. Para acceder a una entidad en particular, se debe encontrar el arquetipo (tabla) correcto e indexar cada columna para obtener cada componente correspondiente para esa entidad.
Apparatus es una implementación de ECS de terceros para Unreal Engine que ha introducido algunas características adicionales al paradigma ECS común. Una de esas características es el soporte de la jerarquía de tipos para los componentes. Cada componente puede tener un tipo de componente base (o una clase base) de forma muy similar a la programación orientada a objetos . Un sistema puede entonces consultar con la clase base y obtener todos sus descendientes coincidentes en la selección de entidades resultante. Esto puede ser muy útil para implementar cierta lógica común en un conjunto de componentes diferentes y agrega una dimensión adicional al paradigma.
Flecs es una implementación de ECS rápida y liviana para C y C++ que le permite crear juegos y simulaciones con millones de entidades.
La forma normal de transmitir datos entre sistemas es almacenarlos en componentes y luego hacer que cada sistema acceda al componente de forma secuencial. Por ejemplo, la posición de un objeto se puede actualizar periódicamente. Esta posición luego es utilizada por otros sistemas. Si hay muchos eventos diferentes poco frecuentes, se necesitarán muchos indicadores en uno o más componentes. Los sistemas tendrán que monitorear estos indicadores en cada iteración, lo que puede volverse ineficiente. Una solución podría ser usar el patrón de observador . Todos los sistemas que dependen de un evento se suscriben a él. La acción del evento, por lo tanto, solo se ejecutará una vez, cuando sucede, y no se necesita sondeo.
El ECS no tiene problemas con los problemas de dependencia que se encuentran comúnmente en la programación orientada a objetos, ya que los componentes son simples contenedores de datos, no tienen dependencias. Cada sistema normalmente consultará el conjunto de componentes que una entidad debe tener para que el sistema opere en él. Por ejemplo, un sistema de renderizado puede registrar los componentes de modelo, transformación y dibujables. Cuando se ejecuta, el sistema ejecutará su lógica en cualquier entidad que tenga todos esos componentes. Otras entidades simplemente se omiten, sin necesidad de árboles de dependencia complejos. Sin embargo, este puede ser un lugar para que los errores se escondan, ya que la propagación de valores de un sistema a otro a través de componentes puede ser difícil de depurar. El ECS se puede utilizar donde los datos desacoplados deben estar vinculados a un tiempo de vida determinado.
El ECS utiliza composición, en lugar de árboles de herencia. Una entidad estará formada típicamente por un ID y una lista de componentes que están asociados a ella. Cualquier objeto de juego puede ser creado agregando los componentes correctos a una entidad. Esto permite al desarrollador agregar fácilmente características a una entidad, sin ningún problema de dependencia. Por ejemplo, una entidad de jugador podría tener un componente de bala agregado a ella, y luego cumpliría con los requisitos para ser manipulada por algún sistema bulletHandler , lo que podría resultar en que ese jugador dañara cosas al chocar con ellas.
Muchos desarrolladores de juegos, como Adam Martin, han proclamado las ventajas de utilizar sistemas de almacenamiento de datos de juegos diseñados con ECS. Un buen ejemplo son las publicaciones del blog de Richard Lord, donde analiza las ventajas y las razones por las que los sistemas de almacenamiento de datos de juegos diseñados con ECS son tan útiles. [11]
Aunque se utiliza principalmente en el desarrollo de videojuegos, el ECS puede ser útil en otros dominios. [12] [ se necesita un ejemplo ]