Programación de videojuegos en Android con libGDX

49
Introducción a libGDX Descargar la librería Crear un proyecto JAVA nuevo Portar el proyecto JAVA a un proyecto Android Ciclo de vida de una aplicación libGDX Gráficos Texturas e Interpolación TextureRegion TextuimagrePacker Empaquetar imágenes automaticamente Carga de imágenes empaquetadas Dibujar imágenes en pantalla Entrada Detectar pulsaciones en la pantalla táctil Audio Sounds Cargar sonidos Reproducir sonidos Descargar sonidos Music Cargar una música Descargar una música Navegando entre pantallas del juego Vibración Cámaras Animación Manual de buenas prácticas Separar la lógica de la presentación Páginas para Desarrollo de Juegos Solución de problemas

Transcript of Programación de videojuegos en Android con libGDX

Page 1: Programación de videojuegos en Android con libGDX

Introducción a libGDXDescargar la libreríaCrear un proyecto JAVA nuevoPortar el proyecto JAVA a un proyecto Android

Ciclo de vida de una aplicación libGDXGráficos

Texturas e InterpolaciónTextureRegion

TextuimagrePackerEmpaquetar imágenes automaticamenteCarga de imágenes empaquetadasDibujar imágenes en pantalla

EntradaDetectar pulsaciones en la pantalla táctil

AudioSounds

Cargar sonidosReproducir sonidosDescargar sonidos

MusicCargar una músicaDescargar una música

Navegando entre pantallas del juegoVibraciónCámarasAnimaciónManual de buenas prácticas

Separar la lógica de la presentaciónPáginas para Desarrollo de JuegosSolución de problemas

Page 2: Programación de videojuegos en Android con libGDX

Introducción a libGDX

LibGDX es un framework multiplataforma de desarrollo de juegos para Windows, Linux yAndroid. Está escrito en Java con una mezcla de C/C++ para dar soporte y rendimiento a tareasrelacionadas con el uso de la física y procesamiento de audio.

LibGDX permite generar una aplicación en su PC y utilizar el mismo código en Android, de estamanera el proceso de pruebas y depuración se realiza de forma más rápida y cómoda ya queel PC es mucho más rápido que el dispositivo Android.Con LibGDX nos aseguramos de que la misma aplicación puede funcionar correctamente endiferentes dispositivos.

LibGDX está compuesto por una serie de componentes de serán comunes a todas lasaplicaciones.

Marco de Aplicación, que manejará el bucle principal y además estará encargado del clico devida, es decir, los eventos de creación,destrucción, pausa y resume de la misma.

Un componente de Gráficos que nos permitirá gestionar la representación de imágenes yobjetos gráficos en la pantalla.

Un componente de Audio, que nos facilitará el acceso a los sonidos y música de la aplicación.

Un componente de de Entrada y Salida para leer y escribir los diferentes ficheros de datoscomo por ejemplo, imágenes, archivos de configuración, sonidos, música, texturas,...

Un componente de Entrada que gestionara la entrada a través del teclado, pantalla tácil oacelerómetro.

Page 3: Programación de videojuegos en Android con libGDX

Adicionalmente podríamos ampliar la gama de módulos con otros dos más.

Math, permite la gestión rápida de cálculos matemáticos orientados al desarrollo devideojuegos.

Physics, que básicamente es un wrapper de Box2D y permite controlar la gestión de colisiones.

Este gráfico muestra en mayor detalle el sistema de módulos de LibGDX

Page 4: Programación de videojuegos en Android con libGDX

Realmente, estos módulos son sólo interfaces públicas que ofrece la librería.La propia aplicación será la encargada de la gestión de los diferentes módulos.

Ventajas: Soporte 2d full (bajo y alto nivel) Mucha documentación, tutoriales, ejemplos de código Releases en forma periódica la ultima fue en setiembre y anterior en Mayo Se puede probar en desktop (antes de subir a mobile) Maneja Audio, input (usuario), física,matemática,archivos Mas poderoso que Andengine Soporta 3d libGDX te da un acceso más fácil a Bajo nivel Posibilidad de tomar un juego hecho en java jar 2d o 3d y adaptarlo a libgdx para q

funcione nativo en android,eso hicieron con el juego Droid Invaders 3d.

Desventaja: El soporte de alto nivel en 3­d esta en construcción actualmente

Links de referencia: Pagina Oficial Wiki del proyecto Blog Foro Juego en 3d ya realizado: Droid Invaders Listado de Ejemplos Video Tutoriales Documentación

Page 5: Programación de videojuegos en Android con libGDX

Descargar la libreríaPara descargar la librería debemos ir a la web de la misma: http://libgdx.badlogicgames.com/

A la derecha pulsamos en download y de las dos versiones de la librería que nos aparecen,seleccionamos la versión Nightly Build.

Tras pulsar en Download ya sólo nos queda descargar la última versión de la librería.

Page 6: Programación de videojuegos en Android con libGDX

Crear un proyecto JAVA nuevoAunque el objetivo final es que el juego funcione sobre Android, trabajaremos con un proyectoJAVA que una vez terminado se portará a Android.

Para crear un proyecto JAVA en Eclipse simplemente en el menú vamos a File > New > JavaProject. Le damos un nombre al proyecto (en este caso Demo1). Elegimos la ruta donde secreará en memoria y le damos a Finish.

Page 7: Programación de videojuegos en Android con libGDX

Una vez creado el proyecto el siguiente paso será añadir la librería. Para ello una buena prácticaes crear un directorio dentro del proyecto donde incluir las librerías que usemos.Para ello click derecho sobre nuestro proyecto y New > Folder. En nuestro ejemplo estacarpeta la llamaremos libs.

Una vez creada esta carpeta, simplemente tendremos que añadir a la misma lo quenecesitamos para este proyecto. Para añadir, nos vamos al directorio donde hemos guardado lalibrería descargada en el apartado anterior y podemos arrastrar o copiar los archivos quenecesitamos (en la imagen).

Nos quedaría el proyecto de esta forma:

Ya tenemos las librerías en el directorio que hemos creado dentro del proyecto. Pero aún noforman parte del mismo, el siguiente paso es añadirlas. Para ello seleccionamos los cuatroficheros dentro de la carpeta libs, hacemos click derecho y en el menú contextualseleccionamos Build Path > Add to Build Path. El proyecto queda de la siguiente forma:

Page 8: Programación de videojuegos en Android con libGDX

Otra buena práctica, aunque no necesaria es añadir la información contenida en el Javadoc dela librería. El objetivo de esto es que cuando se muestre la ayuda emergente de eclipse veamosla información contenida en el Javadoc de la librería.

Para ello hacemos click derecho sobre el proyecto y en el menú contextual Build Path >Configure Build Path... tras lo que se nos muestra lo siguiente:

Page 9: Programación de videojuegos en Android con libGDX

En esta ventana desplegamos gdx.jar y tal como se ve en la imagen seleccionamos Javadoclocation. Una vez hecho esto pulsamos sobre Edit...

Pulsamos en Browse... y buscamos la localización del Javadoc que se encuentra enlibgdx­nightly > docs > api. Una vez seleccionado este directorio pulsamos sobre Ok paraconfirmar el cambio. Y ya tenemos esta característica habilitada.

Una vez preparado Eclipse y nuestro proyecto JAVA ya podemos empezar a trabajar.

Lo primero será crear la clase principal del juego, que será la encargada de manejar y controlar

Page 10: Programación de videojuegos en Android con libGDX

todo lo que ocurra en el juego.

Para ello click derecho sobre src > New > Class.

­ Creamos la clase en el paquete com.desarrolladoresandroid.libgdx.demo1­ El nombre de la misma es Demo1Game­ Esta nueva clase heredará de Game (com.badlogic.gdx.Game).

Una vez creada la clase principal del proyecto, crearemos el punto de entrada para la ejecuciónde la aplicación JAVA. Una clase que nos permitirá lanzar el juego.

Para ello creamos una clase que contenga el método main:

Page 11: Programación de videojuegos en Android con libGDX

­ Nombre de la clase: Demo1Desktop­ Mismo paquete que la clase principal.­ Seleccionamos la opción public static void main(String[] args)

Nos quedaría el proyecto de la siguiente forma:

Page 12: Programación de videojuegos en Android con libGDX

Para poder lanzar el juego añadimos en la clase Demo1Desktop tenemos que añadir losiguiente:

new JoglApplication(new Demo1Game(), "Demo1", 320, 480, false);

Los parámetros indican lo siguiente:

­ new Demo1Game(). Instancia de la clase que implementa Game­ "Demo1". Que es el título de la aplicación.­ 320. Ancho en píxeles.­ 480. Alto en píxeles.­ false. Para indicar que no queremos utilizar OpenGL S 2.0 en este caso. Por lo que se utilizaráel 1.1

Una vez hecho esto ya tenemos un “juego” que no hace nada y que podemos lanzar comoaplicación JAVA.

Para lanzarlo tenemos que hacer click derecho en el proyecto y Run As > Java ApplicationUna vez hecho esto nos saldrá una ventana para seleccionar el punto de entrada de laaplicación que en nuestro ejemplo es Demo1Desktop.java

El resultado de la ejecución será una pantalla negra con la resolución indicada.

Page 13: Programación de videojuegos en Android con libGDX
Page 14: Programación de videojuegos en Android con libGDX

Portar el proyecto JAVA a un proyecto Android

Ahora crearemos el proyecto para compilarlo en Android. Para efectos practicos usare unejemplo que yo ya tenía. Hecho en escritorio llamado HolaLibgdx.

Page 15: Programación de videojuegos en Android con libGDX
Page 16: Programación de videojuegos en Android con libGDX

11. Crear carpeta libs dentro del proyecto y ponerle las siguientes librerías de las quedescargamos incluyendo esas carpetas:

Importante! "SE DEBEN INCLUIR LAS CARPETAS armeabi y armeabi­v7a como se ve en laimagen. Estas carpetas vienen en las librerías que descargamos"

Page 17: Programación de videojuegos en Android con libGDX

12. Referenciamos las librerías copiadas. Click derecho al proyecto / build path / configure buildpath...

13. Antes de cerrar esa pantalla anterior ir a la pestaña project y adjuntarle la referencia alproyecto de escritorio.

Page 18: Programación de videojuegos en Android con libGDX

12. Modificar la Activity principal "HolaLibGdxActivity" para que no extienda de Activity sino deAndroidApplication. (crt+shift+o) para resolver los imports necesarios.package com.libgdx.holalibgdx;

import android.os.Bundle;

import com.badlogic.gdx.backends.android.AndroidApplication;import com.libgdx.holalibgx.HolaLibgdx;

public class HolaLibGdxActivity extends AndroidApplication /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState); //Aca inicializamos al app de escritorio.

initialize(new HolaLibgdx(),false);

Debería quedarnos así.13. Lo ejecutamos en el emulador.

Page 19: Programación de videojuegos en Android con libGDX
Page 20: Programación de videojuegos en Android con libGDX

Desbloqueamos el dispositivo en el emulador.

Page 21: Programación de videojuegos en Android con libGDX

y Se ejecuta exactamente lo mismo que en escritorio. Lo que hicimos recién, también compilóla aplicación en un archivo .apk dentro del directorio /bin del proyecto android,ese archivo .apk se lleva al dispositivo fisico real y al ejecutarlo te instala la app creada.

Page 22: Programación de videojuegos en Android con libGDX

Ciclo de vida de una aplicación libGDXEste apartado describe cómo se estructura una aplicación libgdx.

LA APLICACION

Es el principal punto de entrada para cualquier aplicación libgdx. La interfaz Applicationdetermina la plataforma y los graficos de fondo que serán utilizados por la aplicación. La interfaztambién proporciona los métodos para acceder a gráficos, audio, archivos de entrada ymódulos de E/S. También da acceso a un módulo de Logging el cual funciona en todas lasplataformas.

LibGDX es compatible actualmente con dos back­ends de aplicaciones de escritorio (lwjgl yJOGL) y otra para Android.

Para crear una aplicación libGDX, se ha de implementar la interfaz ApplicationListenerprimero.

APPLICATION LISTENER

ApplicationListener es el responsable de la inicialización de la aplicación, la actualización delestado del juego (es decir, la lógica del juego), renderización de la imagen, pausado del juego,guardar el estado y la liberación de los recursos al salir de la aplicación.

Es también el lugar donde los eventos del ciclo de vida son manejados. Cada aplicación / juego,sin importar el back­end y / o plataforma de destino tendrá que implementar la interfazApplicationListener. La implementación es exactamente la misma para todas las plataformas.

Por tanto, Application es responsable del circuito de juego y ApplicationListener es el lugardonde se implementa la lógica del juego.

La implementación de la interfaz ApplicationListener

Page 23: Programación de videojuegos en Android con libGDX

Los eventos que son desencadenados por los en la aplicación del ciclo de vida tal como sedescribe:

create (): Se llama una vez cuando se crea la aplicación.

resize(int width, int height): Se llama a este método cada vez que la pantalla del juegocambia su tamaño y el juego no está en el estado de pausa. También se le llama sólo una vezjusto después del método create (). Los parámetros son la nueva anchura y altura de la pantalla.

render (): Método llamado por el bucle del juego de la aplicación cada vez que se renderiza. Laactualización del juego también tiene lugar aquí antes de la representación real.

pause (): El método de pausa se llama justo antes que se destruya la aplicación. En Android sellama cuando el botón de inicio se presiona o haya una llamada entrante. En el escritorio sellama justo antes de dispose () al salir de la aplicación. Es un buen lugar para guardar el estadodel juego en Android, ya que no se garantiza que sea reanudado.

resume(): Este método es llamado sólo en Android, cuando la aplicación recibe el foco. En elescritorio este método no será llamado nunca.dispose (): Se le llama cuando la aplicación se destruye. Es precedido por una pausa ().

Page 24: Programación de videojuegos en Android con libGDX

Ciclo de vida de una aplicacion

Los métodos antes mencionados son provocados por la aplicación durante su ciclo de vida.

El siguiente diagrama muestra las diferentes fases por las que pasa una aplicación libGDX:

Page 25: Programación de videojuegos en Android con libGDX

GráficosEl módulo de gráficos es un resumen de la comunicación con el GPU y proporciona métodos deconveniencia para obtener las instancias de OpenGL ES. Se encarga de todo el códigorepetitivo necesarios para hacerse con el ejemplo de OpenGL y se ocupa de todas lasimplementaciones proporcionadas por el fabricante.Dependiendo del hardware subyacente, los contenedores pueden ser o pueden no estardisponible.El módulo de gráficos también proporciona métodos para generar mapas de pixels y texturas.En el siguiente código podemos ver cómo obtener una instancia de la API OpenGL 1.0:

GL10 gl = Gdx.graphics.getGL10 ();

El método devuelve una instancia que puede ser usada para dibujar en la pantalla. En el casoque la configuración de hardware no sea compatible con OpenGL ES 1.0, devuelve null.

El siguiente fragmento de código borra la pantalla y la pinta de rojo:

gl.glClearColor(0.1f, 0.0f, 0.0f, 1);gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

Texturas e Interpolación

Texture es una "imagen" en la memoria del chip gráfico (las imágenes en disco se cargarán enesta zona de memoria). En OpenGL el ancho y alto de una textura tiene que ser potencia de 2(...32, 64, 128, 256, 512, 1024, etc). Aunque en los ejemplos se definen la textura cuadrada, notiene por qué ser así. Puedes tener una textura de 128x32, 32x256, etc.

Por ejemplo, el HTC G1 soporta como mucho, una textura de 1024x1024 (Aunque puedes tenermás de una textura a la vez). Intentar utilizar texturas más grandes en este dispositivoprovocarán errores en el juego.La recomendación es que no pases del valor 1024 paraestablecer el ancho o alto de tus texturas.

Un parámetro muy importante que hay que indicar a la hora de crear un objeto Texture es unvalor TextureOptions que indicará qué método se utilizará para redimensionar las imágenesque tenemos dentro de la textura. (Para no complicar las cosas, dejaremos esa explicación).

Page 26: Programación de videojuegos en Android con libGDX

Se pueden elegir los siguientes modos:

NEAREST:La imagen aparecerá pixelada. Es mucho más rápido, pero la imagen tiene menor calidad.

Original:

Ampliada con NEAREST:

BILINEAR:La imagen aparece más difuminada. Es un poco más lento, pero no verás píxeles en la misma.

Original:

Ampliada con BILINEAR:

REPEATING:Si la textura es de 32x32 y tiene que dibujarse sobre una superficie de 64x64, veremos 4imágenes rellenando ese hueco. Como si pusiéramos la misma imagen una y otra vezrepitiéndola. Este modo no funciona con los Sprites normales, así que por ahora, vamos aignorarlo.

Cuando utilizas imágenes que contienen valores alpha (transparencia) puedes encontrarte con

Page 27: Programación de videojuegos en Android con libGDX

que te aparezcan "halos" que rodean los bordes de las mismas. Aquí es donde entra en juego latécnica "premultiplied alpha", la cual corrige ese problema. Intenta evitar utilizar "premultipliedalpha" a menos que veas cosas raras en los bordes de tus imágenes, como sobras o halosresplandecientes que no deberían estar.

Si quieres una interpolación bilineal, estableces:

TextureOptions.BILINEAR

Si quieres una interpolación bilineal con "premultiplied alpha", estableces:

TextureOptions.BILINEAR_PREMULTIPLYALPHA

Lo mismo ocurre si quieres interpolación NEAREST con o sin "premultiplied alpha". Es cosatuya explorar los valores que puedes elegir de TextureOptions.

Para finalizar, decir que TextureOptions.DEFAULT =TextureOptions.NEAREST_PREMULTIPLYALPHA

Page 28: Programación de videojuegos en Android con libGDX

TextureRegion

Define un área rectangular de una textura. El sistema de coordenadas utilizado tiene su origenen la esquina superior izquierda con el eje x apuntando hacia la derecha y el eje y apuntandohacia abajo.Las textureRegion son empleadas para crear nuevas imagenes( o también llamados actores detipo imagen) asociadas a un área de una textura.

Tiene varias opciones para construir un objeto de esta clase, son los siguientes:

TextureRegion() Construye una region sin textuta ni coordenadas definidas.Se podran definir despues empleandolos métodos de la clase.

TextureRegion(Texture texture) Construye una region de tamaño especificado en la textura.

TextureRegion(Texture texture, float u, float v, float u2, float v2)

TextureRegion(Texture texture, int width, int height) Construye una región con con las coordenadas de la textura y el ancho y alto especificado.

TextureRegion(Texture texture, int x, int y, int width, int height) Define una tetura especificando el punto (x,y) de origen y el tamaño del area (ancho,alto)

TextureRegion(TextureRegion region) Construye una región con la misma textura y coordenadas que la región pasada como parámetro.

TextureRegion(TextureRegion region, int x, int y, int width, int height) Construye una región con la misma textura y coordenadas que la región pasada como parámetro.

Un ejemplo de selección de un área con TextureRegion es el siguiente

TextureRegion texture = new TextureRegion(new Texture( Gdx.files.internal("data/jugador.png")), 0, 0, 40, 40);

Page 29: Programación de videojuegos en Android con libGDX

TexturePacker

Empaqueta imagenes en un Texture Atlas.

Lo ideal es almacenar muchas imágenes más pequeñas en una imagen másgrande,obligar a la textura más una vez, luego dibujar porciones de la misma muchasveces. libgdx tiene una clase TexturePacker que es una aplicación de línea de comandosqueempaqueta muchas imágenes más pequeñas en 1imágen más grande.

TexturePacker se basa en este algoritmo. También tiene una fuerza bruta, el embalaje devarias maneras y luego elegir el resultado más eficiente.

Empaquetar imágenes automaticamente

Se deberá importar la libreria: gdx­tools.jar

El código para ejecutar el TexturePacker:

Settings settings = new Settings();settings.padding=2;settings.maxHeight=1024;settings.maxWidth=1024;settings.incremental=true;

TexturePacker.process(settings, "images", "data");

Se deberá tener en el proyecto una carpeta images, con las imagenes a procesar. El procesogenerará la carpeta data con el pack realizado.

Carga de imágenes empaquetadasAsi se recuperan las texturas de un textureAtlas Generado por un packer.

public static AtlasRegion background;atlas = new TextureAtlas(Gdx.files.internal("data/pack"));background = atlas.findRegion("background");

Page 30: Programación de videojuegos en Android con libGDX

Dibujar imágenes en pantalla

Creamos la clase Asset para almacenar los recursos de imagenes. */public class Assets

/** Contiene el paquete de texturas. */public static TextureAtlas atlas;

/** Regiones dentro de la imagen de textura empaquetada */public static AtlasRegion background;public static AtlasRegion soundoff;public static AtlasRegion soundon;public static AtlasRegion start;public static AtlasRegion title;

/** * Load. */public static void load()

atlas = new TextureAtlas(Gdx.files.internal("data/pack"));background = atlas.findRegion("background");soundoff = atlas.findRegion("soundoff");soundon = atlas.findRegion("soundon");start = atlas.findRegion("start");title = atlas.findRegion("title");

public static void dispose()atlas.dispose();

Page 31: Programación de videojuegos en Android con libGDX

public class HolaLibgdxExample implements ApplicationListener

/** The gui cam. */OrthographicCamera guiCam;

/** Se utiliza para dibujar y optimizar las imagenes en el renderizado de la pantalla. */SpriteBatch batcher;

@Overridepublic void create()

@Overridepublic void dispose() batcher.dispose();

@Overridepublic void pause()

@Overridepublic void render()

GL10 gl = Gdx.graphics.getGL10(); //referencia a OpenGL 1.0gl.glClearColor(0,1,0,1);gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

guiCam = new OrthographicCamera(10, 15); //definicion de nuestra propia medida del juego

guiCam.position.set(10f / 2, 15f / 2, 0);// Donde estara mirando la camara

batcher = new SpriteBatch(); //crear solamente un batcher por pantalla y eliminarlo cuando no se use

Page 32: Programación de videojuegos en Android con libGDX

guiCam.update();batcher.setProjectionMatrix(guiCam.combined);

//Dibujando el Backgroundbatcher.disableBlending();

//se elimina graficamente la transparencia ya que es un fondobatcher.begin();batcher.draw(Assets.background, 0, 0, 10, 15);batcher.end();

//Dibujando elementos en pantalla activamos el Blendingbatcher.enableBlending();batcher.begin();batcher.draw(Assets.title, 1, 8, 8, 6);batcher.draw(Assets.start, 2, 5, 6, 1);batcher.draw(Assets.soundon, 2, 3, 6, 1);batcher.end();

@Overridepublic void resize(int arg0, int arg1)

@Overridepublic void resume()

Page 33: Programación de videojuegos en Android con libGDX
Page 34: Programación de videojuegos en Android con libGDX

Entrada

El módulo de entrada permite capturar los diversas formas de entrada de cadaplataforma. Permite saber del estado de cada tecla, la pantalla táctil y el acelerómetro.

En el escritorio la pantalla táctil se sustituye por el ratón, mientras que el acelerómetro noestá disponible.

En el fragmento de código siguiente se obtiene el touch actual de coordenadas si hay untouch del celular (o del ratón en el escritorio):

if (Gdx.input.isTouched ()) System.out.println ("de entrada se produjo en x =" + x + ", y =" + y);De manera similar a todos los medios de entrada pueden ser consultados y manipulados.

Detectar pulsaciones en la pantalla táctil

Se debe difinir un Vector, un area ficticia donde se captará el evento de pulsación del dedo.Usamos tambien el objeto de OrthographicCamera, para convertir los pixeles en nuestramedida en metros. Luego preguntamos si el boton que creamos “BoundingBox” tiene un touch.Y escribimos el código para manejar ese evento.

Page 35: Programación de videojuegos en Android con libGDX
Page 36: Programación de videojuegos en Android con libGDX

AudioLibGDX cuenta con un módulo de audio que ofrece dos tipos de recursos: El sonido y lamúsica.Ambos tipos soportan el formato WAV,MP3 y OGG. También ofrece acceso al hardware desonido.

La diferencia entre el sonido y la música es que el sonido se almacena en memoria y se usacada vez que se quiere reproducir alguno de ellos, mientras que la música son streams desonido que están almacenados en ficheros y a los que se accede cada vez que se quierereproducir algo.

El siguiente fragmento de código reproduce un fichero de música desde el disco con el volumena la mitad:

Music music = Gdx.audio.newMusic(Gdx.files.getFileHandle("data/myMusicFile.mp3",FileType.Internal));music.setVolume(0.5f);music.play();music.setLooping(true);

Sounds

Sound es una clase destinada a la reproducción de un efecto de sonido. Lo normal es cargar elsonido desde un archivo a memoria y luego reproducirlo a través del método Sound.play(). Lossonidos son generalmente cortos, llegando a durar unos pocos segundos ya que al sercargados en memoria pueden llegar a ocupar demasiado, incidiendo directamente en elrendimiento.

Cuando ya no vayamos a usar más ese sonido será necesario llamar al métodoSound.dispose() para liberar memoria en el dispositivo.

Page 37: Programación de videojuegos en Android con libGDX

Cargar sonidos

Los Archivos para los efectos de sonido los pondremos dentro de una carpeta llamada data

Para cargar en memoria un efecto de sonido tan sólo será necesario definirlo como tipo Soundy llamar al método Gdx.audio.newSound pasando como parámetro el fichero dentro deldirectorio data.

El siguiente fragmento de código carga un sonido en memoria.

Sound explosionexplosion = Gdx.audio.newSound(Gdx.files.internal("data/explosion.ogg"));

Puesto que el sonido será una cosa que sólo se cargará una vez durante toda la vida de laaplicación, haremos la llamada a newSound en nuestro método destinado a la carga de datos.

Reproducir sonidosPara reproducir un sonido previamente cargado en memoria tan sólo será necesario hacer unallamada al método play del sonido pasando como parámetro un valor entre 0 y 1 querepresentará el volumen.

explosion.play(1);

Descargar sonidosUna vez que no queramos hacer uso del sonido será necesario descargarlo de memoria ya queen los dispositivos móviles, la memoria RAM sigue siendo un elemento muy precidado.

Para descargar de memoria un sonido tan sólo será necesario llamar al método dispose delobjeto. Esto podemos hacerlo en nuestro apartado destinado a la descarga de datos o bien enel método dispose de la aplicación, como ya hemos visto en el apartado de ciclo de vida de laaplicación.

explosion.dispose();

Page 38: Programación de videojuegos en Android con libGDX

MusicMusic es la clase de libgdx para cargar archivos de sonido en nuestros juegos deriva de la claseDisposable consta de los siguientes métodos:

play() →Comienza a la canción,en el el caso de estar pausada la reanuda donde sequedo y en el caso de que se hubiera parado la comienza desde el principio.

pause() →Pausa la canción, si la canción no ha empezado aun o esta ya ha finalizado,este método es ignorado al llamarlo.

stop() →Para la canción.La siguiente vez que se llame al método play() la cancióncomenzará desde el principio.

isPlaying() →Función que devuelve un booleano, indicando si es verdad o no que lacanción esta sonando.

setLopping() →Admite como parámetro un booleano para indicar si se activa la funciónloop en la canción, esta función activa la repetición indefinida de la música, de tal formaque si se llama al procedimiento indicando true, la canción se repite indefinidamentehasta que la paremos o hasta que desactivemos el loop.

isLopping() →Función que devuelve un booleano, indicando si es verdad o no que lacanción esta sonando.

setVolume() →Varía el volumen del sonido, admite por parámetros (0 ó 1) ,con un 0 sepone en silencio y con 1 se pone el volumen al máximo.

getPosition() → Función que devuelve un float con la posición de la canción enmilisegundos

dispose() → Es el destructor de la clase. Es muy conveniente llamarlo cuando no seanecesaria la musica ya que consume memoria del disposivo­

Libgdx soporta los formatos MP3, OGG y WAV. Es conveniente usar Ogg en casi todos loscasos.Si necesita más control sobre el dispositivo de audio, puede utilizar el AudioDevice y clasesAudiorecorder que también se obtiene de la interfaz de audio. Estas clases permiten a lasalida de las muestras de PCM para el dispositivo físico de audio, así como muestras PCMregistro de un micrófono conectado.

Cargar una músicaLas músicas se pueden almacenar de forma interna en el proyecto que estamos desarrollandoo en una ruta fija(por ejemplo para poner como música un sonido standard del sistema)

Para cargar una música en memoria debemos instanciar un objeto de la clase Music pasandolecomo parámetro un puntero al fichero del tipo FileHandle nativo de java, de la siguiente forma:

Music music = Gdx.audio.newMusic(Gdx.files.getFileHandle("data/8.12.mp3", FileType.Internal));

Page 39: Programación de videojuegos en Android con libGDX

En este ejemplo la canción 8.12.mp3 esta guardada dentro de la carpeta del proyecto data, porlo que el tipo de archivo le indicamos que es interno. FileType.Internal. En el caso de no poderabrir el archivo se genera una excepción GdxRuntimeExceptionLos tipos posibles de ficheros son los nativos de Javade tipo File.FileType, estos son:

External → Path relativo a la raiz del almacenamiento SD de android. Internal → Path relativo a la ruta de la aplicacion android o dicho de otro modo relativo al

directorio raiz de la aplicación creada. Classpath → El path del fichero esta en una ruta relativa a la raiz del Clashpath Absolute → El path esta indicado de forma absoluta, indicando el filesystem que lo

contiene.

Reproducir una música

Para reproducir una música como hemos mencionado antes basta con llamar al metodo play()desde el objeto instanciado de tipo Music.Vamos a verlo mas claramente con un pequeño ejemplo de como dejar una músicareproduciéndose en un bucle infinitodonde la música es un archivo mp3 almacenado en una carpeta que hemos llamado data

Music music = Gdx.audio.newMusic(Gdx.files.getFileHandle("data/8.12.mp3", FileType.Internal)); music.setLooping(true); music.play();

Descargar una músicaUna vez que no queramos hacer uso del sonido será necesario descargarlo de memoria.Para descargar de memoria un sonido tan sólo será necesario llamar al método dispose delobjeto. Esto podemos hacerlo en nuestro apartado destinado a la descarga de datos o bien enel método dispose de la aplicación, como ya hemos visto en el apartado de ciclo de vida de laaplicación.En el caso de que la música estuviera en un bucle lo lógico es pararla antes de eliminarla porseguir una secuencia lógica, y en parte por estética de la programación, estos se hacellamando al método stop, por tanto el orden seria :

music.stop();music.dispose();

Navegando entre pantallas del juego

Page 40: Programación de videojuegos en Android con libGDX

Game extiende de AplicationListener para implementar multiples pantallas.Una Screen es una pantalla de un juego. Opciones, Menu principal, nivel 1, nivel 2, creditos, etc.

Para cambiar entre pantallas haremos:

Screen gameScreen = new GameScreen(game);game.setScreen(gameScreen);return;

es decir, creamos la screen, y se la seteamos a la instancia del juego.

VibraciónPara agregarle al juego del arkanoid (el del video tutorial) que vibre al chocar la barrita con lapared izquierda por modificamos el método render() de la clase GameScreen.

try Gdx.input.vibrate(200); System.out.println("vibra"); catch (Exception e) System.out.println(e);

CámarasOrthographicCamera guiCam;guiCam = new OrthographicCamera(10, 15); //definicion de nuestra propia medida del juego

10x15 metros: Esto es porque dividmos los 320x480 pixeles en bloques de 32px.

guiCam.position.set(10f / 2, 15f / 2, 0); // Donde estara mirando la camara

Page 41: Programación de videojuegos en Android con libGDX

AnimaciónCrearemos un personaje de un personaje y haremos una animación, es decir, que caminecomo si se estuviera moviendo.

Aquí se ve el ejemplo de un hombre corriendo. La imagen se puede ver como una matriz de imágenes lascuales se van a recorrer con dos ciclos y se van a pasar por imagen a un vector.Cuando se crea la animation, se le pasa por parametro la velocidad con la que se mueve el frame y el vectorde imágenes.Por último cuando se invoca al spriteBatch.draw(); se le indica el vector que contiene las imágenes, laposición de X y de Y en donde se quieren dibujar las mismas.

Usaremos la siguiente Imagen como secuencia:

Copiaremos esta imagen, en la carpeta /imagen del proyecto

Creamos una clase que implemente screen animación:

Page 42: Programación de videojuegos en Android con libGDX

public class AnimationScreen implements Screen

Game game;static final float WORLD_WIDTH = 5;static final float WORLD_HEIGHT = 3.3f;private static final int FRAME_COLS = 6; // #1private static final int FRAME_ROWS = 5; // #2OrthographicCamera guiCam;SpriteBatch batcher;

Animation walkAnimation; // #3Texture walkSheet; // #4TextureRegion[] walkFrames; // #5SpriteBatch spriteBatch; // #6TextureRegion currentFrame; // #7

float positionX=1;

float stateTime; // #8

Inicializamos en el constructor lo referente a la animación:

public AnimationScreen(Game game) this.game = game;

batcher = new SpriteBatch();guiCam = new OrthographicCamera(WORLD_WIDTH, WORLD_HEIGHT);guiCam.position.set(WORLD_WIDTH / 2, WORLD_HEIGHT / 2, 0);

walkSheet = new Texture(Gdx.files.internal("images/man.png")); // #9TextureRegion[][] tmp = TextureRegion.split(walkSheet,

walkSheet.getWidth() / FRAME_COLS, walkSheet.getHeight()/ FRAME_ROWS); // #10

walkFrames = new TextureRegion[FRAME_COLS * FRAME_ROWS];int index = 0;for (int i = 0; i < FRAME_ROWS; i++)

for (int j = 0; j < FRAME_COLS; j++) walkFrames[index++] = tmp[i][j];

walkAnimation = new Animation(0.025f, walkFrames); // #11

Page 43: Programación de videojuegos en Android con libGDX

spriteBatch = new SpriteBatch(); // #12stateTime = 0f; // #13

Ahora en el render hacemos:

Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // #14stateTime += Gdx.graphics.getDeltaTime(); // #15currentFrame = walkAnimation.getKeyFrame(stateTime, true); // #16spriteBatch.begin();

spriteBatch.draw(currentFrame, positionX, 2); // #17spriteBatch.end();

update(delta);

(16: obtenemos el frame correspondiente en base al tiempo que lleva moviendose)

Metodo Update

public void update(float delta)positionX+=0.1f;

Si necesitan el código fuente completo de este ejemplo: [email protected]

Page 44: Programación de videojuegos en Android con libGDX

Manual de buenas prácticasTO DO: Introducción a cosas para ser más eficientes y limpios escribiendo código.

Para ser limpios y eficientes escribiendo código es importante tener en cuenta varias cosascomo creaciones de métodos para simplificar el código, no hacer condiciones muy largas omuchos bucles anidados, estos son solo algunos ejemplos, ahora explicare un poco masextenso algunos de los puntos mencionados anteriormente.

­ Definir variables al principio de la clase/método, de esta forma se tiene un acceso rápido a esavariable y sabemos de un simple vistazo que atributos tiene.

­ Respetar las reglas de nomenclatura de los lenguajes tales como los siguientes:­ Los nombres de las variables comienzan con letras minúsculas, y en caso de contener

varias palabras se le pondrá mayúscula a la primera letra de cada palabra a partir de la segundapalabra.

­ Los nombres de los métodos se escribirán en minúscula siguiendo la misma regla queel nombrado de las variables. Por lo general, el nombre de estos suelen ser verbos.

­ Las variables finales se escribirán integramente en mayúscula, separando, si fueranecesario, diferentes palabras por medio del carácter guión bajo “_”

­ El nombre de los paquetes se realizará integramente en minúscula, aunque contengavarias palabras.

­ El nombre de las clases comenzará con la primera letra en mayúscula y las siguientesen minúscula. En caso de contener varias palabras se las distingirá poniendo mayúscula laprimera letra de cada palabra.

­ Tabular el código para una mayor compresión del mismo. En java, a diferencia de otroslenguajes de programación como puede ser python, no es necesario que las lineas de códigoestén tabuladas para pertenecer a un método/función/clase ya que para esto se utilizan lasllaves, pero de esta forma se hace el código más legible.

­ Realizar un estudio que relacione el tiempo de procesamiento vs almacenamiento. Enocasiones una lista puede estar muy bien para almacenar datos, pero un array tiene un accesoinmediato al dato contenido.

­ Si ves que programando escribes varias veces lo mismo, creaciones de objeto que varían muypoco, comprobación de un objeto, cambiar un objeto, lo mas probable es que puedas cambiarlopor una función o un método. Por ejemplo:

­ Crear un casillero de 10 x 10, esto implica dibujar o crear 100 casillas, escribirías100 veces:batcher.draw(casilla, posX, posY, 1, 1);

Page 45: Programación de videojuegos en Android con libGDX

Y esto no es eficiente, pero podrías dibujarlo con:

for (int i = 1; i < 11 ; i++) for (int j = 1; j < 11; j++)

batcher.draw(casilla, i, j, 1, 1);

­ Usar switch case si ves que comparas lo mismo dentro de muchos if, teniendo encuenta que un case solo comprueba integer y enumerados.

­ Antes de crear un método comprobar que no existe ya, o parecido, para que puedasmodificarlo, siempre que al modificarlo no haya nada dependiendo de el.

­ Usar varios for anidados hace que el programa se ralentice mucho, ya que podemosencontrarnos con recorridos con muchos elementos y los recorre todos por lo que ralentizamucho y no es eficiente, esto no suele aparecer mucho pero hay que tener cuidado a la hora demeter for while o do, uno dentro de otros ya que puede dar problemas

Otra de las cosas que hay que tener en cuenta a la hora de programar es ser limpio y noescribir como se nos van ocurriendo las cosas y dejarlo así, ya que si después alguien quiereusar nuestro o código o simplemente saber como funciona le sera imposible, por eso cuandoestemos programando hay que intentar dejar lineas simples, o explicar con comentarios cuandoveamos que algo puede que no se entienda.Lo que también ayudara a la hora de la limpieza y de la claridad seran la clases, lo masimportante en el caso de la programación orientada a objetos. Siempre que vallas a utilizar unobjeto que vaya a tener mas de una propiedad se utilizan clases. Algunos ejemplos:

­ Pelota en un espacio: Además de su nombre tendrá un x e y indicando su posición.­ Personaje: Además de su nombre puede tener su posición indicada con x e y, un

inventario guardado en un array, o cualquier cosa.En estos y en muchos mas la creación de una clase es lo mejor, cuando veas que estascreando dos variables para guardar información sobre un objeto dentro de una claseseguramente podrás instanciar ese objeto desde otra clase y sera mas claro que poniendotantos atributos.

Page 46: Programación de videojuegos en Android con libGDX

Separar la lógica de la presentación

Con lógica nos referimos a todas las comprobaciones, modificaciones o creaciones que sehacen antes de renderizar, ya que el proceso de renderizado solo ya es lento si metes tambiéntoda la logica ara que el juego sea lento, por esto es recomendable hacerlo en una clase aparte.

Para hacer la parte lógica basta con crear un clase aparte del renderizado donde comprobemoslo que haga falta antes de pintar en pantalla. Por ejemplo:­Cambiar la velocidad de una pelota al chocar con una pared:

// Choque en pared izquierdaif(ball.position.x ­ 0.25 < 1)

ball.position.x = 1 + 0.25f;ball.direction.x = ball.VELOCITY;

­Comprobar el valor de una casilla para pintarla de un color diferente:

public AtlasRegion casilla(int x, int y)switch(matriz[x][y])

case 0: return Assets.casillaG; break;case 1: return Assets.casillaB; break;case 2: return Assets.casillaR; break;case 3: return Assets.barco; break;default: return Assets.barco2; break;

­Actualizar valores de las variables.

En resumen todo lo que no sea dibujar en pantalla y deba ejecutarse siempre se ha de ponerfuera del renderizado, pero teniendo en cuenta que el render lo debe llamar, si hicieramos laparte logica en una clase llamada World deberia quedar algo parecido a esto:

public class World

//atributos internos

//constructor

public World()

Page 47: Programación de videojuegos en Android con libGDX

initialize();//metodo interno, abajo creado.

//inicializar variables o limpiar

public void initialize()

//actualizacion

public void update()//aqui deberá ir todo lo que forma parte de la lógica para el renderizado de la

pantalla, teniendo en cuenta que hay que llamarlo desde el render, que se el puede pasar losparámetros que se necesiten

Puede haber distintos World, y puede usarse en las pantallas que se necesiten, no tiene porqueser solo de una.

Para usar el World hay que llamarlo desde el render, pero antes tiene que haber un objetodesde el que llamarlo, que sera creado en la clase de la pantalla, aqui un ejemplo:

public class GameScreen implements Screen

World world;//Atributos

public GameScreen()

this.world = new World();//esto llama al contructor, que a la vez llama al inizialite.

//inicializacion de atributos.

@Overridepublic void dispose()

@Override

Page 48: Programación de videojuegos en Android con libGDX

public void hide()

@Overridepublic void pause()

@Overridepublic void render(float delta) //delta es el tiempo transcurrido desde la ultima llamada

por si la logica lo necesita.World.update();//aqui actualizamos la logica del juego.//Pintar imágenes.

@Overridepublic void resize(int width, int height)

@Overridepublic void resume()

@Overridepublic void show()

Page 49: Programación de videojuegos en Android con libGDX

Páginas para Desarrollo de Juegos

Descargar Sonidoshttp://www.mysoundfx.com/

Musica para dar ambiente a tu juegohttp://pro.jamendo.com/es/

Tutorial creación Sprites Animadas desde cerohttp://ilovepixel.net/tutorial.html

2d Game Art For Programmers

http://2dgameartforprogrammers.blogspot.com/

Crear un personaje para Animaciónhttp://2dgameartforprogrammers.blogspot.com/2011/10/creating­game­character.html

Carashttp://2dgameartforprogrammers.blogspot.com/2011/11/creating­basic­face.html

Fondoshttp://2dgameartforprogrammers.blogspot.com/2011/10/more­fun­with­gradients.html

Solución de problemasTODO: Se describen los problemas que más pueden aparecer junto con sus soluciones.