Anuncios

Bienvenidos sean a este post, en el dia de hoy no solo nos centraremos en solucionar los problemas del post anterior sino tambien agregaremos el codigo de la misma.

Anuncios

Para comenzar, primero solucionaremos el problema de que esta clase no es una vista y para ello modificaremos esta linea:

public class PongJuego {
Anuncios

Por la siguiente linea:

class PongJuego extends SurfaceView {
Anuncios

En este caso primero vamos a convertirla en privada a la clase y luego a heredar a SurfaceView la cual esta relacionada con View, a medida que la escriban les sugerira el paquete sino lo hace les debera quedar en rojo, la seleccionan y presionan Alt+Enter para agregarlo, en cualquier caso les agregara el siguiente paquete:

import android.view.SurfaceView;
Anuncios

Pero aun asi nos quedara con un error pero de eso hablaremos en un momento, y se preguntaran porque usarlo y no directamente View? Esto es debido a varias circunstancias, la primera es que al ser heredera de View tambien nos permite acceder a esta clase y la clase SurfaceView en particular nos permite tener metodos elementos a la hora de trabajar con juegos.

Anuncios

Continuando con el error si lo vemos es debido a que no tenemos un constructor predeterminado

Anuncios

Para solucionarlo vamos a agregar el siguiente constructor dentro de nuestra clase:

    public PongJuego(Context contexto, int x, int y){
        super(contexto);
    }
Anuncios

Con esto compensamos el constructor que mencionamos en el post anterior y nos devolvia un error, el primer dato sera para la vista o contexto donde debe trabajar, el segundo es el eje X y el tercero el eje Y, despues por medio de super estableceremos el contexto de la actividad maestra o principal, veamos como esta nuestro codigo hasta ahora:

PongJuego.java

package org.example.pong;

import android.content.Context;
import android.view.SurfaceView;

class PongJuego extends SurfaceView {

    public PongJuego(Context contexto, int x, int y){
        super(contexto);
    }

}
Anuncios

Hasta ahora tenemos nuestra clase que hereda todas las capacidades de View y a su vez tiene su constructor para poder crear el objeto de la clase PongActivity, si lo probaramos en este instante obtendriamos una hermosa pantalla en blanco la cual nos permitira comenzar a trabajar sobre nuestro juego.

Anuncios

Como estaremos volviendo varias veces sobre esta clase a continuacion estableceremos las bases para agregar los objetos (pelota y bate) asi como la deteccion de colision como los efectos de sonido pero sera en los proximos posts, para nuestra siguiente modificacion agregaremos las variables que usaremos durante el proyecto, estas iran dentro de la clase pero por fuera del constructor:

    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;
Anuncios

En este bloque tenemos todas nuestras variables/objetos declarados y solo en algunos casos definidos, en la primera variable usamos la palabra final para indicar que este valor no va a poder ser modificado, equivale a decir que es constante, y en este caso lo usamos para indicar si estamos depurando el programa o no, ya lo aplicaremos mas adelante, el siguiente bloque:

    private SurfaceHolder mNuestroCont;
    private Canvas mCanvas;
    private Paint mPincel;
Anuncios

Al igual como trabajamos con el primer proyecto lo usaremos para dibujar todo lo necesario en pantalla, el primero sera para el contenedor o la vista, el segundo sera para el Canvas y el ultimo el pincel para dibujar en dicho Canvas, por detras de este bloque la siguiente variable la usaremos para almacenar cuantos frames por segundo tenemos y la siguiente indicara la cantidad de milisegundos en un segundo, tenemos el siguiente bloque:

    private int mScreenX;
    private int mScreenY;
Anuncios

Estas variables contendran la resolucion de nuestra pantalla, veamos el siguiente bloque:

    private int mFontTam;
    private int mFontMargen;
Anuncios

Estas se encargaran de almacenar cuan grande seran nuestras letras o fuentes de nuestro texto, despues tendremos este bloque:

    private Bate mBate;
    private Pelota mPelota;
Anuncios

Seran los objetos que usaremos en el juego y si se dieron cuenta de un detalle no nos devolvio un error y nos permitio elegirlo como tipo al momento de escribirlo, esto es debido a que las clases existen y solamente las declaramos y no los definimos, pasemos a hablar sobre el ultimo bloque:

    private int mPuntaje;
    private int mVidas;
Anuncios

Estas seran las variables que se encargaran de guardar el puntaje (mPuntaje) y las vidas disponibles (mVidas), con esto tendriamos todas las variables que necesitaremos en nuestro juego, por el momento tenemos dos variables que son de tipo constante (DEPURANDO y MILES_EN_SEGUNDO) porque no queremos que nadie las modifique, por lo menos por ahora a la primera, pasemos a modificar nuestro constructor de la siguiente manera:

    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();

        iniciaNuevoJuego();
    }
Anuncios

La primera linea se mantendra igual porque es la encargada de llamar al constructor de la clase padre, las siguientes dos lineas se encargan de iniciar los valores mScreenX y mScreenY a traves de los valores recibidos en x e y respectivamente, despues vendra este bloque:

        mFontTam = mScreenX / 20;
        mFontMargen = mScreenX /75;
Anuncios

La primer linea establecera el tamaño de la fuente, en este caso sera un 20% del ancho de la pantalla, la siguiente linea sea encargara de calcular el margen pero esta vez sera el 75% del ancho de la pantalla, veamos nuestro siguiente bloque:

        mNuestroCont = getHolder();
        mPincel = new Paint();
Anuncios

Este bloque se encargara de inicializar los objetos que esten listos para ser dibujados en canvas, el metodo getHolder es propio de la clase SurfaceView, por ultimo tendremos un llamado a la funcion iniciaNuevoJuego pero como este aun no existe nos devolvera un error.

Anuncios

Para solucionar esto vamos a crear esta funcion con el siguiente codigo:

    private void iniciaNuevoJuego(){

        mPuntaje = 0;
        mVidas = 3;
        
    }
Anuncios

Obviamente esta funcion estara dentro de la clase pero por fuera del constructor, en esta simplemente iniciamos o reiniciamos (eso dependera de si es el primer juego o uno nuevo del jugador) los valores de mPuntaje y mVidas, con esto explicado y creado no deberemos tener ningun tipo de error en nuestro codigo, pasemos al metodo encargado de “dibujar” en nuestra pantalla:

    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));
            mPincel.setTextSize(mFontTam);
            mCanvas.drawText("Puntaje: " + mPuntaje
                            + "  Vidas: " + mVidas,
                    mFontMargen,mFontTam,mPincel);
            if (DEPURANDO){
                imprimirDepuracion();
            }
            mNuestroCont.unlockCanvasAndPost(mCanvas);
        }
    }
Anuncios

Hablemos sobre esta nueva funcion, primero chequea si nuestro contenedor es valido, en caso de ser verdadero procedera a ejecutar el bloque, de lo contrario no hara nada, dentro del bloque tenemos esta linea:

mCanvas = mNuestroCont.lockCanvas();
Anuncios
Anuncios

La cual se encargara de bloquear el area de memoria para que podamos comenzar a dibujar en nuestro Canvas, la siguiente linea establecera el color del mismo, la siguiente sera para establecer el color de nuestro pincel, blanco, la siguiente linea establecera el tamaño de la fuente en base al valor obtenido en el constructor, despues tendremos la linea que se encargara de escribir en el Canvas, en ella nos mostrara el puntaje (mPuntaje) y las vidas (mVidas), en esta estableceremos el margen de la fuente, el tamaño de la fuente y el pincel para “dibujarlo”, despues tendremos un condicional donde verificara si DEPURANDO es verdadero en caso de ser asi llamara a imprimirDepuracion, este metodo aun no existe pero ya lo veremos a continuacion, la ultima linea despues del condicional se encarga de desbloqiear el Canvas y aplicar todas las modificaciones realizadas en mCanvas, por ultimo vamos a agregar la ultima funcion:

    private void imprimirDepuracion(){
        int debugTam = mFontTam / 2;
        int debugComienzo = 150;
        mPincel.setTextSize(debugTam);
        mCanvas.drawText("FPS: " + mFPS,
                10,
                debugComienzo + debugTam, 
                mPincel);
    }
Anuncios
Anuncios

En esta funcion primero declararemos a debugTam de tipo int al cual le asignaremos el tamaño de la fuente divido por dos, despues declararemos una variable llamada debugComienzo y le asignaremos el valor de 150, despues estableceremos el tamaño del texto de nuestro pincel a traves de la variable debugTam, las siguientes lineas se encargan de mostrar un texto en pantalla y en este caso veremos los frames por segundo (FPS) de la misma forma que explicamos antes, con esto ya tendriamos cubierto (por ahora) nuestra clase PongJuego, no pierdan las esperanzas todavia nos falta un poco para disfrutar de nuestro segundo juego pero antes de finalizar veamos nuestro codigo final:

PongJuego.java

package org.example.pong;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

class PongJuego extends SurfaceView {

    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;

    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();

        iniciaNuevoJuego();
    }

    private void iniciaNuevoJuego(){

        mPuntaje = 0;
        mVidas = 3;

    }

    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));
            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);
    }

}
Anuncios

En resumen, hoy hemos visto como convertir una clase en tipo Vista, como se hace, como se aplico polimorfismo, hemos creado un constructor para la solucionar el problema en PongActivity, hemos visto como declaramos todas las variables necesarias y las hemos iniciado bajo distintas formas, 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.