You are on page 1of 4

Ejercicio paso a paso: Introduciendo movimiento en Asteroides

1. Comienza declarando las siguientes variables en la clase VistaJuego:



// //// THREAD Y TIEMPO //////
// Thread encargado de procesar el juego
private ThreadJuego thread = new ThreadJuego();
// Cada cuanto queremos procesar cambios (ms)
private static int PERIODO_PROCESO = 50;
// Cuando se realiz el ltimo proceso
private long ultimoProceso = 0;
2. La animacin del juego la llevar a cabo el mtodo actualizaFisica() que ser ejecutado a
intervalos regulares definidos por la constante PERIODO_PROCESO. Esta constante ha sido
inicializada a 50 ms. EnultimoProceso se almacena el instante en que se llam por ltima vez
a actualizaFisica().
3. Copia el siguiente mtodo dentro de la clase VistaJuego:
protected void actualizaFisica() {
long ahora = System.currentTimeMillis();
// No hagas nada si el perodo de proceso no se ha cumplido.
if (ultimoProceso + PERIODO_PROCESO > ahora) {
return;
}
// Para una ejecucin en tiempo real calculamos retardo
double retardo = (ahora - ultimoProceso) / PERIODO_PROCESO;
ultimoProceso = ahora; // Para la prxima vez
// Actualizamos velocidad y direccin de la nave a partir de
// giroNave y aceleracionNave (segn la entrada del jugador)
nave.setAngulo((int) (nave.getAngulo() + giroNave * retardo));
double nIncX = nave.getIncX() + aceleracionNave *
Math.cos(Math.toRadians(nave.getAngulo())) * retardo;
double nIncY = nave.getIncY() + aceleracionNave *
Math.sin(Math.toRadians(nave.getAngulo())) * retardo;
// Actualizamos si el mdulo de la velocidad no excede el mximo
if (Math.hypot(nIncX,nIncY) <= MAX_VELOCIDAD_NAVE){
nave.setIncX(nIncX);
nave.setIncY(nIncY);
}
// Actualizamos posiciones X e Y
nave.incrementaPos(retardo);
for (Grafico asteroide : Asteroides) {
asteroide.incrementaPos(retardo);
}
}

Como veremos a continuacin este mtodo ser llamado de forma continua. Como queremos
desplazar los grficos cada PERIODO_PROCESO milisegundos, verificamos si ya ha pasado
este tiempo desde la ltima vez que se ejecut (ultimoProceso).
Como tambin es posible que el sistema est ocupado y no nos haya podido llamar hasta un
tiempo superior a PERIODO_PROCESO, vamos a calcular el factor de retardo en funcin del
tiempo adicional que haya pasado. Si por ejemplo, desde la ltima llamada ha pasado dos
veces PERIODO_PROCESO, la variableretardo ha de valer 2. Lo que significar que los
grficos han de desplazarse el doble que en circunstancias normales. De esta forma
conseguiremos un desplazamiento continuo en tiempo real.
A continuacin, se actualizan las variables que controlan la aceleracin y cambios de direccin
de la nave. Se consiguen por medio de las variables aceleracionNave y giroNave. En el
siguiente captulo modificaremos estas variables para que el jugador pueda pilotar la nave. A
partir de estas variables se obtiene una nueva velocidad de la nave, descompuesta en sus
componentes x e y. Si el mdulo de estos componentes es mayor que la velocidad mxima
permitida, no se actualizar la velocidad.
Finalmente se actualizan las posiciones de todos los grficos (nave y asteroides) a partir de sus
velocidades. Esto se consigue llamando al mtodo incrementaPos() definido en la
clase Grafico.
4. Ahora necesitamos que esta funcin sea llamada continuamente, para lo que utilizaremos
un Thread. Crea la siguiente clase dentro de la clase VistaJuego:

class ThreadJuego extends Thread {
@Override
public void run() {
while (true) {
actualizaFisica();
}
}
}

5. Introduce estas lneas al final del mtodo onSizeChanged():

ultimoProceso = System.currentTimeMillis();
thread.start();

Esto ocasionar que se llame al mtodo run() del hilo de ejecucin. Este mtodo es un bucle
infinito que continuamente llama al actualizaFisica().
6. Ejecuta la aplicacin y observa como el juego cobra vida.

El trabajo con hilos de ejecucin es especialmente delicado. Como veremos en prximos
captulos, este cdigo nos va a ocasionar varios quebraderos de cabeza. Un problema es que
seguir ejecutndose aunque nuestra aplicacin est en segundo plano. Veremos cmo
detener el hilo de ejecucin, cuando estudiemos el ciclo de vida de una actividad. (NOTA: Si
ejecutas el programa en el terminal real y detectas que este funciona ms lentamente, puede
ser buena idea detener la aplicacin). Un segundo problema, aparecer cuando dos hilos de
ejecucin traten de acceder a la misma variable a la vez. Tambin se resolver ms adelante.

Ejercicio paso a paso: Manejo de la nave con el teclado
Veamos cmo podemos utilizar un manejador de eventos de teclado para maniobrar la nave de
Asteroides:
1. Abre el proyecto Asteroides.
2. Inserta este cdigo en la clase VistaJuego.
@Override
public boolean onKeyDown(int codigoTecla, KeyEvent evento) {
super.onKeyDown(codigoTecla, evento);
// Suponemos que vamos a procesar la pulsacin
boolean procesada = true;
switch (codigoTecla) {
case KeyEvent.KEYCODE_DPAD_UP:
aceleracionNave = +PASO_ACELERACION_NAVE;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
giroNave = -PASO_GIRO_NAVE;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
giroNave = +PASO_GIRO_NAVE;
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
ActivaMisil();
break;
default:
// Si estamos aqu, no hay pulsacin que nos interese
procesada = false;
break;
}
return procesada;
}
3. Cada vez que se pulse una tecla se realizar una llamada al
mtodo onKeyDown() con los siguientes parmetros: El primero es un entero que nos
identifica el cdigo de la tecla pulsada. El segundo es de la clase KeyEventy nos permite
obtener informacin adicional sobre el evento, como por ejemplo, cuando se produjo.
Este mtodo ha de devolver un valor booleano, verdadero, si consideramos que la
pulsacin ha sido procesada por nuestro cdigo, y falso, si queremos que otro
manejador de evento siguiente al nuestro reciba la pulsacin.
4. Antes de ponerlo en marcha comenta la llamada a ActivaMisil(), dado que esta
funcin an no est implementada.
5. Verifica si funciona correctamente.
NOTA:Para poder recoger eventos de teclado desde una vista es necesario que esta
tenga el foco y para que esto sea posible verifica que tiene la propiedad focusable="true"

Prctica: Manejo de la nave con el teclado
El ejercicio anterior no funciona de forma satisfactoria. Cuando pulsamos una tecla para
girar la nave se pone a girar pero ya no hay manera de pararla. El manejador de
eventos onKeyDown solo se activa cuando se pulsa una tecla, pero no cuando se suelta.
Trata de escribir el manejador de eventos onKeyUp para que la nave atienda a las
rdenes de forma correcta. Puedes partir del siguiente cdigo:


@Override
public boolean onKeyUp(int codigoTecla, KeyEvent evento) {
super.onKeyUp(codigoTecla, evento);
// Suponemos que vamos a procesar la pulsacin
boolean procesada = true;
...
return procesada;
}

Solucin: Una posible solucin al ejercicio se muestra a continuacin:
@Override
public boolean onKeyUp(int codigoTecla, KeyEvent evento) {
super.onKeyUp(codigoTecla, evento);
// Suponemos que vamos a procesar la pulsacin
boolean procesada = true;
switch (codigoTecla) {
case KeyEvent.KEYCODE_DPAD_UP:
aceleracionNave = 0;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
giroNave = 0;
break;
default:
// Si estamos aqu, no hay pulsacin que nos interese
procesada = false;
break;
}
return procesada;
}

You might also like