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) # PatrullandoExplicación del Código
- Clase
State: Clase base para todos los estados. Cada estado hereda de esta clase y redefine el métodoon_eventpara manejar las transiciones específicas. - Clases de Estados:
Patrolling,Chasing,Attacking, yFleeingson clases que representan los diferentes estados del NPC. Cada una redefine el métodoon_eventpara manejar las transiciones. - Clase
NPC: Representa al NPC y mantiene su estado actual. El métodoon_eventpermite cambiar el estado del NPC basado en eventos. - Ejemplo de Uso: Se crea una instancia de
NPCy 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
Hidingque hereda deState. - Modifica la clase
Fleeingpara que pueda transicionar al estadoHiding. - Modifica la clase
Hidingpara que pueda transicionar de vuelta aPatrollingcuando 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) # PatrullandoConclusió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
