Introducción
Las Máquinas de Estados Finite (FSM, por sus siglas en inglés) son una herramienta fundamental en la programación de comportamientos de IA en videojuegos. Permiten modelar el comportamiento de un personaje o sistema en términos de estados y transiciones, facilitando la toma de decisiones y la gestión de acciones complejas.
Conceptos Clave
- Estado: Representa una condición o situación específica en la que se encuentra el sistema o personaje.
- Transición: Es el cambio de un estado a otro, generalmente desencadenado por un evento o condición.
- Evento: Una acción o condición que provoca una transición entre estados.
- Acción: Comportamiento o actividad que se realiza en un estado específico o durante una transición.
Ejemplo de FSM
Consideremos un NPC (Non-Playable Character) en un juego de aventuras que puede estar en uno de los siguientes estados:
- Patrullando
- Persiguiendo
- Atacando
- Huyendo
Diagrama de Estados
[Patrullando] --(ve al jugador)--> [Persiguiendo] [Persiguiendo] --(alcanza al jugador)--> [Atacando] [Atacando] --(jugador huye)--> [Persiguiendo] [Persiguiendo] --(jugador se escapa)--> [Patrullando] [Atacando] --(vida baja)--> [Huyendo] [Huyendo] --(seguro)--> [Patrullando]
Tabla de Transiciones
Estado Actual | Evento | Estado Siguiente | Acción |
---|---|---|---|
Patrullando | Ve al jugador | Persiguiendo | Comenzar persecución |
Persiguiendo | Alcanza al jugador | Atacando | Iniciar ataque |
Atacando | Jugador huye | Persiguiendo | Perseguir jugador |
Persiguiendo | Jugador se escapa | Patrullando | Reanudar patrulla |
Atacando | Vida baja | Huyendo | Buscar refugio |
Huyendo | Seguro | Patrullando | Reanudar patrulla |
Implementación en Código
A continuación, se presenta un ejemplo de implementación de una FSM en Python para el NPC descrito anteriormente.
class State: def __init__(self, name): self.name = name def on_event(self, event): pass class Patrolling(State): def __init__(self): super().__init__("Patrullando") def on_event(self, event): if event == "ve_al_jugador": return Chasing() return self class Chasing(State): def __init__(self): super().__init__("Persiguiendo") def on_event(self, event): if event == "alcanza_al_jugador": return Attacking() elif event == "jugador_se_escapa": return Patrolling() return self class Attacking(State): def __init__(self): super().__init__("Atacando") def on_event(self, event): if event == "jugador_huye": return Chasing() elif event == "vida_baja": return Fleeing() return self class Fleeing(State): def __init__(self): super().__init__("Huyendo") def on_event(self, event): if event == "seguro": return Patrolling() return self class NPC: def __init__(self): self.state = Patrolling() def on_event(self, event): self.state = self.state.on_event(event) def __str__(self): return self.state.name # Ejemplo de uso npc = NPC() print(npc) # Patrullando npc.on_event("ve_al_jugador") print(npc) # Persiguiendo npc.on_event("alcanza_al_jugador") print(npc) # Atacando npc.on_event("vida_baja") print(npc) # Huyendo npc.on_event("seguro") print(npc) # Patrullando
Explicación del Código
- Clase
State
: Clase base para todos los estados. Cada estado hereda de esta clase y redefine el métodoon_event
para manejar las transiciones específicas. - Clases de Estados:
Patrolling
,Chasing
,Attacking
, yFleeing
son clases que representan los diferentes estados del NPC. Cada una redefine el métodoon_event
para manejar las transiciones. - Clase
NPC
: Representa al NPC y mantiene su estado actual. El métodoon_event
permite cambiar el estado del NPC basado en eventos. - Ejemplo de Uso: Se crea una instancia de
NPC
y se simulan eventos para mostrar cómo cambia el estado del NPC.
Ejercicio Práctico
Ejercicio 1: Añadir un Nuevo Estado
Añade un nuevo estado llamado "Escondido" que se activa cuando el NPC está huyendo y encuentra un escondite. El NPC debe permanecer en el estado "Escondido" hasta que el jugador se aleje.
Solución
- Define la nueva clase
Hiding
que hereda deState
. - Modifica la clase
Fleeing
para que pueda transicionar al estadoHiding
. - Modifica la clase
Hiding
para que pueda transicionar de vuelta aPatrolling
cuando el jugador se aleje.
class Hiding(State): def __init__(self): super().__init__("Escondido") def on_event(self, event): if event == "jugador_se_aleja": return Patrolling() return self class Fleeing(State): def __init__(self): super().__init__("Huyendo") def on_event(self, event): if event == "seguro": return Patrolling() elif event == "encuentra_escondite": return Hiding() return self # Ejemplo de uso npc = NPC() print(npc) # Patrullando npc.on_event("ve_al_jugador") print(npc) # Persiguiendo npc.on_event("alcanza_al_jugador") print(npc) # Atacando npc.on_event("vida_baja") print(npc) # Huyendo npc.on_event("encuentra_escondite") print(npc) # Escondido npc.on_event("jugador_se_aleja") print(npc) # Patrullando
Conclusión
Las Máquinas de Estados Finite son una herramienta poderosa y flexible para modelar comportamientos en videojuegos. Permiten gestionar de manera clara y estructurada los diferentes estados y transiciones de un personaje o sistema, facilitando la implementación y el mantenimiento del código. En el siguiente tema, exploraremos los Árboles de Decisión, otra técnica útil para la toma de decisiones en IA para videojuegos.
IA para Videojuegos
Módulo 1: Introducción a la IA en Videojuegos
- Historia y Evolución de la IA en Videojuegos
- Conceptos Básicos de IA
- Herramientas y Lenguajes de Programación
Módulo 2: Navegación en Videojuegos
- Algoritmos de Búsqueda de Caminos
- Implementación de A*
- Navegación con NavMesh
- Evitación de Obstáculos
Módulo 3: Toma de Decisiones
Módulo 4: Aprendizaje Automático
- Introducción al Aprendizaje Automático
- Redes Neuronales en Videojuegos
- Aprendizaje por Refuerzo
- Implementación de un Agente de Aprendizaje
Módulo 5: Integración y Optimización
Módulo 6: Proyectos Prácticos
- Proyecto 1: Implementación de Navegación Básica
- Proyecto 2: Creación de un NPC con Toma de Decisiones
- Proyecto 3: Desarrollo de un Agente con Aprendizaje Automático