Source: http://xn--programacindevideojuegos-pmc.com/android/codificar-un-juego-tipo-space-invaders-para-android-parte-6/
Timestamp: 2019-08-20 07:37:19+00:00

Document:
Codificar un juego tipo Space Invaders para Android: Parte 6 – Programación de video juegos
Implementando la clase de Invader
Esta clase como la clase de PlayerShip tendrá un objeto RectF así como un objeto Bitmap para la detección de impactos y para dibujar respectivamente. Implementaremos estas características exactamente de la misma manera. Sin embargo, la clase de Invader tendrá un Bitmap para cada cuadro de animación (brazos arriba y brazos abajo). Veremos en esta clase que tenemos un método getBitmap y otro de getBitmap2. Veremos luego en el método draw de SpaceInvadersView como escojemos cuál llamar en cada cuadro.
Teniendo esto presente, ingresa este código para declarar todos los objetos y variables que la clase de Invader va a necesitar.
RectF rect; Random generator = new Random(); // La nave espacial del jugador va a ser representada por un Bitmap private Bitmap bitmap1; private Bitmap bitmap2; // Qué tan largo y ancho será nuestro Invader private float length; private float height; // X es el extremo a la izquierda del rectángulo que le da forma a nuestro invader private float x; // Y es la coordenada superior private float y; // Esto mantendrá la rapidez de los pixeles por segundo a la que el invader se moverá. private float shipSpeed; public final int LEFT = 1; public final int RIGHT = 2; // Se está moviendo la nave espacial y en qué dirección private int shipMoving = RIGHT; boolean isVisible;
// La nave espacial del jugador va a ser representada por un Bitmap
// Qué tan largo y ancho será nuestro Invader
// X es el extremo a la izquierda del rectángulo que le da forma a nuestro invader
// Esto mantendrá la rapidez de los pixeles por segundo a la que el invader se moverá.
// Se está moviendo la nave espacial y en qué dirección
Lo siguiente, tenemos al constructor de Invader que inicializa a rect como un rectángulo vacío, inicializa length y width basado en la resolución de la pantalla, activa isVisible como true porque queremos ver al invader a menos que haya sido disparado. Fijate como la ubicación de x y y en la pantalla es determinada por la posición de los invaders dentro del ejercito de invaders. Un número de row (fila) y otro de column (columna) son pasados al constructor y son usados junto con un padding (relleno) de un veinticincoavo de la resolución de la pantalla x para determinar ubicación inicial exacta del invader.
Luego en el constructor, inicializamos y adaptamos a dos objetos Bitmap usando los dos archivos de gráficos. Finalmente, establecemos a speed en cuarenta pixeles por segundo. Esto irá aumentando como se vayan acercando los invaders a la Tierra.
public Invader(Context context, int row, int column, int screenX, int screenY) { // Inicializa un RectF vacío rect = new RectF(); length = screenX / 20; height = screenY / 20; isVisible = true; int padding = screenX / 25; x = column * (length + padding); y = row * (length + padding/4); // Inicializa el bitmap bitmap1 = BitmapFactory.decodeResource(context.getResources(), R.drawable.invader1); bitmap2 = BitmapFactory.decodeResource(context.getResources(), R.drawable.invader2); // Ajusta el primer bitmap a un tamaño apropiado para la resolución de la pantalla bitmap1 = Bitmap.createScaledBitmap(bitmap1, (int) (length), (int) (height), false); // Ajusta el segundo bitmap a un tamaño apropiado para la resolución de la pantalla bitmap2 = Bitmap.createScaledBitmap(bitmap2, (int) (length), (int) (height), false); // Qué tan rápido va el invader en pixeles por segundo shipSpeed = 40; }
// Ajusta el primer bitmap a un tamaño apropiado para la resolución de la pantalla
// Ajusta el segundo bitmap a un tamaño apropiado para la resolución de la pantalla
// Qué tan rápido va el invader en pixeles por segundo
Ahora, tenemos un montón de códigos get y set y de métodos de ayuda. Los primeros dos get y set de abajo obtienen y establecen el objeto como invisible y establecen el estado actual de visibilidad. Los siguientes dos get obtienen los dos bitmap y los regresan al código que los llamó. Los siguientes tres, getX, getY y getLength regresan los valores de x, y y length respectivamente. Son usados, como eran usados en PlayerShip para obtener las coordenadas precisas con la cuales disparar una bala. Ingresa los siguientes métodos de get y set.
public void setInvisible(){ isVisible = false; } public boolean getVisibility(){ return isVisible; } public RectF getRect(){ return rect; } public Bitmap getBitmap(){ return bitmap1; } public Bitmap getBitmap2(){ return bitmap2; } public float getX(){ return x; } public float getY(){ return y; } public float getLength(){ return length; }
Y por supuesto, nuestra clase de Invader necesita un método de update. Esto trabaja en exactamente la misma manera como lo hizo para la clase de PlayerShip. Fijate como quiera que no hay código para manejar al invader moviendose para abajo. Veremos este código a continuación. Ingresa el código para el método de update de la clase de Invader.
public void update(long fps){ if(shipMoving == LEFT){ x = x - shipSpeed / fps; } if(shipMoving == RIGHT){ x = x + shipSpeed / fps; } // Actualiza rect el cual es usado para detectar impactos rect.top = y; rect.bottom = y + height; rect.left = x; rect.right = x + length; }
El siguiente método dropDownandReverse (BajateyRegresate) hace exactamente lo que el nombre sugiere. Intercambia LEFT (izquierda) por RIGHT (derecha) y viceversa y luego incrementa la coordenada y de los invaders en height lo cual tiene el efecto de moverlo hacia abajo de la pantalla. Finalmente, la rapidez se incrementa en un 18% al multiplicarlo por 1.18. Ingresa el método dropDownandReverse.
public void dropDownAndReverse(){ if(shipMoving == LEFT){ shipMoving = RIGHT; }else{ shipMoving = LEFT; } y = y + height; shipSpeed = shipSpeed * 1.18f; }
El método takeAim es como una inteligencia artificial para nuestro invader. El primer bloque de código en este método detecta si el objeto Invader está alineado aproximadamente en forma horizontal con el jugador. Si es así, un número aleatorio es generado para producir una probabilidad de 1 entre 150 de regresar true al código que lo llamó. Como veremos pronto en el código que lo llamó, cuando true es regresado, se hace un intento para disparar una bala al llamar a shoot.
Si 1 entre 150 no parece que sea una probabilidad alta para que el disparo se haga, solo considera que este método se llamará hasta sesenta veces por segundo en una o tal vez en dos columnas de invasores que regresen true a la condición inicial de if. Así es que va a haber muchas balas volando cuando corramos este código.
En el segundo bloque de códigos en este método, a todos los invaders se les da una oportunidad de soltar un disparo, no importa si están alineados al jugador o no. Esto está excelente para crear un ambiente hostil y eliminar las guaridas. Como cada uno de los invaders recibe cerca de sesenta oportunidades cada segundo entonces las probabilidades han cambiado a 1 en 2000. Estas son variables muy buenas con las que puedes jugar si quires hacer el juego más dificil o más facil.
public boolean takeAim(float playerShipX, float playerShipLength){ int randomNumber = -1; // Si está cerca del jugador if((playerShipX + playerShipLength > x && playerShipX + playerShipLength < x + length) || (playerShipX > x && playerShipX < x + length)) { // Una probabilidad de 1 en 500 chance para disparar randomNumber = generator.nextInt(150); if(randomNumber == 0) { return true; } } // Si está disparando aleatoriamente (sin estar cerca del jugador) una probabilidad de 1 en 5000 randomNumber = generator.nextInt(2000); if(randomNumber == 0){ return true; } return false; }
// Si está cerca del jugador
// Una probabilidad de 1 en 500 chance para disparar
// Si está disparando aleatoriamente (sin estar cerca del jugador) una probabilidad de 1 en 5000
« Codificar un juego tipo Space Invaders para Android: Parte 5
Codificar un juego tipo Space Invaders para Android: Parte 7 »

References: resolución 
 resolución 
 resolución 
 resolución 
 resolución 
 resolución