ECS y máquinas de estados (FSM)

En este artículo vamos a explicar la arquitectura ECS aplicada a las máquinas de estados (FSM) en el desarrollo de videojuegos en JavaScript. Para ello, primero debemos entender que una máquina de estados (FSM, Finite State Machine) es un modelo de programación donde un sistema puede encontrarse en un número limitado de estados y cambiar entre ellos en función de distintos eventos o condiciones.

Aunque pueda parecer un concepto muy teórico, en realidad forma parte del funcionamiento de prácticamente cualquier videojuego. Personajes, enemigos o incluso el propio jugador cambian continuamente de estado según la lógica o la inteligencia artificial del juego.

Veamos cómo podemos combinar las máquinas de estados (FSM) con la arquitectura ECS para construir enemigos más organizados, flexibles y fáciles de mantener.

Máquinas de estados (FSM)

Las Máquinas de Estados Finitos (FSM) nacieron a mediados del siglo XX, pero siguen siendo un pilar fundamental en la programación de videojuegos por varias razones clave:

  • Determinismo absoluto: Una FSM elimina el caos. Dados un estado actual y un estímulo concreto, el resultado final es 100% un estado predecible y consistente.
  • Unicidad: El sistema solo puede tener activado un estado a la vez, por ejemplo: atacar, patrullar, etc.
  • Transición: Pasar de un estado a otro únicamente ocurre si un evento o estímulo específico activa esa transición.
  • Diseño mediante diagramas de flujo: Antes de programar una FSM suelo diseñarla mediante un diagrama de flujo. Este enfoque, muy próximo al funcionamiento de una máquina de Moore, permite visualizar fácilmente todos los estados y las transiciones antes de escribir una sola línea de código.
  • Simplicidad de depuración: Si un personaje de un videojuego se queda flotando en el aire de forma infinita, el programador no tiene que revisar miles de líneas de código aleatorias; simplemente abre el bloque de código asignado al Estado: Saltando.
  • Consumo mínimo de recursos: Las FSM requieren muy poca memoria y apenas consumen tiempo de procesamiento, por lo que resultan ideales para controlar simultáneamente el comportamiento de un gran número de enemigos en un videojuego.

ECS y FSM

Actualmente es muy común combinar una máquina de estados FSM con una arquitectura ECS. Mientras ECS es una arquitectura encargada de organizar los datos de un videojuego, una FSM es un patrón de comportamiento que define el flujo de decisiones de una entidad.

Si recordamos el artículo anterior, donde identificábamos a cada enemigo mediante un ID y los sistemas que debían aplicarse a cada uno de ellos, en un videojuego moderno estructurado bajo ECS, la máquina de estados se convierte simplemente en un componente más de la entidad. Por ejemplo:

  • El componente guarda una variable llamada EstadoActual = "Alerta".
  • El sistema (código) lee ese componente en cada ciclo de juego y aplica las reglas lógicas de la máquina de estados: «Si la entidad está en ‘Alerta’ y la distancia al Jugador es menor a 5 metros, cambia su componente a ‘Persiguiendo'».

Por tanto, ECS y las máquinas de estados (FSM) no compiten entre sí, sino que se complementan perfectamente. ECS organiza la estructura general del videojuego, mientras que las máquinas de estados controlan el comportamiento de sus entidades. Dicho de otro modo, mientras ECS responde a la pregunta «¿cómo organizo los datos de mis entidades?», una FSM responde a «¿qué debe hacer una entidad en este momento?».

Combinando componentes ID y state

Manteniendo la idea del artículo anterior «ECS aplicado a enemigos», además de un ID para identificar a cada entidad enemiga, podemos añadir un nuevo componente state para manejar sus estados finitos. Por ejemplo:

enemy = {
    ID: SOLDIER,
    position: { x:100, y:50 },
    health: 100,
    state: PATROL
};

Este componente state es simplemente otro dato del enemigo. Sin embargo ahora podemos implementar diferentes estados según el tipo de enemigo. Si recordamos el artículo anterior donde cada tipo de enemigo tenía su propio sistema update() del tipo:

update() {
  for (let i=0; i<this.enemies.length; i++) {
    let enemy = this.enemies[i];
    switch(enemy.ID) {
        case SOLDIER:
            systemSoldier.update(enemy);
            break;

        case ARCHER:
            systemArcher.update(enemy);
            break;

        case BOSS:
            systemBoss.update(enemy);
            break;
    }
  }
}

Ahora podemos implementar dentro de cada sistema su propia máquina de estados FSM como por ejemplo, dentro de systemSoldier:

update(enemy) {
    switch(enemy.state) {
        case PATROL:
            this.patrol(enemy);
            break;

        case ATTACK:
            this.attack(enemy);
            break;

        case FLEE:
            this.flee(enemy);
            break;

        case DEAD:
            this.dead(enemy);
            break;
    }
}

Mediante la combinación del identificador ID y el componente state, el sistema primero determina qué tipo de enemigo debe procesar y, a continuación, decide qué acción ejecutar en función de su estado actual.

Como puede observarse, ECS y las máquinas de estados (FSM) resuelven problemas diferentes y, por tanto, se complementan perfectamente:

  • ECS → organiza los datos de las entidades.
  • FSM → controla su comportamiento.

Este es el enfoque que llevo utilizando últimamente en mis videojuegos:

  • el ID decide qué sistema o IA procesa al enemigo (systemSoldier, systemBoss, etc)
  • el state decide qué acción ejecuta ese sistema (PATROL, ATTACK, FLEE, DEAD, etc)

En otras palabras, el ID decide quién procesa al enemigo y el state decide qué hace ese enemigo. ECS y las máquinas de estados (FSM) no son alternativas entre sí, sino herramientas complementarias. Mientras ECS organiza la información de las entidades, las FSM se encargan de controlar su comportamiento.

Conclusiones ECS y máquinas de estados (FSM)

Aunque actualmente existen técnicas de inteligencia artificial mucho más avanzadas, las máquinas de estados siguen siendo una de las soluciones más utilizadas en el desarrollo de videojuegos. Son rápidas, sencillas de implementar y fáciles de mantener.

La combinación de ECS y máquinas de estados (FSM) me permite mantener una inteligencia artificial organizada, ampliar fácilmente el comportamiento de cada enemigo, reutilizar sistemas, simplificar la depuración y conservar una arquitectura flexible y sencilla de mantener.

Aunque a medida que añadimos nuevos tipos de enemigos, sistemas y máquinas de estados la arquitectura pueda parecer más compleja, en la práctica sigo considerándola un enfoque híbrido entre POO, ECS y FSM. Personalmente me ofrece un equilibrio muy interesante entre rendimiento, organización, flexibilidad y facilidad de mantenimiento, sin la complejidad que suelen introducir las implementaciones más puras.

Como ocurre con cualquier arquitectura, no existe una solución única para todos los proyectos. Este es simplemente el enfoque que mejor se adapta a mi forma de desarrollar videojuegos y el que llevo utilizando con muy buenos resultados en mis proyectos.

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