Bienvenidos sean a este post, en el post anterior vimos como establecer a nuestra pelota en el juego ahora nos toca el turno del bate.
Para esta ocasion trabajaremos sobre la clase Bate que como podran imaginarse sera muy similar a la clase Pelota pero con una diferencia sustancial, esta debe ser controlada por el usuario.
Como podran pensar se puede y se debe trabajar el toque de pantalla del usuario desde esta clase pero como esto en realidad posee una complejidad que en este momento no es necesaria vamos a hacer que la deteccion del toque para manejar nuestro bate lo efectue PongJuego y nuestra clase solo haga tres cosas:
- Moverse a la izquierda
- Moverse a la derecha
- No moverse
Con esto aclarado volveremos a trabajar con RectF para crear nuestro bate, tambien volveremos a trabajar de la misma forma es decir con un metodo getter para obtener a nuestro objeto y las distintas variables para manejar el desplazamiento de nuestro bate, para comenzar vamos a agregar las variables que necesitaremos dentro de la clase:
Bate.java
package org.example.pong;
import android.graphics.RectF;
class Bate {
private RectF mRect;
private float mLongitud;
private float mXCoord;
private float mBateVeloc;
private int mScreenX;
final int DETENIDO = 0;
final int IZQUIERDA = 1;
final int DERECHA = 2;
private int mBateMueve = DETENIDO;
}
En este caso primero tendremos el objeto de tipo RectF para contener a nuestro bate, luego tendremos una variable para definir la longitud del mismo, la siguiente sera para indicar en cual coordenada del eje X se encuentra, la que sigue sera para la velocidad del bate y la ultima para el ancho de la pantalla, las siguientes tres seran constantes para indicar si esta detenido, va a la izquierda y otra para la derecha, por ultimo tenemos una variable para indicar si nuestro bate se mueve o esta detenido, por ahora no se movera asi que le asignamos el estado DETENIDO, nuestro siguiente paso sera crear un constructor adecuado para nuestra clase:
Bate(int sx, int sy){
mScreenX = sx;
mLongitud = mScreenX / 8;
float altura = sy / 40;
mXCoord = mScreenX / 2;
float mYCoord = sy - altura;
mRect = new RectF(mXCoord,mYCoord,
mXCoord + mLongitud,
mYCoord + altura);
mBateVeloc = mScreenX;
}
Con este constructor iniciaremos todas nuestras variables y objetos, primero asignaremos el valor recibido en sx a mScreenX, nuestro siguiente paso sera dividir a mScreenX por ocho y asignarlo a mLongitud (con esto establecemos la longitud del bate), luego crearemos una nueva variable de tipo float llamada altura la cual sera el valor de sy dividido cuarenta, a mXCoord le asignaremos el resultado de mScreenX dividido dos y por ultimo crearemos una nueva variable llamada mYCoord la cual sera la diferencia entre sy menos el valor asignado en altura, nuestro siguiente paso sera crear verdaderamente el objeto mRect a este le pasaremos los valores de mXCoord y mYCoord para left y top respectivamente, luego tomaremos a mXCoord y le sumaremos a mLongitud para asignarlo a right y por ultimo tenemos a mYCoord al cual sumamos altura y se asigna a bottom, con esto tenemos nuestras cuatro variables asignadas dentro del objeto mRect, por ultimo usamos el valor de mScreenX a mBateVeloc para establecer la velocidad del bate, al igual que en el caso de la pelota nuestro siguiente paso sera agregar el metodo getter para el objeto mRect:
RectF getmRect(){
return mRect;
}
Con este metodo podremos tener acceso al objeto de nuestro bate (mRect), al igual que en el post anterior vamos a generar los metodos auxiliares para poder ayudar a nuestro bate, agreguemos la primera funcion:
void setEstadoMovimiento(int state){
mBateMueve = state;
}
Esta funcion la usaremos para establecer el valor de mBateMueve para saber en cual sentido se esta moviendo o si esta detenido, pasemos a nuestro siguiente metodo:
void actualizar(long fps){
if(mBateMueve == IZQUIERDA){
mXCoord = mXCoord - (mBateVeloc/fps);
}
if (mBateMueve == DERECHA){
mXCoord = mXCoord + (mBateVeloc/fps);
}
if(mXCoord < 0){
mXCoord = 0;
}
else if (mXCoord + mLongitud > mScreenX){
mXCoord = mScreenX - mLongitud;
}
mRect.left = mXCoord;
mRect.right = mXCoord + mLongitud;
}
Este metodo lo usaremos para actualizar la posicion de nuestro bate, para ello tendremos un condicional donde verifica si mBateMueve es igual a IZQUIERDA, esto indica que se esta moviendo hacia la izquierda por ende a mXCoord le restara la division de mBateVeloc y fps, el siguiente condicional verifica si mBateMueve es igual a derecha hace exactamente lo mismo al condicional anterior pero en lugar de restarlo lo suma para desplazarlo al otro lado.
Despues tendremos un condicional que usaremos para verificar que nuestro bate no se vaya de la pantalla, el primer condicional verifica si mXCoord es menor a cero y este deja a mXCoord con el valor de cero, despues usaremos un else if donde verificamos que la suma de mXCoord y mLongitud no sea mayor a mScreenX, en caso de ser verdadero establece como valor de mXCoord a la diferencia entre mScreenX y mLongitud, nuestros ultimos dos valores son para establecer los de left y right de mRect, con esto ya tenemos completa nuestra nueva clase, veamos el codigo final hasta ahora:
Bate.java
package org.example.pong;
import android.graphics.RectF;
class Bate {
private RectF mRect;
private float mLongitud;
private float mXCoord;
private float mBateVeloc;
private int mScreenX;
final int DETENIDO = 0;
final int IZQUIERDA = 1;
final int DERECHA = 2;
private int mBateMueve = DETENIDO;
Bate(int sx, int sy){
mScreenX = sx;
mLongitud = mScreenX / 8;
float altura = sy / 40;
mXCoord = mScreenX / 2;
float mYCoord = sy - altura;
mRect = new RectF(mXCoord, mYCoord,
mXCoord + mLongitud,
mYCoord + altura);
mBateVeloc = mScreenX;
}
RectF getmRect(){
return mRect;
}
void setEstadoMovimiento(int state){
mBateMueve = state;
}
void actualizar(long fps){
if(mBateMueve == IZQUIERDA){
mXCoord = mXCoord - (mBateVeloc/fps);
}
if (mBateMueve == DERECHA){
mXCoord = mXCoord + (mBateVeloc/fps);
}
if(mXCoord < 0){
mXCoord = 0;
}
else if (mXCoord + mLongitud > mScreenX){
mXCoord = mScreenX - mLongitud;
}
mRect.left = mXCoord;
mRect.right = mXCoord + mLongitud;
}
}
Con todo esto modificado podemos pasar a implementarlo en nuestra clase PongJuego, para ello primero vamos a ir al constructor de esta clase y vamos a agregar la siguiente linea detras de nuestro objeto para crear la pelota:
mBate = new Bate(mScreenX,mScreenY);
En este caso creamos a nuestro objeto con el constructor que explicamos anteriormente, le asignamos los valores de mScreenX y mScreenY, nuestra siguiente linea sera para agregarla dentro del metodo actualizar dentro de la clase PongJuego:
mBate.actualizar(mFPS);
En este caso enviaremos el valor de mFPS al actualizar de la clase Bate, nuestra ultima modificacion sera en el metodo dibujar, a la cual agregaremos la siguiente linea despues de la encargada de dibujar la pelota:
mCanvas.drawRect(mBate.getmRect(),mPincel);
Como en el caso anterior solo se encarga de dibujar a nuestro bate, antes de probarlo veamos como quedo nuestro codigo final hasta ahora de la clase PongJuego:
PongJuego.java
package org.example.pong;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
class PongJuego extends SurfaceView implements Runnable {
private final boolean DEPURANDO = true;
private SurfaceHolder mNuestroCont;
private Canvas mCanvas;
private Paint mPincel;
private long mFPS;
private final int MILES_EN_SEGUNDO = 1000;
private int mScreenX;
private int mScreenY;
private int mFontTam;
private int mFontMargen;
private Bate mBate;
private Pelota mPelota;
private int mPuntaje;
private int mVidas;
private Thread mJuegoThread = null;
private volatile boolean mJugando;
private boolean mPausado = true;
public PongJuego(Context contexto, int x, int y){
super(contexto);
mScreenX = x;
mScreenY = y;
mFontTam = mScreenX / 20;
mFontMargen = mScreenX /75;
mNuestroCont = getHolder();
mPincel = new Paint();
mPelota = new Pelota(mScreenX);
mBate = new Bate(mScreenX,mScreenY);
iniciaNuevoJuego();
}
private void iniciaNuevoJuego(){
mPuntaje = 0;
mVidas = 3;
mPelota.reset(mScreenX,mScreenY);
}
private void dibujar(){
if (mNuestroCont.getSurface().isValid()){
mCanvas = mNuestroCont.lockCanvas();
mCanvas.drawColor(Color.argb(255,26,128,182));
mPincel.setColor(Color.argb(255,255,255,255));
mCanvas.drawRect(mPelota.getmRect(),mPincel);
mCanvas.drawRect(mBate.getmRect(),mPincel);
mPincel.setTextSize(mFontTam);
mCanvas.drawText("Puntaje: " + mPuntaje
+ " Vidas: " + mVidas,
mFontMargen,mFontTam,mPincel);
if (DEPURANDO){
imprimirDepuracion();
}
mNuestroCont.unlockCanvasAndPost(mCanvas);
}
}
private void imprimirDepuracion(){
int debugTam = mFontTam / 2;
int debugComienzo = 150;
mPincel.setTextSize(debugTam);
mCanvas.drawText("FPS: " + mFPS,
10,
debugComienzo + debugTam,
mPincel);
}
@Override
public void run(){
while(mJugando){
long frameInicio = System.currentTimeMillis();
if (!mPausado){
actualizar();
detectarColisiones();
}
dibujar();
long esteFrameTiempo = System.currentTimeMillis() - frameInicio;
if (esteFrameTiempo > 0){
mFPS = MILES_EN_SEGUNDO / esteFrameTiempo;
}
}
}
private void actualizar(){
mPelota.actualizar(mFPS);
mBate.actualizar(mFPS);
}
private void detectarColisiones(){
}
public void pause(){
mJugando = false;
try{
mJuegoThread.join();
} catch (InterruptedException e){
Log.e("Error","uniendo a thread");
}
}
public void resume(){
mJugando = true;
mJuegoThread = new Thread(this);
mJuegoThread.start();
}
}
Con esto ya podemos compilar nuestra aplicacion, si lo probamos deberemos tener una pantalla semejante a al siguiente:

Nota: No se olviden de setear a mPausado en true.
En este caso podemos ver como ahora no solamente tenemos la pelota sino que tendremos a nuestro bate en la base pero por ahora no funciona con respecto a la interaccion con el usuario lo cual veremos en el proximo post.
En resumen, hoy hemos completado la clase Bate, hemos visto como con procedimientos parecidos a la creacion de la pelota hemos hecho el bate, hemos logrado la ubicacion del mismo y ya agregar algunos limites del mismo con respecto a la pantalla, como se implementa para que sea generado por nuestro game engine, espero les haya sido util 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