Autómatas y programación de videojuegos - norman-ipn/Evolutivo GitHub Wiki

En ocasiones algunas personas (interesadas en la programación) que han visto funcionar el videojuego de peleas (TFT) me han preguntado acerca del comportamiento de los personajes y como son controlados por el usuario, es decir la forma en que reacciona al ejecutar determinados movimientos en el joystick, como ejemplo, cuando movemos la palanca y oprimimos algún botón, el personaje “camina”, se “agacha”, “salta” o ejecuta un movimiento especial como un “Hurricane kick”.

Pues bien, para eso se recurrió a un autómata finito, sin entrar en detalles estrictos sobre su definición podemos considerarlo de la manera siguiente:

AF = (Q, A, I, FT, F)

Q conjunto finito de estados

A alfabeto finito

I pertenece a Q estado inicial

FT: QxA->Q función de transición

F Estados finales

Para nuestros fines, el personaje es un AF…

AF = (Q, A, I, FT, F)

Q conjunto de estados que tienen asociados una animación y una serie de atributos adicionales, como ejemplo, el estado “Camina” posee una animación donde se puede observar al personaje caminar además de tener asociado el tipo de movimiento que le permite desplazarse en pantalla y que guarda los valores de la posición (hacia arriba, izquierda, derecha, movimiento tipo parabólico etc…).

A Conjunto de símbolos, cada “símbolo” de nuestro alfabeto se considera un evento, como ejemplo cuando movemos el joystick hacia arriba (EV_PU) u oprimimos un botón (EV_BA).

I Este es nuestro estado inicial, que en nuestro caso pudiese tener varios estados iniciales, ¿para qué?, solo para iniciar cada vez con una animación diferente de nuestro personaje.

FT: QxA->Q permanece intacta y nos permitirá realizar el cambio de estado.

F Este estado finalmente, puede ser cuando nuestro personaje fue noqueado ¡K.O.!

Ahora bien, pongamos esto en pseudocódigo, definamos una clase CAF (clase autómata finito). Sus métodos:

DefineEdo(int ID, anim A, int M);

ID=identificador único de estado, A=animación, M=tipo de movimiento

AgregaTransicion(int I, int E, int F);

I=id del estado en cuestion, E=evento que nos permite realizar la transición, F=id del estado al cual cambiamos

EdoInicial(int E) E= inicia el AF en el estado E

EnviaEvento(int E) E = evento enviado al AF, el cual evaluara con la función de transición que nosotros definamos mediante el método AgregaTransicion(int I, int E, int F);

En un ciclo básico de ejecución del videojuego tenemos algo como esto:

Enum EDOS {INTRO1, INTRO2, ENGUARDIA, CAMINA, SALTA, KO};

Enum EVENTOS{ FIN_ANIMACION, JOY_U, JOY _R, JOY _NINGUNO, MINIMA_ENERGIA};

CAF AF; //autómata finito

GESTOR_EVENTOS GE; //gestor de eventos

JOYSTICK JS; //el joystick

RENDER_OBJ R; //objeto que hace render

ANIM A[]; //nuestra gama de animaciones

MOVIMIENTO M[]; //los tipos de movimientos

//Definiendo estados con su animación y tipo de movimiento

AF.DefineEdo(INTRO1, A[0], M[0]);

AF.DefineEdo(INTRO2, A[1], M [0]);

AF.DefineEdo(ENGUARDIA, A[2], M [1]);

AF.DefineEdo(CAMINA, A[3], M [2]);

AF.DefineEdo(SALTA, A[4], M [3]);

AF.DefineEdo(KO, A[5], M [6]);

//Definimos el comportamiento…

AF.AgregaTransicion(INTRO1, FIN_ANIMACION, ENGUARDIA );

AF.AgregaTransicion(INTRO2, FIN_ANIMACION, ENGUARDIA );

AF.AgregaTransicion(ENGUARDIA, JOY_U, SALTA );

AF.AgregaTransicion(SALTA, TOCA_EL_PISO, ENGUARDIA );

AF.AgregaTransicion(ENGUARDIA, JOY _R, CAMINA );

AF.AgregaTransicion(CAMINA, JOY _NINGUNO, ENGUARDIA );

AF.AgregaTransicion(ENGUARDIA, MINIMA_ENERGIA, KO);

While(…)

{

JS.Actualiza();//actualizamos el joystick

// Generamos eventos que dependen del joystic y otros, como ejemplo

// el que controla el nivel de energía del personaje y genera el evento MINIMA_ENERGIA

GE.GeneraEvento(JS,.. );

AF. EnviaEvento( GE.RetEvento() );// enviamos el evento al AF que interpretara la función de transición

//Hacemos un render

R.RenderPersonaje( AF.Animacion(), AF.Posicion() );

}