Como ya hemos explicado antes, lo que vamos a intentar hacer es manejar el comportamiento del objeto como una serie de estados relacionados entre sÌ, de manera que la entidad que implementa esa colecciÛn de estados ( conocida como ìm·quina de estadosî ) sea capaz de transitar de un estado a otro. Es decir, tendremos una clase Ball que tiene agregados una serie de objetos ( los estados ) y un gr·fico para representarse a sÌ misma ( el movieclip ). Las m·quinas de estados que vamos a implementar son no jer·rquicas y no concurrentes. Si querÈis leer algo m·s completo sobre m·quinas de estados, pasad por FlashSim orquantum-leaps ( gracias a Jonathan Kaye for the links ). Dado que estamos desarrollando un juego, y que por tanto, la performance debe ser nuestra mayor preocupaciÛn, vamos a intentar simplificar la m·quina de estados lo m·s posible.
Vamos a intentar ilustrarlo con un diagrama UML ( statechart diagram ):
M·quina de estados de la pelota
El universo del juego
Veamos este ˙ltimo diagrama con un poco m·s de detalle, para entender cÛmo funciona la m·quina de estados. Definimos los estados en los que vamos a dividir el comportamiento del juego:
1.- initGame: InicializaciÛn general del juego.
2.- initRound: InicializaciÛn de cada ronda de juego. Se pondr·n a cero los contadores de pelotas explotadas y de tiempo,Ö..
3.- gamePlay: Se est· ejecutando el juego. Las pelotas est·n botando, y el jugador est· intentando explotarlasÖ.
4.- endOfTime: Se ha terminado el tiempo. Chequearemos si se han explotado suficientes pelotasÖ
5.- defeat: No se han explotado suficientes. Hemos perdido.
6.- newChallenge: Hemos explotado suficientes, entonces se nos pregunta si queremos volver a empezar, o nos retiramos. En caso de que queramos volver a empezar, volveremos al estado initRound, y en caso de retirarnos, vamos al estado endOfGame.
7.- endOfGame: El juego ha terminado. Se puede enviar a servidor la informaciÛn sobre la puntuaciÛn, etc.
Una vez comprendida la separaciÛn conceptual en estados, veamos cÛmo funciona la m·quina de estados.
En primer lugar, en cada estado se ejecuta una acciÛn ( initGameAction, initRoundAction,Ö ). Normalmente, una m·quina de estados tiene asignadas tres acciones por estado: una a la entrada en el estado, otra en la ejecuciÛn, y otra a la salida del estado. En nuestro caso, vamos a realizar una implementaciÛn sencilla, en la que sÛlo se ejecutar· una acciÛn por estado. La m·quina de estados no es jer·rquica ni concurrente, por lo que la evaluaciÛn de las transiciones se simplifica mucho.
Por ejemplo, en el estado initRound, se ejecutar· el callback initRoundAction, que se encargar· de la inicializaciÛn de la ronda actual.
Cada una de las flechas representa una transiciÛn. Cada estado tiene asignados un n˙mero de transiciones indeterminado. Esas transiciones son callbacks que devuelven un booleano, de manera que la m·quina de estados se mover· por la transiciÛn que devuelva true. Normalmente, esas transiciones eval˙an flags que son propiedades de la clase. Voy a intentar explicarlo mejor.
La m·quina de estados est· vinculada a un temporizador ( un enterframe de un clip vacÌo, por ejemplo ), de manera que a cada tick de ese temporizador, la m·quina de estados eval˙a todas las transiciones que salen del estado en el que se encuentra, y transitarÈ por la primera que devuelve un true. Por tanto, pasar· a otro estado, ejecutando la acciÛn asignada a dicho estado, y en el siguiente tick evaluar· las transiciones de ese nuevo estado, transitando a su vez por la primera que encuentre que devuelva true.
Esto se entender· mucho mejor con el ejemplo de la pelota. Aunque todavÌa es pronto para ver cÛdigo, recordemos que habÌamos decidido que la pelota no fuera una subclase de MovieClip, sino una entidad m·s compleja, que agregara la m·quina de estados y el clip para su presentaciÛn gr·fica.
Bien, pues cuando instanciamos esa clase y creamos y arrancamos su m·quina de estados, nos encontramos en el primer estado de la misma: initBall. Se ejecutar· la acciÛn correspondiente ( initBallAction ), que se encarga de hacer un attachMovie y de colocar en el stage el correspondiente MovieClip. Una vez hecho esto, ponemos a true un flag de la clase ( por ejemplo isInitFlag ), y a false otro llamado isOutOfBoundsFlag. En cada tick del temporizador se ejecutan las transiciones asignadas al estado initBall ( en este caso sÛlo hay una, que parte de initBall y acaba en moveBall ),. Por tanto, si esa transiciÛn devuelve el valor del flag isInitFlag, devolver· true cuando el clip se haya inicializado y colocado en pantalla, por lo que la m·quina de estados transitar· al estado moveBall.
Ese estado tiene asignadas tres transiciones: una sobre sÌ mismo, otra a outOfBounds, y otra a destroyBall. Respectivamente, esas transiciones evaluar·n tres flags: isOutOfBoundsFlag== false, isOutOfBoundsFlag== true ( sÌ, es el mismo ), y isClickedFlag== true.
Mientras tanto, en la acciÛn de ese estado, primero se mover· la pelota, y luego se chequear· si la pelota est· fuera del stage ( sea por que tiene que rebotar con el suelo, o porque se ha salido por los laterales ). En caso de que asÌ ocurra, el flag isOutOfBoundsFlag se pondr· a true. Por tanto, al evaluarse las transiciones, si la bola no se ha salido del stage, el flag isOutOfBounds ser· igual a false, por lo que la transiciÛn que devolver· true ser· la que se realiza sobre sÌ mismo ( isOutOfBounds== false ), por lo que volver· a entrar en ese estado, ejecutando otra vez la acciÛn moveBallAction, por lo que se volver· a mover la bola, se volver· a chequear si se ha salidoÖ..
En caso de que la bola se hubiera salido, la transiciÛn que devolverÌa true serÌa la que termina en outOfBounds. En ese estado se cambiarÌa el movimiento de la bola ( rebote ) o la posiciÛn ( si se ha salido por un lateral ), y se volverÌa al estado de movimiento.
En caso de que se haya hecho clic en el clip se transitarÌa al estado destroyBall.
En el prÛximo post veremos esto implementado en cÛdigo, pero por ahora es m·s importante entender el concepto subyacente, que es que la propia entidad es la que, chequeando una serie de flags propios, va cambiando su comportamiento. Y ese comportamiento est· encapsulado en una serie de estados, independientes unos de otros.
Hasta pronto...