Bienvenidos sean a este post, despues de haber visto basicamente que son y para que sirven los hilos de ejecucion (threads) hoy pasaremos a insertar los primeros movimientos en nuestro juego, para ello vamos a poner manos a la obra.
Abramos nuestra app Asteroides y vayamos a nuestra clase VistaJuego para agregar las siguiente lineas al comienzo de nuestra clase:

private ThreadJuego hilo = new ThreadJuego();
private static int PERIODO_PROCESO = 50;
private long ultimoProceso = 0;

En la primera linea crearemos un objeto de la clase ThreadJuego, no se preocupen por ahora ya lo crearemos un poco mas adelante, llamada hilo, luego tenemos una constante llamada PERIODO_PROCESO que sera utilziada para indicar cada cuanto queremos procesar cambios en milisegundos y por ultimo una variable llamada ultimoProceso para almacenar cuando se realizo el ultimo proceso. Ahora procederemos a agregar un nuevo metodo en nuestra clase VistaJuego:

protected void actualizarFisica(){
    long ahora = System.currentTimeMillis();
    if (ultimoProceso + PERIODO_PROCESO > ahora){
        return;
    }
    double retardo = (ahora - ultimoProceso) / PERIODO_PROCESO;
    ultimoProceso = ahora;
    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));
    if (Math.hypot(nIncX,nIncY) <= MAX_VELOCIDAD_NAVE){
        nave.setIncX(nIncX);
        nave.setIncY(nIncY);
    }
    nave.incrementaPos(retardo);
    for(Grafico asteroide: asteroides){
        asteroide.incrementaPos(retardo);
    }
}

En este metodo crearemos la habilidad de poder actualizar los movimientos de nuestros elementos, para ello primero crearemos una variable llamada ahora donde almacenara el tiempo actual en milisegundos, luego por medio de un condicional if, donde si cumple que el ultimoProceso mas el PERIODO_PROCESO es mayor a ahora sale del mismo, nuestra siguiente variable llamada retardo, almacenara el valor del mismo generado por la diferencia entre ahora y el ultimoProceso dividido por PERIODO_PROCESO, luego almacenaremos en ultimoProceso el valor de ahora para la proxima vez, el siguiente bloque se encargara de actualizar la velocidad y la direccion de la nave en base a giroNave y aceleracionNave:

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));

Como pueden ver por medio de estas operaciones, primero seteamos el angulo de direccion de nuestra nave, luego estableceremos los valores de incremento tanto del eje X como del eje Y, en el siguiente condicional si el valor de la hipotenusa de los ejes antes creados es menor o igual de la constante MAX_VELOCIDAD_NAVE seteara el incremento de nuestros ejes X e Y de la nave. La siguiente linea se encarga justamente de actualizar su posicion, por ultimo el bloque for se encargara de actualizar la posicion de los asteroides. Ahora agregaremos la clase faltante al principio para poder solucionar el error y el metodo creado anteriormente sea llamado constantemente, veamos la clase a agregar en VistaJuego:

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

Como pueden ver es bastante simple, mientras sea verdad (true) llamara a nuestro metodo actualizarFisica(), ahora haremos la ultima modificacion para poder probar nuestra app, para ello debemos agregar las siguientes lineas al final del metodo onSizeChanged():

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

Y nuestro metodo quedara de la siguiente forma:

protected void onSizeChanged(int ancho, int alto, int ancho_anter,
                             int alto_anter){
    super.onSizeChanged(ancho,alto,ancho_anter,alto_anter);
    nave.setCenY(alto/2);
    nave.setCenX(ancho/2);
    for(Grafico asteroide: asteroides){
        do {
            asteroide.setCenX((int) (Math.random() * ancho));
            asteroide.setCenY((int) (Math.random() * alto));
        } while(asteroide.distancia(nave) < (ancho+alto)/5);
    }
    ultimoProceso = System.currentTimeMillis();
    hilo.start();
}

Probemos nuestra app y veamos como funciona mediante el siguiente video

Como pueden ver en el video al pulsar jugar podemos ver como nuestros asteroides comienzan a moverse tanto en graficos bitmap como en graficos vectoriales, despues de ver el video podemos decir

BrightZigzagBushbaby-small

Todo muy lindo pero hablemos de un par de inconvenientes, en el video se llega a ver que no tiene una buena performance, el hilo se seguira ejecutando a pesar de estar en segundo plano nuestra app y por ultimo si probaramos nuestra app en un dispositivo movil consumira drasticamente la bateria del mismo pero no se preocupen en proximos posts iremos solucionando todos estos inconvenientes.
En resumen, hoy hemos puesto en practica lo visto en el post anterior, tambien hemos creado la primera rutina para hacer las animaciones de nuestros elementos, tambien hemos como implementarlo, y por fin nuestra app ya va tomando mas forma, espero les haya sido util sigueme en Twitter, Facebook o Google+ para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios