sábado, 9 de junio de 2012

Construcción de un Juego de Pong en Flash con AS3 (parte 2)


Este día continuo con la explicación de este pequeño juego hecho en flash con AS3 y lo que básicamente voy a mostrar es el control de choques o detección de colisiones, este proceso es sencillo y básico al desarrollar cualquier proyecto flash game y bueno en cualquier otro programa que haga desarrollo de juegos.

Dentro de mi programa principal esta la función muevePelota la cual es la encargada del movimiento de la pelota sobre el escenario, dentro de esta debemos hacer uso del método hitTestObjetc que es la encargada de la detección de colisión con el objeto que se le manda como paramento que en este caso es la paleta_mc, nuestro fragmento de código sería el siguiente:
//controla el choque contra la paleta
if(pelota_mc.hitTestObject(paleta_mc))
{
 yDireccion *= -1;
 //pelota_mc.y = paleta_mc.y - pelota_mc.height - paleta_mc.height/2;
 pelota_mc.y  -= pelota_mc.height - paleta_mc.height/2;
} 


El jugador debe de responder con la paleta y no debe dejar pasar la pelota como es un típico juego de Pong, si el jugador no puede responder o contestar se debe de resetear la posición de la pelota para que continúe el juego así que se modifica el código que se tenía en la parte 1 y lo que hacemos es controlar el choque de la pelota contra el fondo del escenario. 
if(pelota_mc.y <=0)
{
 yDireccion *= -1;
}
else if(pelota_mc.y >= stage.stageHeight - pelota_mc.height)
{
 resetPosicionPelota();
 //yDireccion *= -1;
}


Lo que hacemos ahora será crear la función resetPosicionPelota() , esta función la ubicáremos en la parte superior de nuestro código debajo de la definición de variables. 
//funcion que reinicia la posicion de la bola
function resetPosicionPelota():void{
 xDireccion = 10;
 yDireccion = -10;
 pelota_mc.x = paleta_mc.x + paleta_mc.width/2 - pelota_mc.width/2;
 pelota_mc.y = paleta_mc.y - pelota_mc.height - paleta_mc.height/2;
}




Primero debemos restablecer las variables de dirección y acomodamos el siguiente saque de la pelota desde el centro de la paleta, ubicando la pelota en medio de la paleta y del lado superior.

Calculo del Angulo de rebote

Por el momento solo estamos armando el proyecto pero ya estamos programando la jugabilidad que va a tener; un juego sin retos que cumplir no sería divertido, por lo cual debemos de hacer más real el movimiento de la pelota a las reacciones de colisión con la paleta.
Dentro de la función muevePelota, ya se ha programado las reacciones de colisión y dentro de ella es donde programaremos el control del ángulo de rebote:


//controla el choque contra la paleta
if(pelota_mc.hitTestObject(paleta_mc))
{
 yDireccion *= -1;
 pelota_mc.y = paleta_mc.y - pelota_mc.height - paleta_mc.height/2;
 //-------------------------------------------------------------------------------
 //control del angulo de rebote de la pelota
 verificaPosicionChoque(paleta_mc);
 //--------------------------------------------------------------------------------
} 


La función que verifica la posición de choque de la pelota respecto a la paleta la escribimos en la parte inicial de nuestro programa:

/-------------------------------control de angulo de rebote---------------------
function verificaPosicionChoque(paleta:MovieClip):void{
 var porcentajeGolpe:Number // variable de calculo de golpe en porcentaje respecto a la pelota
 var posicionPelota:Number = pelota_mc.x - paleta.x;//posicion de la pelota respecto a la paleta
 
 porcentajeGolpe = (posicionPelota /( paleta.width  - pelota_mc.width)) - 0.5;//0.5 para obtener valor positivo
 
 xDireccion = porcentajeGolpe * 20;
 yDireccion *= 1.05;
}


Creamos dos variables una que indica el porcentaje de golpe esto se refiere al incremento de velocidad que tendrá la pelota al chocar con algún lugar de la paleta especifico, la variable posicionPelota lo que hace es capturar en tiempo real la posición donde choca la pelota respecto a la paleta claro esta posición es la que mandamos constantemente desde la función muevePelota, y este verificador capta esa posición.

Básicamente para comprender mejor esto, sería así:


La paleta ejerce también una fuerza con la cual la pelota gana cierta velocidad, esta distribución de fuerza será relativa a la posición donde golpee la pelota a la paleta, es por eso que se necesita captar la posición de la pelota respecto a la paleta dentro de la función muevePelota, lo interesante de esto es que también modificamos la dirección de la pelota modificando las variables de dirección x e y según el porcentaje en el caso de x y en el caso de la variable y haciendo una multiplicación por 1.05 que le da un toque realista al movimiento de la pelota.

Es momento de ubicar al adversario en el escenario, de la biblioteca sacamos una paleta y la acomodamos en la capa paletas, y le damos de nombre de instancia enemigo_mc. Ahora debemos de programar la inteligencia artificial de este objeto en el escenario, primero habilitamos su listener para eso vamos a la función iniciaJuego y llamamos a su listener  así:
enemigo_mc.addEventListener(Event.ENTER_FRAME, mueveEnemigo);

Luego debemos de programar la función mueveEnemigo que es la base de la IA que tendrá el objeto enemigo.
//--------------------------control del movimiento del Enemigo--------
function mueveEnemigo(event:Event):void{
 //var objetivo del enemigo
 var enemigoTargetX:Number;
 
 enemigoTargetX = pelota_mc.x - enemigo_mc.width/2;
 
 if(enemigoTargetX <= 0)
 {
  enemigoTargetX = 0;
 }
 else if(enemigoTargetX >= stage.stageWidth - enemigo_mc.width)
 {
  enemigoTargetX = stage.stageWidth - enemigo_mc.width;
 }
 enemigo_mc.x += (enemigoTargetX - enemigo_mc.x)/4;
}


La variable enemigoTargetX  es la que se encarga de seguir al objeto pelota respecto al centro de la paleta enemiga por lo que este target u objetivo es el que controla la IA, el enemigo al igual que la paleta que controlamos se mueve en el eje X por lo que se controla básicamente ese movimiento respecto al escenario.

En la función muevePelota  debemos de establecer la detección de colisión que también debe tener el enemigo mediante estas sentencias:
if(pelota_mc.hitTestObject(enemigo_mc))
 {
  yDireccion *= -1;
  pelota_mc.y = enemigo_mc.y + enemigo_mc.height + pelota_mc.height/2;
  verificaPosicionChoque(enemigo_mc);
 }



Dentro de esta sentencia de control se encuentra nuestra función verificadora de choques por ultimo debemos de volver a resetear la posición de la pelota si es que el enemigo falla y deja pasar la pelota, para eso modificamos las sentencias siguientes.
if(pelota_mc.y <=0)
 {
  //yDireccion *= -1;
  resetPosicionPelota();
  
 }
Quitamos la reacción de yDireccion y solamente debemos de resetear la posición de la pelota; ahora debemos de probar el programa y lo que obtendremos será:
 


Ya tenemos casi listo nuestro proyecto lo que nos falta serian solo algunos detalles, añadimos una capa nueva la que llamamos score, lo que hacemos es crear un nuevo símbolo llamado mcScore,  este mc tiene dos capas una capa superior contiene las acciones y la capa inferior llevara otro mc que será el slide que tendrá los movimientos para mostrar el resultado, este mc lo llamamos mcElementos  básicamente este tiene dos elementos de texto y le daremos de nombre en el panel de propiedades player_txt y enemigo_txt . Volviendo a nuestro mcScore trabajamos el movimiento que tendrá el slide para mostrar el resultado que será de arriba abajo, la disposición de elementos seria este:

 
El movimiento que se le da es una interpolación de movimiento clásica los primeros 15 frames mueven el mc de abajo a arriba y los últimos 15 frames llevan el mc de arriba/abajo. Tomando en cuenta que nuestro proyecto correrá a 24 fps. Esta cantidad de cuadros que manejamos puede ser modificada fácilmente.

Tenemos que darle nombre de instancia en el panel de propiedades antes de realizar el cambio de movimiento sobre los objetos del escenario en la escena principal le damos nombre de score_mc  y dentro de este clip le damos nombre de instancia a mcElementos que es el mc que hace el movimiento de arriba/abajo; este mc tiene nombre de instancia slide_mc.

Ahora debemos de programar; inicializamos las variables score tanto del player como del enemigo:
//definicion de variables Score
var playerScore:Number;
var enemigoScore:Number;


Y dentro de la función iniciaJuego, inicializamos esas variables: 
//inicia variables Score
 playerScore = 0;
 enemigoScore =0;


Y dentro de la función muevePelota, las sentencias de control que controlan el movimiento de la pelota en la recta “y”  tenemos que incrementar el resultado tanto de el enemigo si se trata de el lado inferior y de incrementar el puntaje del jugador si la pelota pasa por el lado superior, además tenemos que crear una función llamada showScore debajo de la función que verifica la posición de choque de la pelota.

//-------------------------------muestra Resultado del partido-----------------------------------
function muestraScore():void{
 score_mc.slide_mc.player_txt.text = "Player : " + playerScore;
 score_mc.slide_mc.enemigo_txt.text = "Enemigo : " + enemigoScore;
 
 score_mc.gotoAndPlay(2);
}

Los demás detalles que deberá de tener nuestro juego se refieren a la instanciación de objetos como el sonido, que es crear una variable de tipo sound que se añade a la biblioteca y se la reproduce al momento de producirse una colisión tanto de la paleta como de la pared. Por último nuestro proyecto final será este: