Entidades Componentes y Sistemas

En este artículo vamos a explicar qué son los ECS: Entidades, Componentes y Sistemas en profundidad en el desarrollo de videojuegos. Si en el artículo anterior vimos por qué surgió ECS y qué problemas intenta resolver dentro del desarrollo de videojuegos, ahora es momento de estudiar los tres pilares fundamentales que forman la arquitectura ECS.

Aunque sus definiciones son relativamente sencillas, comprender cómo colaboran entre sí requiere un pequeño cambio de mentalidad respecto a la programación POO orientada a objetos tradicional. Por este motivo, en lugar de limitarnos a estudiar conceptos teóricos, utilizaremos ejemplos prácticos para entender cómo se construye realmente un videojuego utilizando ECS: Entidades, Componentes y Sistemas.

NOTA: En este artículo utilizaremos una implementación de ECS centrada en la entidad (orientada al desarrollo de videojuegos) y no una implementación puramente orientada a los datos, donde los componentes se almacenan de forma contigua para maximizar el rendimiento en motores gráficos.

¿Qué son las entidades?

Una de las mayores diferencias entre ECS: Entidades, Componentes y Sistemas y la POO (Programación Orientada a Objetos) tradicional es el concepto de entidad. Cuando comenzamos a estudiar ECS solemos pensar que una entidad será una clase o un objeto complejo que contendrá toda la información y comportamiento del juego.

Sin embargo, en ECS una entidad es algo mucho más sencillo que en realidad debemos imaginar como un objeto vacío:

let player = {};
let enemy = {};
let bullet = {};

A primera vista puede parecer extraño, pero estas tres entidades no contienen información ni del jugador, ni del enemigo ni de los disparos. Ni siquiera sabemos quien puede disparar, cuanto daño hacen los disparos, cuanta salud tiene el enemigo o si el jugador puede recibir daño.

Todavía no sabemos nada de todo esto pero precisamente esa es la idea. Una entidad por sí sola no tiene posición, vida, velocidad, armas ni comportamiento. Toda esa información se añadirá posteriormente mediante componentes.

Una entidad simplemente representa algo que existe dentro del mundo del juego, por este motivo suele decirse que las entidades identifican y los componentes describen. La entidad representa el objeto y los componentes definen sus características.

Mientras que en Programación Orientada a Objetos solemos agrupar toda la información dentro de una misma clase, la filosofía de ECS: Entidades, Componentes y Sistemas consiste en separar completamente la identidad de un objeto de sus datos y comportamientos.

En ECS la entidad permanece vacía y toda la información se distribuye entre distintos componentes independientes. De esta forma podemos construir cualquier tipo de objeto combinando componentes sin necesidad de crear complejas jerarquías de herencia.

¿Qué son los componentes?

Un componente es una estructura que almacena datos relacionados con una característica concreta de una entidad. Por ejemplo, podemos crear un componente encargado de almacenar la posición:

let position = {
    x: 100,
    y: 200
};

Otro componente podría almacenar la vida:

let health = {
    hp: 50
};

Y otro la velocidad:

let velocity = {
    vx: 3,
    vy: 0
};

Cada componente representa un tipo de dato asociado a una responsabilidad específica y contiene únicamente la información necesaria para describir esa característica. De modo que si en el apartado anterior vimos que una entidad es simplemente un objeto vacío como:

let enemy = {};

Ahora para definir a la entidad podemos añadirle los componentes que queramos y asociarlos a la entidad con:

let enemy = {
    position,
    health,
    velocity
};

Con este método podemos describir completamente a nuestro enemigo de forma sencilla utilizando únicamente una estructura de datos. La entidad sigue representando el objeto del juego, mientras que los componentes almacenan toda la información relacionada con él.

Este es uno de los principios fundamentales de ECS: Entidades, Componentes y Sistemas, los componentes sólo almacenan datos, nada más. Los componentes no contienen lógica ni comportamiento. Los componentes únicamente describen el estado de una entidad, mientras que el comportamiento y su lógica pertenece a los sistemas.

Una de las ventajas de ECS es que podemos construir objetos complejos combinando componentes sencillos, sin utilizar herencias de clases POO. Por ejemplo:

let boss = {
    position,
    health,
    velocity,
    weapon
};

Esta capacidad para combinar características es una de las principales razones por las que ECS resulta tan flexible. Además, podemos utilizar un mismo tipo de componente en multitud de entidades distintas. Cada entidad utiliza únicamente los componentes que necesita. Esto evita crear grandes jerarquías de clases y facilita enormemente la reutilización de datos dentro del videojuego.

NOTA: En ECS especializados los componentes no suelen almacenarse directamente dentro de la entidad como hemos hecho en estos ejemplos. Sinó mediante estructuras especializadas para mejorar el rendimiento y facilitar el acceso a los datos. Esto lo veremos en el artículo ECS y rendimiento.

¿Qué son los sistemas?

Los sistemas contienen la lógica del videojuego y son los encargados de procesar entidades que poseen determinados componentes, para producir su comportamiento. Por ejemplo, supongamos que tenemos el siguiente sistema de movimiento:

function movementSystem(entities) {

    for (const entity of entities) {

        if (!entity.position || !entity.velocity) continue;

        entity.position.x += entity.velocity.vx;
        entity.position.y += entity.velocity.vy;
    }
}

Este sistema se encarga de ejecutar el comportamiento y la lógica del movimiento de un listado de cualquier entidad que tenga los siguientes componentes:

Position
Velocity

El sistema simplemente busca entidades que tengan los componentes (Position, Velocity) y actualiza su posición: nada más. Lo interesantes de este sistema es que no sabe qué tipo de Entidad está procesando, ni le importa. Sólo le importa que existan los componentes (Position, Velocity). Esto permite reutilizar la lógica para cientos de tipos distintos de objetos.

La idea clave es que en ECS, los sistemas no contienen lógica específica de cada tipo de entidad, sólo contienen lógica basada en datos. Esto permite reutilizar el mismo sistema para múltiples tipos de objetos dentro del juego sin necesidad de herencia ni estructuras complejas. Incluso, podemos tener diferentes tipos de sistemas de movimiento utilizando los mismos componentes, consiguiendo aún más versatilidad.

Si una entidad no tiene alguno de estos componentes, el sistema la ignora, si los tiene, ejecuta su comportamiento asociado. De esta forma los sistemas recorren las entidades y aplican la lógica necesaria durante el transcurso del videojuego y el comportamiento emerge de la colaboración entre componentes y sistemas:

movementSystem(entities);
combatSystem(entities);
aiSystementities();
renderSystem(entities);

Entidades, Componentes y Sistemas

Como hemos visto, ECS: Entidades, Componentes y Sistemas se basa en una idea muy simple:

  • Las entidades identifican.
  • Los componentes almacenan datos.
  • Los sistemas procesan esos datos.

Separar estas responsabilidades permite construir objetos complejos mediante composición en lugar de herencia y facilita la reutilización de la lógica entre distintos tipos de entidades. Aunque al principio pueda parecer una forma extraña de programar, comprender esta separación es la clave para aprovechar todas las ventajas que ofrece ECS.

El sistema de movimiento es un ejemplo básico de cómo ECS separa la lógica del juego de la estructura de los objetos. Las entidades aportan identidad, los componentes aportan datos y los sistemas convierten esos datos en comportamiento.

Personalmente, lo que más me gusta de este enfoque es que se pueden crear entidades sin necesidad de caer en complejas jerarquías y herencias de la POO, que indirectamente también repercuten en un peor rendimiento. Gran parte de lo explicado en mis libros «Programando Videojuegos» cubre indirectamente la esencia del ECS. Muchos desarrolladores llegan a soluciones similares mediante composición, funciones reutilizables o sistemas especializados sin implementar un ECS puro.

Este artículo forma parte de la serie ECS: Entidades, Componentes y Sistemas, donde se explica su arquitectura y cómo aplicarla en la programación de videojuegos.

¡ Espero que este artículo sea de vuestro interés !

Logotipo de Safe CreativeLogotipo de Creative Commons Attribution 4.0

Deja un comentario