Bienvenidos sean a este post, en este caso vamos a trabajar de una forma similar al proyecto anterior pero le agregaremos un par de efectos mas.
La clase que utilizaremos para mostrar el fondo exttendera a Transformar y tambien usaremos la camara no solo para crear el efecto parallax sino tambien el movimiento vertical, pero que es un efecto parallax?
Es cuando diferentes capas de fondo se mueven a distintas velocidades para lograr el efecto de movimiento y profundidad, simplemente moviendo la capa del frente mas rapido que las traseras.
El Tinchicus
Para aclararlo en nuestro proyecto, la capa trasera sera el fondo y la delantera la plataforma, este efecto no es una invencion de los videojuegos sino que se implemento en los primeros tiempos del cine, si bien esto ya se lograba con el mitico Atari 2600 hoy en dia se puede lograr mejores efectos con mas planos para dar un mejor efecto de profundidad, vamos a comenzar con nuestra primera clase y para ello vamos a crear una nueva con las siguientes caracteristicas:
- Nombre: TransformarFondo
- Tipo: Class
Pasemos a modificar el codigo generado con el siguiente:
package org.example.pepeaventura;
import android.graphics.PointF;
class TransformarFondo extends Transformar {
private float recortarX;
private boolean primeroInvertido = false;
public TransformarFondo(float velocidad,
float anchoObjeto,
float alturaObjeto,
PointF posicionInicial){
super(velocidad,
anchoObjeto,
alturaObjeto,
posicionInicial);
}
boolean getPrimeroInvertido(){
return primeroInvertido;
}
void volteaPrimeroInvertido(){
primeroInvertido = !primeroInvertido;
}
float getRecortarX(){
return recortarX;
}
void setRecortarX(float nuevoRecorteX){
recortarX = nuevoRecorteX;
}
}
Como dijimos antes esta clase la usaremos para extender a Transformar, trabaja de forma similar a como lo hicimos en el proyecto anterior, la primera variable representa la posicion horizontal de la imagen del fondo y la segunda va a ser para indicar cual de las imagenes del fondo se dibujara primero, lo siguiente sera el constructor para poder enviar los datos necesarios al constructor de la clase Transformar y poder utilizarlo, esto lo hacemos por medio del super, y por ultimo tenemos una serie de metodos getter and setter para las variables:
- getPrimeroInvertido, devuelve el valor de primeroInvertido
- volteaPrimeroInvertido, invierte el valor de primeroInvertido
- getRecortarX, devuelve el valor de recortarX
- setRecortarX, setea a recortarX con un nuevo valor
Con esto tenemos nuestra clase completa pasemos a la siguiente, creamos la nueva clase con las siguientes caracteristicas:
- Nombre: ComponenteGraficosFondo
- Tipo: Class
Pasemos a modificar su codigo de la siguiente manera:
package org.example.pepeaventura;
import android.content.Context;
import android.graphics.PointF;
import org.example.pepeaventura.especoj.EspecJuegoObjeto;
class ComponenteGraficosFondo implements ComponenteGraficos {
private String mNombreBitmap;
@Override
public void inicializar(Context contexto,
EspecJuegoObjeto espec,
PointF tamanoObjeto,
int pixelsPorMetro){
mNombreBitmap = espec.getBitmapNombre();
BitmapAlmacen.agregarBitmap(contexto,
mNombreBitmap,
tamanoObjeto,
pixelsPorMetro,
true);
}
}
Para esta clase implementaremos a la interfaz ComponenteGraficos, nuestro primer paso sera crear una variable para almacenar el nombre del bitmap, el siguiente paso sera definir uno de los dos metodos que necesitamos para implementar nuestra interfaz, en este caso sera inicializar y le enviaremos los cuatro atributos que necesita, dentro del bloque definiremos el nombre del bitmap a traves de espec y el metodo getBitmapNombre, lo siguiente es agregar este bitmap en el BitmapAlmacen con todos los datos que recibimos y configuramos, para nuestro siguiente paso sera agregar el metodo faltante para poder implementar la interfaz:
@Override
public void dibujar(Canvas canvas,
Paint pincel,
Transformar t,
Camara cam) {
TransformarFondo tf = (TransformarFondo) t;
Bitmap bitmap = BitmapAlmacen.getBitmap(mNombreBitmap);
Bitmap bitmapInverso = BitmapAlmacen
.getBitmapInverso(mNombreBitmap);
int recortarXescalado = (int) tf.getRecortarX()
* cam.getPixelsPorMetro();
int ancho = bitmap.getWidth();
int alto = bitmap.getHeight();
PointF ubicacion = t.getUbicacion();
float inicioYflotante = ((cam.getCentro() -
((cam.getCentroMundoCamaraY() - ubicacion.y) *
cam.getmPixelsPorMetroY())));
int inicioY = (int) inicioYflotante;
float finalYflotante = ((cam.getCentro() -
((cam.getCentroMundoCamaraY() - ubicacion.y -
t.getTamano().y) *
cam.getmPixelsPorMetroY())));
int finalY = (int) finalYflotante;
Rect desdeRect1 = new Rect(0, 0,
ancho - recortarXescalado, alto);
Rect haciaRect1 = new Rect(recortarXescalado,
inicioY, ancho, finalY);
Rect desdeRect2 = new Rect(ancho - recortarXescalado,
0, ancho, alto);
Rect haciaRect2 = new Rect(0, inicioY,
recortarXescalado, finalY);
if (!tf.getPrimeroInvertido()) {
canvas.drawBitmap(bitmap, desdeRect1,
haciaRect1, pincel);
canvas.drawBitmap(bitmapInverso, desdeRect2,
haciaRect2, pincel);
} else {
canvas.drawBitmap(bitmap, desdeRect2,
haciaRect2, pincel);
canvas.drawBitmap(bitmapInverso,desdeRect1,
haciaRect1,pincel);
}
}
Este metodo sera el encargado de dibujar en pantalla sino que ademas nos permitira implementar nuestra interfaz, primero crearemos una variable de tipo TransformarFondo y le pasaremos el atributo Transformar que recibimos, luego creamos un Bitmap al cual le pasaremos el bitmap que definimos en inicializar, para despues crear una variable para escalar a recortarX de la clase TransformarFondo gracias a la escala de la camara, los siguiente sera obtener el ancho y alto del bitmap y la ubicacion del mismo, por ultimo calcularemos el valor de la coordenada Y inicial de tipo flotante, y a este lo transformaremos en coordenadas de pixel gracias a la camara, lo mismo haremos para calcular la coordenada Y final de tipo flotante, pero ambos valores los agregaremos en dos variables de tipo int con nombres similares.
El siguiente paso sera crear los Rect para al igual que el proyecto anterior unir el fondo normal con el fondo invertido y hacer un efecto de continuidad para ello crearemos dos variables llamadas desdeRect1 y haciaRect1, despues tendremos dos variables tambien de tipo Rect llamadas desdeRect2 y haciaRect2, en ambos casos las usaremos para definir los Rect de origen y destino para las dimensiones del bitmap y del bitmap inverso cuando las dibujamos con el canvas, con esto ya tenemos cubierta la clase encargada de dibujar el fondo con respecto a la camara, pasemos a ver su codigo final:
ComponenteGraficosFondo.java
package org.example.pepeaventura;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import org.example.pepeaventura.especoj.EspecJuegoObjeto;
class ComponenteGraficosFondo implements ComponenteGraficos {
private String mNombreBitmap;
@Override
public void inicializar(Context contexto,
EspecJuegoObjeto espec,
PointF tamanoObjeto,
int pixelsPorMetro){
mNombreBitmap = espec.getBitmapNombre();
BitmapAlmacen.agregarBitmap(contexto,
mNombreBitmap,
tamanoObjeto,
pixelsPorMetro,
true);
}
@Override
public void dibujar(Canvas canvas,
Paint pincel,
Transformar t,
Camara cam) {
TransformarFondo tf = (TransformarFondo) t;
Bitmap bitmap = BitmapAlmacen.getBitmap(mNombreBitmap);
Bitmap bitmapInverso = BitmapAlmacen
.getBitmapInverso(mNombreBitmap);
int recortarXescalado = (int) tf.getRecortarX()
* cam.getPixelsPorMetro();
int ancho = bitmap.getWidth();
int alto = bitmap.getHeight();
PointF ubicacion = t.getUbicacion();
float inicioYflotante = ((cam.getCentro() -
((cam.getCentroMundoCamaraY() - ubicacion.y) *
cam.getmPixelsPorMetroY())));
int inicioY = (int) inicioYflotante;
float finalYflotante = ((cam.getCentro() -
((cam.getCentroMundoCamaraY() - ubicacion.y -
t.getTamano().y) *
cam.getmPixelsPorMetroY())));
int finalY = (int) finalYflotante;
Rect desdeRect1 = new Rect(0, 0,
ancho - recortarXescalado, alto);
Rect haciaRect1 = new Rect(recortarXescalado,
inicioY, ancho, finalY);
Rect desdeRect2 = new Rect(ancho - recortarXescalado,
0, ancho, alto);
Rect haciaRect2 = new Rect(0, inicioY,
recortarXescalado, finalY);
if (!tf.getPrimeroInvertido()) {
canvas.drawBitmap(bitmap, desdeRect1,
haciaRect1, pincel);
canvas.drawBitmap(bitmapInverso, desdeRect2,
haciaRect2, pincel);
} else {
canvas.drawBitmap(bitmap, desdeRect2,
haciaRect2, pincel);
canvas.drawBitmap(bitmapInverso,desdeRect1,
haciaRect1,pincel);
}
}
}
Con esta clase concluida pasemos a crear la ultima clase con las siguientes caracteristicas:
- Nombre: ComponenteActualizarFondo
- Tipo: Class
Pasemos a modificar su codigo con el siguiente:
package org.example.pepeaventura;
class ComponenteActualizarFondo implements ComponenteActualizar {
@Override
public void actualizar(long fps,
Transformar t,
Transformar jugadorTransformar){
TransformarFondo tf = (TransformarFondo) t;
JugadorTransformar jt =
(JugadorTransformar) jugadorTransformar;
float actualRecortarX = tf.getRecortarX();
if (jugadorTransformar.apuntandoDerecha()){
actualRecortarX -= t.getVelocidad() / fps;
tf.setRecortarX(actualRecortarX);
} else if (jugadorTransformar.apuntandoIzquierda()){
actualRecortarX += t.getVelocidad() / fps;
}
if (actualRecortarX >= t.getTamano().x){
tf.setRecortarX(0);
tf.volteaPrimeroInvertido();
} else if (actualRecortarX <= 0){
tf.setRecortarX((int)t.getTamano().x);
tf.volteaPrimeroInvertido();
}
}
}
En esta clase vamos a implementar a ComponenteActualizar y para poder usarla debemos definir a actualizar, en el metodo actualizar recibiremos tres datos, uno para el fps, dos de tipo Transformar de los cuales uno sera para el fondo y otro para el jugador pero dentro del bloque crearemos dos objetos de Transformar los cuales seran uno para el fondo, al cual le asignaremos a t, y otro para el jugador, y a este le asignaremos a jugadorTransformar, despues crearemos una variable para obtener el valor actual de recortarX, nuestro siguiente paso sera este condicional:
if (jugadorTransformar.apuntandoDerecha()){
actualRecortarX -= t.getVelocidad() / fps;
tf.setRecortarX(actualRecortarX);
} else if (jugadorTransformar.apuntandoIzquierda()){
actualRecortarX += t.getVelocidad() / fps;
}
En este caso chequearemos si el jugador si esta mirando a la derecha o a la izquierda y en base a eso decrementaremos o incrementaremos a recortarX respectivamente, despues tenemos el siguiente condicional:
if (actualRecortarX >= t.getTamano().x){
tf.setRecortarX(0);
tf.volteaPrimeroInvertido();
} else if (actualRecortarX <= 0){
tf.setRecortarX((int)t.getTamano().x);
tf.volteaPrimeroInvertido();
}
}
Este condicional verifica si se reduce cualquiera de los extremos de izquierda o derecha y en cualquiera de los casos procede a invertir el orden y resetear al actual recortarX, con esto ya tenemos completa nuestra clase de actualizar a medida que modifiquemos el movimiento.
En resumen, hoy hemos creado tres clases encargadas de manejar el fondo de nuestro juego, hemos visto que son muy similares a la vista en el proyecto anterior, pero en esta ocasion debenos ajustarla a nuestra camara, tambien que en esta ocasion tendremos un Transformar tanto para el jugador como para el fondo de forma independiente, 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.


Donación
Es para mantenimento del sitio, gracias!
$1.00
