Bienvenidos sean a este post, hasta el post anterior estuvimos creando todas las clases, interfaces y componentes que usaremos para nuestros objetos en el juego pero con un error, hoy solucionaremos el mismo.
Para ello vamos a crear una nueva clase que se llamara Transformar, esta clase no solo contendra toda la informacion y ejecutara todas las acciones que son comunes a GameEngine sino que tambien hara un piquitin mas porque no solo contendra el tamaño, la orientacion, la posicion o hacia donde esta orientado sino que tambien se encargara de las colisiones, esto ultimo es muy raro que sea realizado por esta clase pero esto lo haremos para orientarnos mejor rumbo al proximo proyecto.
Antes de continuar les recomiendo bajar este archivo que posee todos los graficos que usaremos en el juego:
Una vez descargado, extraen los archivos en la PC, los seleccionan y presionen Ctrl+C para copiarlos, van al Android Studio, a la carpeta res/drawable, presionan Ctrl+V para pegarlos, les aparecera un nuevo cuadro donde deben seleccionar a drawable (no drawable-v24), presionen Ok, aparecera otro cuadro y vuelven a presionar Ok para finalmente tener todos los elementos dentro del recurso, con esto ya tenemos las imagenes para cada uno de nuestros objetos, retomando este post creamos una nueva clase con los siguientes datos:
- Nombre: Transformar
- Tipo: Class
Con nuestra nueva clase creada, modificaremos el codigo con el siguiente:
package org.example.invasores;
import android.graphics.PointF;
import android.graphics.RectF;
class Transformar {
private int mXClip;
private boolean mPrimeraInvertida = false;
private RectF mColision;
private PointF mPosicion;
private boolean mMirandoDerecha = true;
private boolean mApuntandoArriba = false;
private boolean mApuntandoAbajo = false;
private boolean mApuntandoIzquierda = false;
private boolean mApuntandoDerecha = false;
private float mVelocidad;
private float mObjetoAltura;
private float mObjetoAncho;
private static PointF mTamanoPantalla;
Transformar(float velocidad,
float objetoAncho,
float objetoAltura,
PointF posicionInicial,
PointF tamanoPantalla){
mColision = new RectF();
mVelocidad = velocidad;
mObjetoAltura = objetoAltura;
mObjetoAncho = objetoAncho;
mPosicion = posicionInicial;
mTamanoPantalla = tamanoPantalla;
}
}
Nota: Si verifican las clases en este instante deben estar todas sin error.
En este caso vamos a declarar nuestras variables/objetos, comencemos a detallar cada uno de los mismos:
- mXClip, va a representar la posicion horizontal de la pantalla donde dos bitmaps que representan al fondo se encuentran.
- mPrimeraInvertida, va a decidir cual de los bitmaps que representan al fondo se dibujara primero.
- mColision, sera usada para crear el rectangulo para detectar las colisiones, tal como vinimos haciendo hasta ahora
- mPosicion, la posicion pixel del rincon left-top de un objeto del juego
- mMirandoDerecha, determina si se esta mirando a la derecha o no, esto nos sera util para tomar ciertas determinaciones mas adelante.
- mApuntandoArriba, determina si apunta hacia arriba
- mApuntandoAbajo, determina si apunta hacia abajo
- mApuntandoIzquierda, determina si apunta hacia la izquierda
- mApuntandoDerecha, determina si apunta hacia la derecha
- mVelocidad, determina la velocidad del objeto
- mObjetoAltura, determina cuan alto es el objeto
- mObjetoAncho, determina cuan ancho es el objeto
- mTamanoPantalla, almacena el tamaño de la pantalla
Todos estos datos en mayor o en menor medida los necesitaremos pero el unico que no es realmente necesario es mTamanoPantalla porque no sera utilizado verdaderamente por la clase pero si sera referenciada para unos determinados momentos y por este motivo sera estatico pero esto lo veremos a medida que avancemos, lo siguiente es el constructor cuya unica funcion sera la de asignar los valores que recibimos a cada uno de los explicados anteriormente, para nuestro siguiente paso agregaremos algunos metodos a nuestra clase:
boolean getPrimeraInvertida(){
return mPrimeraInvertida;
}
void flipPrimeraInvertida(){
mPrimeraInvertida = !mPrimeraInvertida;
}
int getXClip(){
return mXClip;
}
void setXClip(int nuevoXClip){
mXClip = nuevoXClip;
}
PointF getTamanoPantalla(){
return mTamanoPantalla;
}
void apuntarArriba(){
mApuntandoArriba = true;
mApuntandoAbajo = false;
}
void apuntarAbajo(){
mApuntandoArriba = false;
mApuntandoAbajo = true;
}
void apuntarIzquierda(){
mApuntandoIzquierda = true;
mApuntandoDerecha = false;
mMirandoDerecha = false;
}
void apuntarDerecha(){
mApuntandoIzquierda = false;
mApuntandoDerecha = true;
mMirandoDerecha = true;
}
boolean apuntandoArriba(){
return mApuntandoArriba;
}
boolean apuntandoAbajo(){
return mApuntandoAbajo;
}
boolean apuntandoIzquierda(){
return mApuntandoIzquierda;
}
boolean apuntandoDerecha(){
return mApuntandoDerecha;
}
El primer metodo solo nos devolvera el valor de mPrimeraInvertida, el segundo solo invierte el valor que posee mPrimeraInvertida porque sera el encargado de hacer la accion de voltear (flip), el tercero devolvera el valor de mXClip, el cuarto metodo recibe un valor y se lo asigna a mXClip, el siguiente metodo sera para obtener el valor de mTamanoPantalla, despues vendran cuatro metodos para indicar hacia donde esta apuntando veamos los detalles:
- apuntarArriba, cambio los valores indicadores de donde apunta para que sea hacia arriba
- apuntarAbajo, idem al anterior pero para abajo
- apuntarIzquierda, idem al anterior pero para la izquierda, observen que setea a mMirandoDerecha como false
- apuntarDerecha, idem al anterior pero lo cambia para la derecha y setea a mMirandoDerecha como true
Los siguientes cuatro metodos se encargan de devolver los valores de mApuntandoArriba, mApuntandoAbajo, mApuntandoIzquierda, mApuntandoDerecha respectivamente, con esto explicado vamos a agregar el siguiente metodo:
void actualizaColision(){
mColision.top = mPosicion.y + (mObjetoAltura / 10);
mColision.left = mPosicion.x + (mObjetoAncho / 10);
mColision.bottom = (mColision.top + mObjetoAltura)
- mObjetoAltura/10;
mColision.right = (mColision.left + mObjetoAncho)
- mObjetoAncho/10;
}
Este metodo se encargara de actualizar a los limites de colisiones, para ello reiniciara los valores de los cuatro parametros del objeto mColision, los primeros valores lo que hace es modificar a top y left, con el producto de la suma del eje X e Y con el valor del 10% de la ancho y altura del objeto todo respectivamente, luego modificaremos a bottom y right, para ello usaremos los valores modificados anteriormente y lo incrementaremos con la altura y ancho y le restaremos otra vez el 10% de la altura y ancho, todo respectivamente, este metodo sera llamado cada vez que actualicemos un frame de nuestro juego, pasemos a agregar los siguientes metodos:
float getObjetoAltura(){
return mObjetoAltura;
}
void pararVertical(){
mApuntandoAbajo = false;
mApuntandoArriba = false;
}
float getVelocidad(){
return mVelocidad;
}
void setPosicion(float horizontal, float vertical){
mPosicion = new PointF(horizontal,vertical);
actualizaColision();
}
PointF getPosicion(){
return mPosicion;
}
PointF getTamano(){
return new PointF((int)mObjetoAltura,
(int)mObjetoAncho);
}
void voltear(){
mMirandoDerecha = !mMirandoDerecha;
}
boolean getMirandoDerecha(){
return mMirandoDerecha;
}
RectF getColision(){
return mColision;
}
El primer metodo devuelve la altura del objeto, el segundo metodo detendra el movimiento de apuntar arriba y abajo, el tercer metodo devuelve a mVelocidad, el cuarto establecera un valor para mPosicion en base a los valores que recibe y llama a actualizaPosicion, el quinto metodo devuelve el valor de mPosicion, el sexto metodo devuelve un valor que puede ser usado para establecer el tamaño del objeto porque devuelve un valor de tipo PointF en base a la altura y el ancho del objeto, el metodo voltear lo unico que hace es invertir el valor de mMirandoDerecha para saber si esta o no mirando a la derecha, el siguiente metodo devuelve el valor de mMirandoDerecha, y el ultimo metodo nos devuelve el valor de mColision, con esto nos falta un solo metodo que es el siguiente:
PointF getPosicionDisparo(float longitudLaser){
PointF mPosicionDisparo = new PointF();
if (mMirandoDerecha){
mPosicionDisparo.x = mPosicion.x
+ (mObjetoAncho / 8f);
} else {
mPosicionDisparo.x = mPosicion.x
+ (mObjetoAncho / 8f) - longitudLaser;
}
mPosicionDisparo.y = mPosicion.y + (mObjetoAltura / 1.28f);
return mPosicionDisparo;
}
Con este metodo obtendremos la posicion desde donde sale el disparo de laser de las naves, primero crearemos el objeto a retornar, luego por medio de un condicional verificamos si esta viendo a la derecha o no, en caso de ser verdadero asigna al valor x del objeto creado anteriormente por medio del valor del eje X de mPosicion mas el valor de la division del ancho del objeto por 8, en caso contrario hace el mismo calculo pero le resta el valor pasado como argumento a este metodo, despues haremos lo mismo pero para el eje Y el cual lo unico que hace es mover la ubicacion del laser un poco mas abajo de la posicion de la nave, por ultimo devolvemos los valores asignado al objeto creado (mPosicionDisparo), con esto ya tenemos completa nuestra clase Transformar, veamos como quedo el codigo hasta ahora:
Transformar.java
package org.example.invasores;
import android.graphics.PointF;
import android.graphics.RectF;
class Transformar {
private int mXClip;
private boolean mPrimeraInvertida = false;
private RectF mColision;
private PointF mPosicion;
private boolean mMirandoDerecha = true;
private boolean mApuntandoArriba = false;
private boolean mApuntandoAbajo = false;
private boolean mApuntandoIzquierda = false;
private boolean mApuntandoDerecha = false;
private float mVelocidad;
private float mObjetoAltura;
private float mObjetoAncho;
private static PointF mTamanoPantalla;
Transformar(float velocidad,
float objetoAncho,
float objetoAltura,
PointF posicionInicial,
PointF tamanoPantalla){
mColision = new RectF();
mVelocidad = velocidad;
mObjetoAltura = objetoAltura;
mObjetoAncho = objetoAncho;
mPosicion = posicionInicial;
mTamanoPantalla = tamanoPantalla;
}
boolean getPrimeraInvertida(){
return mPrimeraInvertida;
}
void flipPrimeraInvertida(){
mPrimeraInvertida = !mPrimeraInvertida;
}
int getXClip(){
return mXClip;
}
void setXClip(int nuevoXClip){
mXClip = nuevoXClip;
}
PointF getTamanoPantalla(){
return mTamanoPantalla;
}
void apuntarArriba(){
mApuntandoArriba = true;
mApuntandoAbajo = false;
}
void apuntarAbajo(){
mApuntandoArriba = false;
mApuntandoAbajo = true;
}
void apuntarIzquierda(){
mApuntandoIzquierda = true;
mApuntandoDerecha = false;
mMirandoDerecha = false;
}
void apuntarDerecha(){
mApuntandoIzquierda = false;
mApuntandoDerecha = true;
mMirandoDerecha = true;
}
boolean apuntandoArriba(){
return mApuntandoArriba;
}
boolean apuntandoAbajo(){
return mApuntandoAbajo;
}
boolean apuntandoIzquierda(){
return mApuntandoIzquierda;
}
boolean apuntandoDerecha(){
return mApuntandoDerecha;
}
void actualizaColision(){
mColision.top = mPosicion.y + (mObjetoAltura / 10);
mColision.left = mPosicion.x + (mObjetoAncho / 10);
mColision.bottom = (mColision.top + mObjetoAltura)
- mObjetoAltura/10;
mColision.right = (mColision.left + mObjetoAncho)
- mObjetoAncho/10;
}
float getObjetoAltura(){
return mObjetoAltura;
}
void pararVertical(){
mApuntandoAbajo = false;
mApuntandoArriba = false;
}
float getVelocidad(){
return mVelocidad;
}
void setPosicion(float horizontal, float vertical){
mPosicion = new PointF(horizontal,vertical);
actualizaColision();
}
PointF getPosicion(){
return mPosicion;
}
PointF getTamano(){
return new PointF((int)mObjetoAltura,
(int)mObjetoAncho);
}
void voltear(){
mMirandoDerecha = !mMirandoDerecha;
}
boolean getMirandoDerecha(){
return mMirandoDerecha;
}
RectF getColision(){
return mColision;
}
PointF getPosicionDisparo(float longitudLaser){
PointF mPosicionDisparo = new PointF();
if (mMirandoDerecha){
mPosicionDisparo.x = mPosicion.x
+ (mObjetoAncho / 8f);
} else {
mPosicionDisparo.x = mPosicion.x
+ (mObjetoAncho / 8f) - longitudLaser;
}
mPosicionDisparo.y = mPosicion.y + (mObjetoAltura / 1.28f);
return mPosicionDisparo;
}
}
En resumen, hasta aca hemos visto la clase que se encargara de manejar las posiciones, el tamaño y las direcciones a donde mirar, tambien le daremos como tarea adicional que se encargue de las colisiones, tambien solucionamos los inconvenientes hasta ahora y en los proximos posts terminaremos de implementarlo, espero les haya gustado sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.
Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar
Es para mantenimiento del sitio, gracias!
$1.00