Bug (I): La Bola loca

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


Bug (I): La bola loca

Los errores imprevistos (o bugs) son algo bastante común en la programación, y que suelen aparecer en la ejecución continuada de nuestros programas. Por mucho que se planee una implementación de código, siempre acaba apareciendo una situación inesperada que rompe nuestro preciado código. No pasa nada. Si aparece un bug se soluciona, y a otra cosa.


En este caso, nosotros encontramos un error si intentamos golpear la pelota con la partes puntiagudas (los extremos) del pong. No siempre sucede, pero la mayoría de las veces la bola empieza a rebotar dentro del pong. Queda atrapada.


En código, el problema viene dado porque la bola rebota continuadas veces en poco tiempo, cambiando su dirección de izquierda a derecha (y viceversa) una y otra vez sin llegar a salir del área de colisión del pong.


La solución que propongo es añadir un Timer a la bola. Un reloj que, tras la colisión, espere un tiempo para volver a comprobar si hay colisiones, y así dar tiempo a la bola para abandonar la zona de colisiones del pong.


En código, añadimos estos atributos a la clase Bola:


  // Para evitar múltiples colisiones
private var colisionado:Boolean = false;
private var timer:Timer = new Timer(100);

Añadimos la inicialización del timer al constructor:


  public function Bola(stage:Stage) 
{
stageRef = stage;
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
iniciaPosicion();
timer.addEventListener(TimerEvent.TIMER, colisionTime, false, 0, true);
timer.stop();
}

Lo que decimos con este código, es que cada vez que se cumpla el tiempo especificado en el constructor del Timer se ejecute la función colisionTime. Además, lo detenemos con timer.stop(), porque de momento no queremos que corra. El código de colisionTime es el siguiente:


  public function colisionTime(e:TimerEvent)
{
timer.stop();
colisionado = false;
}

Es decir, pasado el tiempo, indicamos que la bola "ha dejado de colisionar". Pero nos falta, entonces, ver cuándo colisionado cambia a true. Este cambio sucede en la función colisiona:


  public function colisiona(objeto:IColisionable):void
{
if (!colisionado)
{
var vel_x:Number = Math.abs(vx);
if (vel_x < max_velocidad)
{
vel_x += acc;
}

if (vx > 0)
{
vx = -vel_x;
}
else
{
vx = vel_x;
}
vy = ((y - objeto.getY()) / objeto.getHeight() * 2) * vel_x;

colisionado = true;
timer.start();
}
}

Si no acaba de colisionar, dejamos que se produzcan las modificaciones propias de la colisión. Después ponemos colisionado a "true" e iniciamos el reloj, que, pasado el periodo marcado, volverá a dejar la bola activa para colisiones.


Sin embargo, si la bola acabara de colisionar, la función no se ejecutaría.


Si soy sincero, la solución que he encontrado no me acaba de convencer. Funciona, sí, pero quizá algo así debería tener una solución más sencilla. Si alguien tiene una solución mejor, que no dude en proponerla en los comentarios.








Anterior Índice Siguiente