Sin categoría

Añade la bola al juego, y lógica para el procesamiento de rebotes.

Share on TwitterShare via email


Esta entrada pertenece a ActionScript 3 – Guía para Principiantes.

Resultado al final del capítulo (Click sobre Flash para jugar; Controles: w, s, flecha arriba, flecha abajo):

La clase Bola

Algo fundamental para que nuestro juego tenga algo de sentido es una bola que rebote de pong en pong. Breve recordatorio (y último detallado) de los pasos a seguir a la hora de crear una nueva clase que tenga una representación gráfica:


1) Creación de la clase ActionScript: Con nuestro proyecto Pong abierto en FlashDevelop, click derecho en la carpeta pong -> Add… -> New Class… -> Bola.as. Y para empezar, escribimos el siguiente código en el archivo:

package mi.pong
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;

/**
* ...
* @author ASL
*/
public class Bola extends MovieClip
{
private var vx:Number = 5;
private var vy:Number = 0;
private var max_velocidad:Number = 2;

private var stageRef:Stage;

public function Bola(stage:Stage)
{
stageRef = stage;

addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
iniciaPosicion();
}

public function iniciaPosicion()
{
x = stageRef.stageWidth / 2;
y = stageRef.stageHeight / 2;
}

public function loop(e:Event)
{
x += vx;
y += vy;

if (y < 0)
{
y = 0;
vy = -vy;
}
else if (y > stageRef.stageHeight)
{
y = stageRef.stageHeight;
vy = -vy;
}

if (x < 0)
{
iniciaPosicion();
vx = 5;
vy = 0;
}
else if (x > stageRef.stageWidth)
{
iniciaPosicion();
vx = -5;
vy = 0;
}
}

}

}

Espero que no resulte demasiado extraño al lector el código escrito para la clase Bola. Tiene bastantes puntos comunes con el código de la clase Pong. Al igual que los pongs, la bola también tiene una velocidad, aunque esta vez formada por dos componentes (ya que puede moverse hacia todas partes), la del eje x “vx” y la del eje y “vy“. También una velocidad máxima “max_velocidad“, que utilizaremos en el futuro para “calibrar” su velocidad.

El último bloque de la función loop (que es la función que se ejecuta cada vez que comienza un nuevo frame) controla que la bola no salga de los límites del eje x de la película, devolviendo a ésta al centro del campo.


2) Creación del símbolo Flash: En la ventana Flash -> Insertar -> Nuevo símbolo… y utilizamos las siguientes opciones:

y para el símbolo dibujamos un simple círculo blanco (ya habrá tiempo para mejorar la apariencia de nuestro juego) con las propiedades de la imagen:

Para añadir nuestra bola al juego añadimos lo siguiente en la función Main:

...
var bola:Bola = new Bola(stage);
addChild(bola);
...

Empiezo a ir un poco rápido porque entiendo que después de todo el rollo soltado en capítulos anteriores, el lector entiende más o menos todo lo que estamos haciendo. Si queda cualquier duda, siempre puedes preguntarla en los comentarios.

Bien, si ejecutamos nuestro Flash veremos nuestra bola moviéndose de un lado otro sin mucho sentido. Ahora, lo que necesitamos, es que colisione con los pongs.

Detección de colisiones

En el problema de las colisiones entre objetos es uno de los problemas tradicionales en la programación de cualquier tipo de videojuego. Son muchas las maneras en las que puede ser abordado y resuelto, y en esta guía he optado por una en particular, que para este caso y desde mi punto de vista, es la más sencillo y adecuado.

La técnica consiste en definir un área, dentro del objeto, que sea “capaz de colisionar”. Es decir, que aunque gráficamente dos objetos estén superpuestos, sólo se produzca colisión si sus áreas de colisión están superpuestas.

Las colisiones, de manera gráfica (la zona más oscura representa la zona de colisión de cada objeto):

En la primera, obviamente, no hay colisión. En la segunda, la bola está sobre el gráfico que representa el pong, pero no sobre su zona de colisión. En la última, sendas zonas de colisiones se superponen, produciéndose el choque.

¿Y cómo vamos a representar esta zona de colisiones? Pues, saliéndonos un poco (muy poco, ¿eh?) de aquello que dijimos de que “todo aquello que pueda hacerse desde ActionScript será hecho desde ActionScript”.

Nuestra zona de colisiones va a ser un nuevo símbolo al que vamos a llamar “HitBox” cuyo único contenido va a ser un cuadrado sin borde y de un color semitransparente. Este símbolo no va a estar asociado a ninguna clase ActionScript.


Ahora necesitamos definar la zona de colisión en los símbolos para la bola y el pong.

1) En la ventana de Biblioteca (Ctrl+L), click derecho en el símbolo Pong -> Edición… Crea una nueva capa llamada hitBox y selecciónala. Ahora arrastra desde la biblioteca un símbolo “HitBox” hasta el centro del Pong.

2) Con la herramienta de transformación libre (Q) ajustamos el cuadrado a la zona de colisión buscada.

3) Nombramos a la instancia del símbolo como “hitBox”. Este paso es muy importante, porque será el que nos dé acceso a la zona de colisión desde el código ActionScript.

Seguimos el mismo proceso para la bola.

¿Cómo detecto colisiones en ActionScript?
object1.hitTestObject(object2)

Que devuelve true si los objetos object1 y object2 han colisionado.

Vamos a pensar un poco la lógica que queremos detras de nuestras colisiones: De momento, sólo tenemos un objeto que puede colisionar: la bola, y dos objetos sobre los que colisionar, los pongs. Entonces, sólo necesitamos que la bola sepa sobre que objetos puede colisionar. Esto lo vamos a conseguir pasándole un Array (una “lista”) con ambos pongs, en la función Main, por supuesto. Nuestra función tendrá este aspecto:

  public function Main()
{
key = new KeyObject(stage);
var colisionadores:Array = new Array();

var miPong1:Pong = new Pong(stage, 0, key);
addChild(miPong1);
colisionadores.push(miPong1);

var miPong2:Pong = new Pong(stage, 1, key);
addChild(miPong2);
colisionadores.push(miPong2);

var bola:Bola = new Bola(stage, colisionadores);
addChild(bola);
}

- colisionadores.push(miPong1); Con la función push añadimos un elemento al Array.

En verdad, estamos repitiendo código, y podemos agrupar la creación de pongs en un bucle:

  public function Main()
{
key = new KeyObject(stage);
var colisionadores:Array = new Array();

for (var i:uint; i < 2; i++)
{
var miPong:Pong = new Pong(stage, i, key);
addChild(miPong);
colisionadores.push(miPong);
}

var bola:Bola = new Bola(stage, colisionadores);
addChild(bola);
}

Ahora debemos modificar la clase Bola para que procesa las colisiones. Añadimos un atributo para guardar la lista de colisionadores:

private var colisionadores:Array;
...
public function Bola(stage:Stage, lista_colisiones:Array)
{
stageRef = stage;
colisionadores = lista_colisiones;
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
iniciaPosicion();
}
...

Y el procesamiento de colisiones en la función loop:

public function loop(e:Event)
{
for (var i:uint = 0; i < colisionadores.length; i++)
{
if (hitBox.hitTestObject(colisionadores[i].hitBox))
{
 vx = -vx;
 vy = ((y - colisionadores[i].y) / colisionadores[i].width*2) * max_velocidad;
}
}

        x += vx;
y += vy;
        ...

Y aquí entra en juego el nombre de instancia “hitBox”, que fue cómo nombramos a nuestro cuadradito semitransparente. Nombrando la instancia como hitBox conseguimos tener un nuevo atributo en la clase correspondiente que representa nuestra zona de colisión. Por eso realizamos el test sobre ellas.

En hitBox.hitTestObject(colisionadores[i].hitBox) ,el primer “hitBox” está haciendo referencia a la zona de colisión de la bola, y el segundo, al del colisionador, en este caso, cualquiera de los pongs.

Si se produce una colisión, cambiamos las componentes de velocidad de la bola.

Toques finales

Ya podríamos ejecutar nuestro juego pong y sería completamente funcional. Pero vamos a añadir un par de detalles para darle algo de vistosidad:

1) Seleccionar un color totalmente transparante (con Alfa a 0%) para el símbolo HitBox y evitar que aparezca en pantalla.

2) Elegir un color verde para el fondo de la película (puedes hacerlo desde Propiedades del Documento).

3) Ajustar la velocidad de la película a 30 FPS (con el documento seleccionado, en la ventana de propiedades, o en la línea de tiempo). Esta velocidad dará una mejor sensación de fluidez.

4) Y cómo extra, he añadido en una nueva capa una sombra para el Pong, copiando la forma del pong y desplazándola ligeramente, borrando el contorno y dándole un color grisáceo semitransparente.

Hasta aquí el desarrollo de nuestro Pong Básico.

En el siguiente capítulo encontrarás los archivos fuente del proyecto.

Anterior Índice Siguiente
Share on TwitterShare via email

Otras entradas que podrían interesarte

Tags: ,

5 comentarios

  1. jorge 30/12/2010 at 00:05 | Permalink

    Angel muchisimas gracias por tus tutoriales de ActionScript(Flash),he aprendido mogollon y espero que sigas subiendo algunos tutos mas.
    Eres grande!!

  2. juan 30/08/2011 at 06:45 | Permalink

    bueno pues dejaremos bofetadas, no sabras arreglar ordenadoes pero mola como programas.
    he seguido tu ejemplo y ahora estoy tratando de modificarlo para hacer un pong un tanto distinto.
    La bola en lugar de rebotar se queda agarrada al pong y el jugador iene que pulsar un boton para soltarla.
    El caso es que me pierdo un poco para eso
    he creado una variable en bola:
    1 la pelota se mueve
    0 la pelota esta quieta
    2 la pelota tiene que salir

    cuando la pelota se crea está en 1 cuando toca un jugador pasa a 0 y se queda quieta, eso va bien, pero estoy tratando que ahora el jugador al pulsar un boton llame a una funcion en bola que ponga el estado a 1 de nuevo y entonce se vuelve a mover.

    Podrias echarme una mano?

    • Ángel Serrano 30/08/2011 at 11:17 | Permalink

      Hola,

      Lo primero que deberías hacer es añadir una nueva tecla a cada uno de los pongs, y que sea la que inicia la acción de reenviar la bola al campo (Aquí se explicaba el funcionamiento del teclado: http://www.metafisicainformatica.com/2010/11/20/3-i-controlando-el-pong-desde-teclado/ deberías añadir un nuevo atributo para designar a la tecla.)

      Quizá los estados para la bola que planteas podrían ser:
      0 -> la pelota se mueven normalmente
      1 -> la bola está pegada al jugador 1
      2 -> la bola está pegada al jugador 2

      Con estos estados, seguramente lo más rápido (aunque no sé si lo más limpio) sería modificar el método loop de la bola tal que:

      public function loop(e:Event)
      {
      if ( estadoBola == 0 ){
      x += vx;
      y += vy;
      }
      else if ( estadoBola == 1 ){
      y = miPong1.y;
      }
      else if (estadoBola == 2 ){
      y = miPong2.y;
      }

      Así, la bola se movería con el pong asociado. Ten en cuenta que en el código actual la clase Bola no tiene acceso a los pongs, así que deberías pasárselos de alguna manera.

      Espero que te sirva de ayuda, gracias por seguir el tutorial!

  3. joako 09/03/2012 at 17:36 | Permalink

    oe cuando ya tengo todo echo lo pruebo y me dice acceso a una propiedad hitBox no definida

Un Trackback

  1. [...] Detección de colisiones La clase Bola. Detección de colisiones. ¿Cómo detecto colisiones en ActionScript?. Toques finales. [...]

Dejar un comentario

Cada comentario que dejas es una bofetada a uno de mis familiares o amigos. Suscribirte al RSS, ya ni te cuento. (¿Por qué?)

Tu email nunca será publicado ni compartido.