Bienvenidos sean a este post, en el post de hoy implementaremos a la primera de nuestras clases en el juego.
Antes de comenzar deben descargar el siguiente archivo el cual contendra todas las imagenes:
Una vez descargado deben extraer los archivos en la pc, luego los copian por medio de Ctrl+C, despues van a Android Studio al recurso res/drawable y presionen Ctrl+V para pegarlo, aparecera un nuevo cuadro, seleccionen la opcion que dice drawable solamente y presionen Ok para hacer la copia, nos aparecera un nuevo cuadro y sin modificar nada presionen Ok para realizar una copia, una vez realizado nos quedara de la siguiente forma

Con esto tenemos los recursos necesarios para nuestro juego y con ello ya completamos una parte de la clase, ahora continuaremos con la clase.
Como venimos haciendo hasta ahora primero vamos a declarar las variables y objetos de nuestra clase, primero modificaremos el acceso de la clase de publica a privada y para ello cambiaremos el inicio de la clase:
public class Manzana {
De la siguiente forma:
class Manzana {
Con esto modificado pasemos a agregar el siguiente bloque con las variables:
private Point mUbicacion = new Point();
private Point mRangoCreacion;
private int mTamano;
private Bitmap mBitmapManzana;
La primera variable guardara la ubicacion de la manzana en la grilla pero no lo hace en pixeles, las segundas dos variables seran los valores para elegir donde generar la manzana, y la ultima sera una imagen para representar a la manzana, nuestro siguiente paso sera agregar el constructor pertinente:
Manzana(Context contexto, Point rc, int t){
mRangoCreacion = rc;
mTamano = t;
mUbicacion.x = -10;
mBitmapManzana = BitmapFactory
.decodeResource(contexto.getResources()
,R.drawable.manzana);
mBitmapManzana = Bitmap
.createScaledBitmap(mBitmapManzana,t,t,false);
}
En este constructor recibiremos tres valores de argumento, el primero sera para el contexto, el segundo sera para el rango y el ultimo para el tamaño, con el segundo valor iniciaremos a mRangoCreacion, el tercero sera para iniciar a mTamano, la siguiente linea establece el valor inicial para el eje X de nuestra manzana, el siguiente bloque (en realidad es una linea extensa) donde por medio de BitmapFactory y el metodo decodeResource asignaremos al recurso que copiamos al principio llamado manzana de la carpeta drawable, el siguiente bloque se encarga de crear la imagen gracias al recurso que le asignamos antes y le definimos el tamaño gracias al valor ingresado en t, nuestro siguiente paso sera agregar dos metodos, el primero sera para la generacion y el segundo para devolver la ubicacion de la manzana, para ello agregaremos el siguiente bloque:
void generar(){
Random random = new Random();
mUbicacion.x = random.nextInt((mRangoCreacion.x) + 1);
mUbicacion.y = random.nextInt((mRangoCreacion.y - 1) + 1);
}
Point getUbicacion(){
return mUbicacion;
}
El primer metodo genera la ubicacion al azar de nuestra manzana, para ello crearemos un objeto de tipo Random, luego asignaremos un valor al azar al eje X de mUbicacion por medio de nextInt, definido por el valor que le asignamos a x en el constructor mas uno, para el eje Y hacemos algo parecido pero al valor de y le restamos uno y le sumamos uno, con esto tendremos nuestros dos ejes de la manzana, el siguiente metodo se encarga de devolver a mUbicacion, algo similar a como trabajabamos con getmRect en los proyectos anteriores, a continuacion agregaremos el ultimo metodo pero no por eso menos importante:
void dibujar(Canvas canvas, Paint pincel){
canvas.drawBitmap(mBitmapManzana,
mUbicacion.x * mTamano,mUbicacion.y * mTamano,pincel);
}
En este caso tendremos el metodo encargado de dibujar nuestra manzana para ello recibira un Canvas y un Paint como atributos, dentro del metodo usaremos el canvas informado y por medio de drawBitmap dibujaremos el Canvas, para ello enviamos los datos en el siguiente orden:
- Es el Bitmap que definimos anteriormente
- El siguiente es el valor de left
- El tercero sera el valor de top
- El ultimo es el pincel que lo dibuja
Con esto ya tenemos nuestra clase completa y presta para ser implementada, antes de continuar veamos el codigo final de nuestra clase:
Manzana.java
package org.example.snake;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import java.util.Random;
class Manzana {
private Point mUbicacion = new Point();
private Point mRangoCreacion;
private int mTamano;
private Bitmap mBitmapManzana;
Manzana(Context contexto, Point rc, int t){
mRangoCreacion = rc;
mTamano = t;
mUbicacion.x = -10;
mBitmapManzana = BitmapFactory
.decodeResource(contexto.getResources()
,R.drawable.manzana);
mBitmapManzana = Bitmap
.createScaledBitmap(mBitmapManzana,t,t,false);
}
void generar(){
Random random = new Random();
mUbicacion.x = random.nextInt((mRangoCreacion.x) + 1);
mUbicacion.y = random.nextInt((mRangoCreacion.y - 1) + 1);
}
Point getUbicacion(){
return mUbicacion;
}
void dibujar(Canvas canvas, Paint pincel){
canvas.drawBitmap(mBitmapManzana,
mUbicacion.x * mTamano,mUbicacion.y * mTamano,pincel);
}
}
Nuestro siguiente paso sera la implementacion de esta clase en nuestro juego, para ello volveremos a SnakeJuego y al Constructor donde agregaremos las siguientes al final del bloque:
mManzana = new Manzana(contexto,
new Point(ANCHO_NUM_BLOQUES,
mNumeroBloquesAlto),
tamanoBloque);
Esto se encargara basicamente de definir al objeto mManzana y enviamos todos los datos del constructor visto anteriormente, el unico dato extraño (por decirlo de alguna manera) es el objeto Point que generamos con new y le enviamos dos datos para generarlo, nuestra ultima modificacion sera en el metodo nuevoJuego donde agregaremos esta linea antes de resetear el puntaje:
mManzana.generar();
Con esta linea ahora tenemos a las coordenadas de nuestra manzana pero todavia no la dibujamos para ello debemos ir al metodo dibujar y antes del condicional de mPausado agregaremos la siguiente linea:
mManzana.dibujar(mCanvas,mPincel);
En este caso usamos el objeto mManzana y accedemos al metodo dibujar y le pasaremos los objetos mCanvas y mPincel, y con esto finalmente dibujaremos nuestra manzana en pantalla, antes de probarlo veamos como quedo nuestro codigo de SnakeJuego hasta ahora:
SnakeJuego.java
package org.example.snake;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Build;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
class SnakeJuego extends SurfaceView implements Runnable {
private Thread mThread = null;
private long mProxTiempoCuadro;
private volatile boolean mPausado = true;
private volatile boolean mJugando = false;
private SoundPool mSP;
private int mComer_ID = -1;
private int mMordida_ID = -1;
private final int ANCHO_NUM_BLOQUES = 40;
private int mNumeroBloquesAlto;
private int mPuntaje;
private Canvas mCanvas;
private SurfaceHolder mSurfaceHolder;
private Paint mPincel;
private Snake mSnake;
private Manzana mManzana;
public SnakeJuego(Context contexto, Point tamano) {
super(contexto);
int tamanoBloque = tamano.x / ANCHO_NUM_BLOQUES;
mNumeroBloquesAlto = tamano.y / tamanoBloque;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
AudioAttributes atributos = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
mSP = new SoundPool.Builder()
.setAudioAttributes(atributos)
.setMaxStreams(5)
.build();
} else {
mSP = new SoundPool(5, AudioManager.STREAM_MUSIC,0);
}
try {
mComer_ID = mSP.load(contexto,R.raw.apple,0);
mMordida_ID = mSP.load(contexto,R.raw.bitten,0);
} catch (Exception e){
Log.e("Error","Ha ocurrido un error con la carga de los archivos");
}
mSurfaceHolder=getHolder();
mPincel = new Paint();
mManzana = new Manzana(contexto,
new Point(ANCHO_NUM_BLOQUES,
mNumeroBloquesAlto),
tamanoBloque);
}
@Override
public void run(){
while(mJugando){
if(!mPausado){
if(requiereActualizar()){
actualizar();
}
}
dibujar();
}
}
public boolean requiereActualizar(){
final long BLANCO_FPS = 10;
final long MILES_POR_SEGUNDO = 1000;
if(mProxTiempoCuadro<=System.currentTimeMillis()){
mProxTiempoCuadro=System.currentTimeMillis()
+ MILES_POR_SEGUNDO / BLANCO_FPS;
return true;
}
return false;
}
public void actualizar(){
}
public void dibujar(){
if(mSurfaceHolder.getSurface().isValid()){
mCanvas = mSurfaceHolder.lockCanvas();
mCanvas.drawColor(Color.argb(255,26,128,182));
mPincel.setColor(Color.argb(255,255,255,255));
mPincel.setTextSize(120);
mCanvas.drawText("" + mPuntaje,20,120,mPincel);
mManzana.dibujar(mCanvas,mPincel);
if (mPausado){
mPincel.setColor(Color.argb(255,255,255,255));
mPincel.setTextSize(100);
mCanvas.drawText(getResources().getString(R.string.inicioTexto),
20,300,mPincel);
}
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
@Override
public boolean onTouchEvent(MotionEvent evento){
switch (evento.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_UP:
if (mPausado){
mPausado = false;
nuevoJuego();
return true;
}
break;
default:
break;
}
return true;
}
public void nuevoJuego(){
mManzana.generar();
mPuntaje = 0;
mProxTiempoCuadro = System.currentTimeMillis();
}
public void pausar(){
mJugando=false;
try{
mThread.join();
} catch (InterruptedException e){
Log.e("Error", "no se pudo detener el thread.");
}
}
public void retomar(){
mJugando=true;
mThread = new Thread(this);
mThread.start();
}
}
Con esto podemos probar nuestro juego y tendremos un resultado similar a como se ve en el siguiente video
Si lograron lo mismo que en el video Felicidades!!! Porque ya estamos dandole mucha mas forma al juego y sobre todo porque hicimos aparecer a una de las dos clases de nuestro juego.
En resumen, hoy hemos visto la clase Manzana, la cual se encargara de crear las manzanas en pantalla, hemos visto todos los metodos necesarios, hemos hablado sobre cada uno de ellos, hemos visto como implementarlo en nuestro engine y como se ve finalmente, 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