La clase VistaJuego

Pasemos a describir la creación de VistaJuego, que como hemos indicado es la responsable de la ejecución el juego. En una primera versión solo se representarán los asteroides de forma estática:

Ejercicio paso a paso: La clase VistaJuego

1.     Crea una nueva clase VistaJuego en el proyecto Asteroides y copia el siguiente código:

public class VistaJuego extends View {
       // //// ASTEROIDES //////
       private List<Grafico> Asteroides; // Vector con los Asteroides
       private int numAsteroides = 5; // Número inicial de asteroides
       private int numFragmentos = 3; // Fragmentos en que se divide
 
       public VistaJuego(Context context, AttributeSet attrs) {
             super(context, attrs);
             Drawable drawableNave, drawableAsteroide, drawableMisil;
             drawableAsteroide =
                  ContextCompat.getDrawable(context, R.drawable.asteroide1);  
                                                                                         R.drawable.asteroide1);
             asteroides = new ArrayList<Grafico>();
             for (int i = 0; i < numAsteroides; i++) {
                    Grafico asteroide = new Grafico(this, drawableAsteroide);
                    asteroide.setIncY(Math.random() * 4 - 2);
                    asteroide.setIncX(Math.random() * 4 - 2);
                    asteroide.setAngulo((int) (Math.random() * 360));
                    asteroide.setRotacion((int) (Math.random() * 8 - 4));
                    asteroides.add(asteroide);
             }
       }
 
       @Override protected void onSizeChanged(int ancho, int alto, 
                                                                   int ancho_anter, intalto_anter) {
             super.onSizeChanged(ancho, alto, ancho_anter, alto_anter);
             // Una vez que conocemos nuestro ancho y alto.
             for (Grafico asteroide: Asteroides) {
                    asteroide.setCenX((int) Math.random()*ancho);
                    asteroide.setCenY((int) Math.random()*alto);
             }
       }
 
       @Override protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
             for (Grafico asteroide: Asteroides) {
                 asteroide.dibujaGrafico(canvas);
             }
       }
}

Como ves se han declarado tres métodos. En el constructor creamos los asteroides e inicializamos su velocidad, ángulo y rotación. Sin embargo, resulta imposible iniciar su posición, dado que no conocemos el alto y ancho de la pantalla. Esta información será conocida cuando se llame a onSizeChanged(). Observa cómo en esta función los asteroides están situados de forma aleatoria. El último método,onDraw(), es el más importante de la clase View, dado que es el responsable de dibujar la vista.

2.     Hemos creado una vista personalizada. No tendría demasiado sentido, pero podrá ser utilizada en cualquier otra aplicación que desarrolles. Visualiza el Layout juego.xml y observa como la nueva vista se integra perfectamente en el entorno de desarrollo.

3.     Registra la actividad Juego en AndroidManifest.xml.

4. Asocia al atributo onClick del botón Jugar del Layout main el método lanzarJuego. Crea el método lanzarJuego() dentro de la clase Asteroides, de forma similar al método lanzarAcercaDe(), pero esta vez arrancando la actividad Juego.

5.    Ejecuta la aplicación. Has de ver cinco asteroides repartidos al azar por la pantalla.

Introduciendo la nave en VistaJuego

El siguiente paso consiste en dibujar la nave que controlará el usuario para destruir los asteroides.

Práctica: Introduciendo la nave en VistaJuego

1. Declara las siguientes variables al comienzo de la clase VistaJuego:

// //// NAVE //////

   private Grafico nave;// Gráfico de la nave

   private int giroNave; // Incremento de dirección

   private float aceleracionNave; // aumento de velocidad
   
   private static final int MAX_VELOCIDAD_NAVE = 20;

   // Incremento estándar de giro y aceleración

   private static final int PASO_GIRO_NAVE = 5;

   private static final float PASO_ACELERACION_NAVE = 0.5f;

Algunas de estas variables serán utilizadas en el siguiente capítulo.

2. En el constructor de la clase instancia la variable drawableNave de forma similar como se ha hecho en drawableAsteroide.

3. Inicializa también en el constructor la variable navede la siguiente forma:

            nave = new Grafico(this, drawableNave);

4. En el método onSiceChange() posiciona la nave justo en el centro de la vista.

5. En el método onDraw() dibuja la nave en el Canvas.

6. Ejecuta la aplicación. La nave ha de aparecer centrada:

7. Si cuando situamos los asteroides, alguno coincide con la posición de la nave, el jugador no tendrá ninguna opción de sobrevivir. Sería más interesante asegurarnos de que al posicionar los asteroides estos se encuentran a una distancia adecuada a la nave, y en caso contrario tratar de obtener otra posición. Para conseguirlo puedes utilizar el siguiente código en sustitución de las dos líneas asteroide.setPosX(…) y asteroide.setPosY(…).

do{

   asteroide.setCenX((int) (Math.random()*ancho));
   asteroide.setCenY((int) (Math.random()*alto));

} while(asteroide.distancia(nave) < (ancho+alto)/5);


NOTA: Ten cuidado donde añades este código.

Ejercicio paso a paso: Evitando que VistaJuego cambie su representación con el dispositivo en horizontal y en vertical

1. Ejecuta la aplicación y cambia de orientación la pantalla del dispositivo. En el emulador se consigue pulsando la tecla Ctrl-F11.

2. Observa cómo cada vez, se reinicializa la vista, regenerando los asteroides. Esto nos impediría jugar de forma adecuada. Para solucionarlo edita AndroidManifet.xml. En la lengüeta Application selecciona la actividad Juego. En los parámetros de la derecha selecciona en Screen orientation: landscape.Observa como en el código XML se ha añadido el siguiente atributo:

    android:screenOrientation="Landscape"

3. Ejecuta de nuevo la aplicación. Observa como la actividad Juego será siempre representada en modo horizontal, de forma independiente a la posición del teléfono.

NOTA: En algunos emuladores, cuando presiones Ctrl-F11 la orientación seguirá cambiando. Se trata de un error de simulación, al no soportar esta configuración. En ese caso, cambia de emulador o pruébalo en un dispositivo real.

 

4. Abre de nuevo las propiedades de la actividad Juego. En Theme selecciona el valor @android:style/Theme.NoTitleBar.Fullscreen. Este tema visualizará la vista ocupando toda la pantalla, sin la barra de notificaciones ni el nombre de la aplicación.

5. Si en Theme pulsas el botón Browse… y seleccionas el botón circular System Resources puedes ver una lista de estilos definidos en el sistema.

NOTA. En algunas instalaciones esta lista puede que no te funcione.

6. Ejecuta la aplicación en un terminal real y verifica el resultado.