Вы находитесь на странице: 1из 128

Departament dEnginyeria Informtica i M atemtiques

Desarrollo de un Videojuego para Android

TITULACIN: Ingeniera Tcnica en Informtica de Sistemas

AUTOR: Eduardo Santiso Martorell


DIRECTOR: Carlos Molina Clemente

FECHA: Febrero de 2013.


RESUMEN

La popularizacin de los dispositivos mviles se ha disparado en los ltimos aos, en parte


gracias a la llegada de los smartphones o telfonos inteligentes. Actualmente forman
parte de la vida diaria de millones de personas en todo el mundo, independientemente de
su edad o condicin social.

El sistema operativo Android es el ms extendido y demandado en el mundo de los


dispositivos mviles, seguramente por su adaptabilidad a todo tipo de dispositivos como
por su sencillez, robustez y capacidad de personalizacin, logrando cubrir las necesidades
de cualquier usuario.

El sector de los videojuegos goza de prosperidad. Actualmente se est abriendo a nuevos


mercados y se acerca a sectores de poblacin inexplotados. El mercado de los videojuegos
para mviles ya es ms grande que cualquier otro mercado de videojuegos porttiles y se
estima que vaya incrementando an ms.

El presente proyecto busca crear un videojuego para dispositivos mviles Android desde
cero. Para ello, llevaremos a cabo el diseo del juego con sus especificaciones y requisitos.
Continuaremos viendo cmo construir un videojuego, creando un framework reutilizable
para futuros proyectos. Despus estudiaremos los fundamentos de las tecnologas que
necesitaremos para, posteriormente, llevar a cabo la implementacin.
RESUM

La popularitzaci dels dispositius mbils sha disparat en els darrers anys, en part grcies
a larribada dels smartphones o telfons intelligents. Avui en dia, formen part de la vida
diria de milions de persones a tot el mn, independentment de ledat o de la condici
social.

El sistema operatiu Android s el ms ests i sollicitat en el mn dels dispositius mbils,


segurament per la seva adaptabilitat a tot tipus de dispositius aix com tamb per la seva
senzillesa, fiabilitat i capacitat de personalitzaci, doncs aconsegueix cobrir les necessitats
de qualsevol usuari.

El sector dels videojocs gaudeix de prosperitat. Actualment, sest obrint a nous mercats i
sapropa a sectors inexplotats de la poblaci. El mercat dels videojocs per a mbils s ja
ms gran que qualsevol altre mercat de videojocs porttils i es preveu que augmenti encara
ms.

Aquest projecte t la intenci de crear un videojoc per a dispositius mbils Android des de
zero. Per aconseguir-ho durem a terme tot el disseny amb les especificacions i
requeriments. Continuarem veient com es construeix un videojoc, creant un framework
reutilitzable per projectes futurs. Desprs estudiarem els fonaments de les tecnologies que
necessitarem per, finalment, acabar realitzant la implementaci.
ABSTRACT

The popularity of mobile devices has exploded in recent years, thanks in part to the arrival
of smartphones. Nowadays, the smartphones are part of the daily lives of millions of
people around the world, regardless of age or social status.

The Android operating system is the most extended and requested in the world of mobile
devices, probably due to its adaptability to all types of devices as well as for its simplicity,
reliability and customization, capable of meeting the needs of any user.

The video game industry is enjoying prosperity. Currently, it is opening to new markets
and it approaches to unexploited sectors of the population. The mobile gaming market is
already bigger than any other portable game market and is expected to increase even more.

This project is intended to create a game for Android mobile devices from scratch. For this
aim, the design of the game is carried out with its specifications and requirements. Then,
the game is performed by creating a reusable framework for future projects. After that, the
foundations for the needed technologies are studied to finish doing the implementation.
INDICE

1 Introduccin ................................................................................................................. 15

1.1 Dispositivos Mviles ........................................................................................... 15

1.2 Industria del Videojuego ..................................................................................... 16

1.3 Videojuegos porttiles ......................................................................................... 17

1.4 Sistemas Operativos para Mviles ...................................................................... 18

1.4.1 iOS de Apple. ................................................................................................ 18

1.4.2 Windows Phone ............................................................................................. 18

1.4.3 Symbian OS ................................................................................................... 19

1.4.4 BlackBerry OS............................................................................................... 19

1.4.5 Android .......................................................................................................... 20

1.5 Por qu Android? ............................................................................................... 21

2 Objetivos del Proyecto ................................................................................................ 23

2.1 Requisitos Funcionales ........................................................................................ 24

2.2 Requisitos no Funcionales ................................................................................... 24

2.3 Requisitos de Rendimiento .................................................................................. 24

3 Especificaciones del Videojuego. ................................................................................ 25

3.1 Gnero i Objetivos del Videojuego. .................................................................... 25

3.2 Mecnica del Juego. ............................................................................................ 25

3.3 Control del Juego. ................................................................................................ 26

3.4 Pantallas. .............................................................................................................. 26

3.4.1 Men Principal. ............................................................................................. 27

3.4.2 Ayuda. ........................................................................................................... 28

9
3.4.3 Ranking. ......................................................................................................... 29

3.4.4 Preparado. ...................................................................................................... 29

3.4.5 Juego. ............................................................................................................. 30

3.4.6 Pausa. ............................................................................................................. 31

3.4.7 Fin de Juego. .................................................................................................. 31

3.4.8 No Hay Movimientos. ................................................................................... 31

3.4.9 Diagrama entre Pantallas ............................................................................... 32

3.5 Sonido. ................................................................................................................. 34

3.6 Puntuacin. .......................................................................................................... 34

4 Diseo .......................................................................................................................... 35

4.1 Estructura de un Videojuego ............................................................................... 35

4.2 Restricciones de Diseo....................................................................................... 35

4.3 MVC (Modelo Vista Controlador) ................................................................ 36

4.4 Entrada ................................................................................................................. 37

4.5 Archivo de I/O ..................................................................................................... 38

4.6 Audio ................................................................................................................... 38

4.6.1 Obteniendo los Recursos ............................................................................... 38

4.7 Grficos ............................................................................................................... 39

4.7.1 La Pantalla ..................................................................................................... 39

4.7.2 Creando los Recursos .................................................................................... 40

4.7.2.1 Trabajar con Texto Empleando Fuentes Bitmap. ................................... 42

4.7.2.2 Mapa de Texturas. .................................................................................. 44

4.8 Gestor de Ventanas .............................................................................................. 45

10
4.9 Framework ........................................................................................................... 46

4.10 Lgica del Juego .................................................................................................. 46

5 Desarrollo. ................................................................................................................... 49

5.1 Conociendo Android y OpenGL. ........................................................................ 49

5.1.1 Preparando las Herramientas. ........................................................................ 49

5.1.2 Arquitectura del Sistema Operativo Android. ............................................... 50

5.1.3 Arquitectura Aplicacin ................................................................................ 51

5.1.3.1 La pila de Actividades ............................................................................ 52

5.1.3.2 Ciclo de Vida de una Aplicacin Android ............................................. 53

5.1.4 Estructura de una Aplicacin Android .......................................................... 55

5.1.5 Rendimiento, el Recolector de Basura y Jit................................................... 57

5.1.6 El problema de la Fragmentacin .................................................................. 58

5.1.7 OpenGL ES 1.0 ............................................................................................. 59

5.1.7.1 Como se Representa una Escena ............................................................ 60

5.1.7.2 Proyecciones........................................................................................... 61

5.1.7.3 Matrices .................................................................................................. 62

5.1.7.4 Sobre Vrtices y Tringulos ................................................................... 62

5.1.7.5 Enviar Vrtices a OpenGL ES ............................................................... 63

5.1.7.6 Texturas en OpenGL .............................................................................. 63

5.1.7.7 Filtrar Texturas ....................................................................................... 64

5.1.7.8 Espacio Mundo, Espacio Modelo........................................................... 64

5.1.7.9 Como Trabaja OpenGL ES 1.0 .............................................................. 65

5.2 Desarrollo del Juego ............................................................................................ 66

11
5.2.1 Estructura de Blocks ...................................................................................... 66

5.2.2 Framework ..................................................................................................... 67

5.2.2.1 Mdulo Archivos Input/Output .............................................................. 67

5.2.2.2 Mdulo Entrada ...................................................................................... 68

5.2.2.2.1 La clase Pool ...................................................................................... 69

5.2.2.2.2 El Controlador de Teclado ................................................................. 70

5.2.2.2.3 El Controlador Tctil ......................................................................... 71

5.2.2.2.4 Juntando las Entradas......................................................................... 72

5.2.2.3 Mdulo Audio ........................................................................................ 72

5.2.2.3.1 Msica ................................................................................................ 73

5.2.2.3.2 Efectos de Sonido .............................................................................. 74

5.2.2.3.3 Juntando el Audio .............................................................................. 74

5.2.2.4 Mdulo Grficos .................................................................................... 75

5.2.2.4.1 GLGraficos ........................................................................................ 75

5.2.2.4.2 Vector ................................................................................................. 75

5.2.2.4.3 La Cmara .......................................................................................... 78

5.2.2.4.4 Vrtices .............................................................................................. 79

5.2.2.4.5 Texturas ............................................................................................. 81

5.2.2.4.6 Dibujando Texto ................................................................................ 83

5.2.2.4.7 Lote de Modelos ................................................................................ 84

5.2.2.4.8 Medir el Rendimiento ........................................................................ 87

5.2.2.4.9 Otras Clases ....................................................................................... 87

5.2.2.5 Mdulo Gestor de Ventanas ................................................................... 88

12
5.2.3 Los elementos del Juego ................................................................................ 91

5.2.3.1 Configuracin ......................................................................................... 91

5.2.3.2 Recursos ................................................................................................. 92

5.2.3.3 La Actividad Principal ........................................................................... 93

5.2.3.4 Pantallas ................................................................................................. 93

5.2.3.4.1 Men Principal ................................................................................... 94

5.2.3.4.2 Pantallas de Ayuda............................................................................. 95

5.2.3.4.3 Pantalla Ranking ................................................................................ 96

5.2.3.4.4 Pantalla Juego .................................................................................... 97

5.2.3.5 Definir el Tablero de Juego .................................................................. 102

5.2.3.5.1 Bloque .............................................................................................. 103

5.2.3.5.2 Tablero ............................................................................................. 103

5.2.3.5.3 TableroRenderer .............................................................................. 110

6 Evaluacin ................................................................................................................. 115

7 Coste .......................................................................................................................... 117

8 Trabajos Futuros ........................................................................................................ 119

9 Conclusiones.............................................................................................................. 121

10 Recursos Utilizados ................................................................................................... 123

11 Planning Temporal. ................................................................................................... 125

12 Referencias ................................................................................................................ 127

13
14
1 Introduccin

En el presente apartado, veremos una introduccin al presente proyecto, en l discutiremos


desde una perspectiva general sobre los dispositivos mviles y los videojuegos, tambin
veremos los sistemas operativos ms utilizados en mviles analizando sus puntos fuertes y
dbiles y finalizaremos con las razones que nos han llevado a escoger entre uno u otro para
el presente proyecto.

1.1 Dispositivos Mviles

El telfono mvil nace de la necesidad de comunicacin en la distancia de un lugar a otro.


Los primeros sistemas estn datados a finales de los aos 40, eran enormes y pesados y
funcionaban por radio analgica.

En muy pocos aos los telfonos mviles evolucionaron pasando por varias generaciones,
popularizndose a partir de los aos 90, y con su xito los fabricantes no han parado de
innovar intentando destacar sobre los de la competencia.

Figura 1. Smartphones

El avance de la tecnologa ha permitido que estos aparatos incorporen funciones que no


hace mucho parecan futuristas, como juegos, reproduccin de msica, correo electrnico,
SMS, agenda electrnica PDA, fotografa digital, video digital, videollamada, navegacin
por Internet, GPS y permiten la instalacin de programas incrementando as la el
procesamiento de datos. Se conocen como Smarphones (en espaol telfono inteligente) y
funcionan como un ordenador un telfono mvil con caractersticas cercanas a un
ordenador personal.

15
Actualmente los telfonos mviles han llegado a convertirse en un dispositivo esencial en
nuestras vidas y los nmeros indican que el mercado de los smartphones y tablets est en
alza. La poblacin demanda cada vez ms este tipo de dispositivos.

Segn los datos de Strategy Analytics, en el tercer trimestre de 2011 se estimaba que
existan 708 millones de usuarios de smartphones en todo el mundo. Slo un ao despus
la cifra ha alcanzado los 1.038 millones. Esto significa que uno de cada siete habitantes en
el mundo tiene un smartphone.

1.2 Industria del Videojuego

Los primeros videojuegos modernos aparecieron en la dcada de los 60, eran juegos
simples que se desarrollaban completamente sobre hardware. Desde entonces el mundo de
los videojuegos no ha cesado de crecer y desarrollarse con el nico lmite impuesto por la
creatividad de los desarrolladores y la evolucin tecnolgica.

Fue en la dcada de los 80 cuando se experiment el boom de los videojuegos como


entretenimiento, con la llegada de las consolas domsticas y ttulos como Space Invaders,
Pac-man, Donkey Kong, o Tetris.

La expansin del videojuego es tan relevante que actualmente se trata de una industria
multimillonaria capaz de rivalizar con las industrias cinematogrfica y musical. [1]

Figura 2. Estadsticas de ventas de videojuegos, msica y cine. Por ESRB.


16
Igual que los dispositivos mviles, el videojuego ha crecido ligado a la tecnologa,
adaptando sus grficos, sonido y jugabilidad, llegando a cotas inimaginables hace unos
aos.

1.3 Videojuegos porttiles

Hoy en da con el avance de la tecnologa en los telfonos inteligentes, la industria del


videojuego pas de ser un entretenimiento de locales especializados, a la palma de la mano
de cualquier persona. La reciente eclosin de los smartphones los ha convertido en la
plataforma de juegos de esta nueva era, capaces de competir con las consolas porttiles
como Nintendo DS o Playstation Portable de Sony.

El mercado de los videojuegos para mviles ya es ms grande que cualquier otro mercado
de videojuegos porttiles, en 2011 los videojuegos de iOS y Android han triplicado su
dominio en los EE.UU. superando a Nintendo y Sony al acaparar cerca del 60% de la cuota
de mercado de los videojuegos porttiles.

Figura 3. Estadsticas del videojuego porttil.

iOS y Android como plataforma de juegos han incrementado sus ingresos de 2009 a 2011:
de 500 millones de dlares (366,5 millones de euros) en 2009, a 800 millones de dlares
(586,5 millones de euros) en 2010 y 1.900 millones de dlares (1.390 millones de euros) en
2011.

17
Existen muchos gneros de videojuegos: deportivos, arcade, estrategia destacamos el
gnero de los rompecabezas, ya que se adaptan perfectamente a los smartphones y gozan
de gran popularidad. Ttulos como Tetris o Bejeweled [2] son conocidos por todos.

1.4 Sistemas Operativos para Mviles

Un sistema Operativo para mvil est pensado para controlar un dispositivo porttil como
un SmartPhone o tableta.

Su funcionamiento es muy similar al de cualquier otro sistema operativo de equipo de


sobremesa pero con un diseo ms sencillo y especialmente pensado para que el usuario
interacte con l mediante pantalla tctil, voz, teclado virtual etc.

Veremos a continuacin los sistemas operativos ms destacados: Android, iOS,


BlackBerry OS, Symbian, Windows Mobile.

1.4.1 iOS de Apple.

iOS es un sistema operativo desarrollado por la compaa Apple Inc. Para los dispositivos
mviles iPod touch, iPhone e iPad. Est basado en una variante del Mach kernel de Mac
OS X, que a su vez es una variante de Unix.

Posee una interfaz grfica gestual que se caracteriza por un buen diseo, funcionalidad y
facilidad de uso.

Su perfecta integracin con servicios en la nube y equipos de sobremesa, especialmente


Mac, es otro de sus puntos fuertes. Adems de contar con una variedad de aplicaciones
enorme.

Pero el sistema operativo de Apple es cerrado, lo que significa que hay menos
posibilidades de cambiar la forma de funcionar del telfono y un control ms rgido de las
aplicaciones publicadas. Adems los dispositivos de Apple tienen un precio bastante alto.

1.4.2 Windows Phone

Es el sistema operativo mvil desarrollado por Microsoft como sucesor de la plataforma


Windows Mobile. Windows Phone forma parte de los sistemas operativos con interfaz
natural de usuario. Se basa en el ncleo del sistema operativo Windows CE y cuenta con
un conjunto de aplicaciones bsicas utilizando las APIs de Microsoft Windows.
18
Un diseo moderno, prctico, atractivo y con caractersticas innovadoras lo convierte en un
sistema moderno y capaz de competir con los ms grandes.

Sin embargo la variedad de mviles con Windows Phone no es tan amplia como la que
ofrecen Android o Symbian. Por otra parte, al llegar ms tarde que sus competidores posee
menor cantidad de aplicaciones disponibles.

1.4.3 Symbian OS

Es un sistema operativo mvil que nace de la alianza de varias empresas de telefona


mvil, actualmente est mantenido por la consultora Accenture.

Symbian ha sido siempre fiable e innovador. Con fuerte nfasis en las funciones bsicas de
telefona y multimedia de sus dispositivos, tambin cuenta con un amplio mercado de
aplicaciones externas y con una tremenda variedad de dispositivos disponibles.

Se trata de una excelente opcin para conseguir terminales de gama media y baja, debido a
su fiabilidad, una cantidad razonable de buenas aplicaciones, posibilidades multimedia y al
precio asequible de muchos de sus modelos.

Lamentablemente Symbian ha perdido protagonismo con la llegada de iPhone y Android,


sobre todo en los smartphones punteros. No se puede comparar la cantidad de aplicaciones
con las de la competencia. Se ha confirmado de forma oficial que Symbian tendr soporte
hasta el ao 2016, por no ser un competidor de Android, iOS o Windows Phone.

1.4.4 BlackBerry OS

El BlackBerry OS es un sistema operativo mvil multitarea desarrollado por Research In


Motion para sus dispositivos BlackBerry. El sistema permite multitarea y tiene soporte para
diferentes mtodos de entrada adoptados por RIM para su uso en computadoras de mano,
particularmente la trackwheel, trackball, touchpad y pantallas tctiles. RIM usa un kernel
propio que al igual que Android, tiene un motor Java.

Con una interfaz sencilla el SO BlackBerry est claramente orientado a su uso profesional
como gestor de correo electrnico y agenda. Blackberry destaca tambin por los aspectos
de seguridad y por sus teclados QWERTY que al estilo de un teclado de PC, permiten una
escritura muy rpida.

19
No obstante la tienda de aplicaciones no es comparable con las de Android o iPhone.
Tampoco existen tantas posibilidades de eleccin en cuanto a dispositivos y el potencial
multimedia no es su fuerte principal.

1.4.5 Android

Android, es el nombre con el que se denomina al SO para dispositivos mviles


desarrollado por la Open Handset Alliance (una alianza de empresas comandada por
Google y en las que participan organizaciones tales como: Motorola, Samsung, HTC, LG,
Sony Ericsson, entre otras).

Figura 4. Logotipo y robot mascota de Android

Originalmente creado para dispositivos mviles, posteriormente expandi su desarrollo


para soportar otros dispositivos tales como tablets, reproductores MP3, netbooks, PCs e
incluso televisores.

Como Android es un sistema escrito en cdigo abierto, los fabricantes de dispositivos


mviles apenas se han encontrado trabas a la hora de recurrir a esta plataforma. Pueden
fabricar dispositivos para todos los bolsillos y modificar Android para ajustarlo a la
potencia del procesador. Es decir Android no es un sistema exclusivo sino que puede
incorporarse a muchos terminales.

Pero Android es mucho ms que un sistema operativo, es tambin un lenguaje de


programacin y un framework para desarrollo de aplicaciones. Es decir, que al conjunto de
todos esos elementos se lo llama Android.

Se trata de un SO multitarea basado en una navegacin en iconos y escritorios con una


interfaz agradable y sencilla. Es completamente personalizable y cuenta con un gran
nmero de aplicaciones disponibles, destacando las de la propia Google.

20
Otro punto a favor de Android es la increble confianza que est recibiendo de los
fabricantes. Gracias a ello, la oferta de telfonos con Android es amplia y la oferta es
variada tanto en marcas como en precios.

Hoy en da uno de los aspectos negativos de Android es su fragmentacin, aunque va


mejorando actualizar el sistema operativo a nuevas versiones no es tan fcil.

1.5 Por qu Android?

Al investigar las plataformas mviles para ver cul se adapta ms a las necesidades del
proyecto, hemos visto que Blackbery OS est orientado a las comunicaciones sociales, que
Symbian OS est en vas de extincin y que Windows Phone ha llegado tarde y an le falta
para despegar, as que dudamos entre Android e iOS.

Desde la perspectiva de desarrolladores de software escoger la plataforma adecuada


es de vital importancia, basando la eleccin normalmente en el pblico potencial que
podra descargar el producto.

Android es el sistema operativo ms extendido en el mundo en los dispositivos mviles por


delante de sus competidores y las cifras indican que Android crece ms rpido.

En la figura 5 podemos observar la cuota de mercado de los sistemas operativos mviles a


fecha de Noviembre del 2011, segn un estudio de Millennial Media.

Figura 5. Comparativa de SO mviles.


21
Adems Android nos ofrece muchas otras ventajas respecto a sus competidores:

- No est atado a un nico fabricante de dispositivos.


- Es Open Source.
- El kit y herramientas de apoyo para desarrollar son gratuitas.
- Posibilidad de adaptar nuevos dispositivos.
- Tiene una gran comunidad de desarrolladores detrs.
- El nivel de personalizacin es mayor.
- Posibilidad de compartir los proyectos.
- Android est en alza, cada da hay ms usuarios y muchas empresas buscan
desarrolladores.

Otro gran inconveniente es que para desarrollar para iOS se necesita un Mac, y a la hora de
realizar este proyecto se persigue no invertir dinero en l.

22
2 Objetivos del Proyecto

El objetivo global de este proyecto de fin de carrera es desarrollar un videojuego para


entornos mviles, en este caso para el sistema operativo Android. Para ello se pretende
aprender sobre diseo y desarrollo de videojuegos y cmo funciona el sistema Android.

Tambin se busca crear un framework (un marco de trabajo, es una estructura con mdulos
definidos para afrontar prcticas similares) estndar para Android que sirva para afrontar
posibles futuros proyectos de forma ms rpida y cmoda.

Hay que tener en cuenta que los juegos para mviles son diferentes a los de sobremesa en
varios aspectos, as que existen otros objetivos que debemos tener en cuenta:

Que tenga una mecnica sencilla.


Las partidas sean cortas.
Que gestione las interrupciones de un mvil. Tener en cuenta que es para
smartphone.
Que sea multidispositivo.
Crear un framework estndar que sirva para afrontar futuros proyectos de
forma ms rpida y cmoda.

Al tratarse de un videojuego para mvil tenemos en cuenta que los jugadores pueden sufrir
dficit de atencin, es decir juegan en el metro, autobs, en clase Esto nos lleva a pensar
en un juego de mecnica sencilla y creemos que lo mejor es crear un juego del tipo
rompecabezas.

El tiempo de juego no lo elige el usuario, buscaremos intencionadamente que las partidas


tengan un ritmo rpido y que el tiempo entre partida y partida sea corto, para suscitar al
jugador a intentar batir la puntuacin mxima, es decir queremos que nuestro juego tenga
una dinmica rpida, sencilla y adictiva.

As mismo es muy importante hacer que el videojuego se adapte y funcione en la mayora


de terminales distribuidos. Para hacer la aplicacin multidispositivo, es necesario, en un
principio, adaptarse al tamao de la pantalla. Crearemos unos grficos originales y simples
para que funcione bien en todos los dispositivos.

23
Debemos tener en cuenta al jugar que puede haber interrupciones, llamadas, mensajes
queremos que nuestro juego sea capaz de interrumpirse y volver a su estado donde lo dej.

As mismo otro objetivo que nos marcamos desde el principio es no invertir capital en este
proyecto.

2.1 Requisitos Funcionales

Nuestra aplicacin tiene varios requisitos principales:

Permitir que el usuario interacte con las pantallas y juegue con la aplicacin.
Debe poderse salir de la aplicacin en cualquier momento.
Ha de ofrecer al usuario la opcin de desactivar el sonido.
Tiene que gestionar las interrupciones del mvil.

2.2 Requisitos No Funcionales

La aplicacin se programar en Java, para dispositivos mviles con Android.


El juego se desarrollar para la versin 2.2 de Android. Por lo que tambin ser
compatible con versiones posteriores.
Se utilizar la versin de OpenGL ES 1.0 para los grficos.
El idioma de la aplicacin ser en espaol.
El uso de la aplicacin tiene que ser sencillo e intuitivo.
Nuestra aplicacin necesita el uso de almacenamiento externo para guardar los
datos de configuracin.

2.3 Requisitos de Rendimiento

Nuestra aplicacin podemos considerarla de tiempo real blando ya que establecemos unos
periodos que deben de cumplirse para una correcta funcionalidad de la aplicacin pero el
margen de error es flexible. Nos marcamos el objetivo de poder mostrar sesenta frames
(imgenes) por segundo. La aplicacin deber estar optimizada sobre el parmetro del
tiempo sacrificando el consumo de memoria principal.

24
3 Especificaciones del Videojuego.

En esta seccin describiremos la parte del diseo de especificaciones del juego.

3.1 Gnero i Objetivos del Videojuego.

Blocks es un videojuego tipo rompecabezas para un jugador. Es un clon de Bejeweled [2].


Bejeweled fue el primer juego desarrollado por PopCap Games, vendi ms de 5 millones
de unidades y fue nombrado el Mejor Juego de Puzzle del 2001.

El objetivo de nuestro juego es conseguir la mayor puntuacin posible. Para ello debemos
ir avanzando niveles antes que termine el tiempo, logrando eliminar un nmero
especificado de bloques en cada nivel.

Figura 6. Bejeweled.

3.2 Mecnica del Juego.

Es un juego con una mecnica simple y sencilla, eliminar bloques del mismo color de un
tablero, mediante la alineacin de tres o ms en una fila o columna.

Para eliminar los bloques deberemos intercambiar de posicin dos bloques que
estn en posiciones adyacentes (vertical u horizontalmente) de manera que formen
una lnea de al menos tres bloques del mismo color (las diagonales no cuentan). Si

25
intercambiamos dos bloques y no consiguen formar ninguna lnea de tres o ms,
stos volvern a su posicin inicial.
Una vez eliminados, si quedan casillas libres en el tablero por debajo de un bloque
este caer hacia abajo debido a la gravedad y en las casillas libres de la parte
superior del tablero aparecern nuevos bloques con color aleatorio. Si esto da lugar
a una nueva lnea de tres o ms, esta lnea tambin desaparece.
El juego termina al agotarse el tiempo. Habr en pantalla un indicador de tiempo
restante. Al avanzar de nivel el tiempo se restablece, pero como ms se avance, el
tiempo por nivel ser menor.
Para avanzar de nivel, debemos reunir el nmero mnimo de bloques especificado
que aparece en la parte superior de la pantalla. Este crece a cada nivel que
completemos. Decidimos no poner una escena de cambio de nivel para no cortar el
ritmo de juego, consiguiendo as que sea ms rpido.
Obtendremos puntos por cada bloque eliminado, as pues cuantos ms bloques
eliminemos ms puntos conseguimos.
Existe un bloque comodn que aparecer en el tablero aleatoriamente. Al pulsar
sobre l elimina todos los bloques de un mismo color, ste tambin ser aleatorio.
La Lupa es una ayuda que al pulsarla desataca un movimiento de bloques que
puede formar lnea. Obtendremos lupas al alcanzar cierta puntuacin.
Empezaremos el juego con dos y el mximo disponible sern tres.

3.3 Control del Juego.

Blocks se controla nica y exclusivamente mediante la pantalla tctil del dispositivo, de


forma sencilla e intuitiva. Pulsando y soltando los botones de los mens y distintas
pantallas y deslizando el dedo para intercambiar los bloques de posicin.

3.4 Pantallas.

En este apartado vamos a disear las pantallas y transiciones que habr entre ellas. Sin
embargo debemos comprender la finalidad de una pantalla:

Una pantalla es una unidad independiente que ocupa por completo el visor
del dispositivo y que es la responsable de una parte del juego. Por ejemplo,

26
ser la que se ocupe del men principal, de la ayuda del juego o de la pantalla
del juego donde tenga lugar la accin.
Una pantalla puede estar compuesta por varios componentes como por
ejemplo, botones, etiquetas, imgenes y los bloques que forman el tablero.
Una pantalla permite al usuario interactuar con los elementos del juego. Estas
interacciones pueden iniciar transiciones de pantalla. Por ejemplo al presionar
el botn Jugar.

Con estas definiciones pasamos a especificar las pantallas o escenas de nuestro juego, lo
primero que mostrar al lanzar la aplicacin ser el men principal.

3.4.1 Men Principal.

El juego arrancar con esta pantalla (figura 7) dnde veremos una animacin del logo
(rotacin y escalado) hasta conseguir su posicin correcta, debajo de ste unos botones
tctiles rectangulares:

- Jugar, que nos permitir empezar la partida


- Instrucciones, nos llevar a la pantalla que nos ensea como jugar al juego.
- Ranking, que muestra las nueve mejores puntuaciones del juego.

Figura 7. Pantalla Men Principal

Adems debajo de stos y en las esquinas inferior izquierda encontraremos un botn


circular con un icono de sonido, que al pulsarlo activa/desactiva el sonido del juego y
cambiar el icono segn el estado en que se encuentre.

27
Para salir del juego bastar con pulsar el botn atrs del dispositivo mvil en cualquier
momento.

3.4.2 Ayuda.

En esta escena encontraremos la informacin para jugar al juego, la dividiremos en varias


pantallas y explicada grficamente para no saturar al jugador.

En cada pantalla veremos una etiqueta que nos indique en que pantalla de ayuda nos
encontramos, es decir 1/3, 2/3 o 3/3.

Para movernos por las distintas pantallas habr uno o dos botones tctiles (segn en la
pantalla de ayuda que nos encontremos) en la esquina inferior derecha adelante y atrs,
para avanzar o retroceder. En la esquina inferior izquierda encontraremos un botn tctil
volver, que al pulsarlo nos llevar al Men principal.

En la primera pantalla explica como intercambiar bloques para formar lneas y conseguir
que desaparezcan, y como los superiores caen por gravedad.

En la segunda pantalla, mostramos la pantalla de juego y explicamos la interfaz del juego:


los indicadores, el botn de pausa y las lupas.

En la tercera pantalla explicamos las reglas del juego: cuando termina el juego, cmo
avanzas de nivel, si el tablero se queda sin movimientos, el bloque comodn

Figura 8. Pantalla Instrucciones

28
3.4.3 Ranking.

En la pantalla de ranking, aparece el ttulo ranking y debajo se nos mostraran las nueve
mejores puntuaciones ordenadas de mayor a menor. En la figura 9 podemos ver esta
pantalla.

En la esquina inferior derecha encontraremos un botn volver, que al pulsarlo nos llevar
al Men principal.

Figura 9. Pantalla Ranking

3.4.4 Preparado.

El juego no empezar inmediatamente, se le da algo de tiempo al usuario para que se


prepare. En esta escena aparece el tablero de juego, y una etiqueta en el centro de la
pantalla Preparado? La podemos ver en la Figura 10.

Figura 10. Pantalla Preparado.


29
Esta escena espera a que el usuario toque la pantalla para empezar la partida, llevndonos a
la escena Juego.

3.4.5 Juego.

Una vez iniciada la partida encontraremos las etiquetas que nos informan sobre el estado
del juego: en la parte inferior podremos observar el nivel en que se encuentra el jugador, y
el tiempo restante. En la barra superior aparecern las etiquetas con el nmero restante de
bloques a eliminar y la etiqueta con la puntuacin. Todas estas etiquetas irn cambiando a
medida que vayamos jugando.

En la barra de la derecha aparecern los iconos de los botones lupa, transparentes si no


estn disponibles y pintados si estn disponibles.

En la esquina inferior derecha de la pantalla veremos un icono tctil con el smbolo de


pausa, al pulsarlo nos llevar a la escena pausa.

Sobre el tablero veremos los bloques. En la figura 11 podremos observar una imagen de la
escena juego.

Figura 11. Pantalla Juego

Si el usuario hace una combinacin y el tablero se queda sin movimientos disponibles,


aparecer la escena No hay movimientos. Cuando el juego termine porque se agote el
tiempo, saltaremos a la escena fin de juego.

30
3.4.6 Pausa.

Esta pantalla se mostrar al pulsar el botn de pausa durante el juego, en ella veremos dos
botones tctiles:

- Continuar: para continuar la partida tal en el punto en que estaba.


- Salir: Que nos permite ir al men principal, terminando la partida actual.

Adems en la parte inferior izquierda se encontrar el botn tctil con el icono sonido, para
activar o desactivar el audio del juego.

En la figura 12 vemos una imagen de la pausa del juego.

Figura 12. Pantalla pausa

3.4.7 Fin de Juego.

En esta escena se mostrar al finalizar el tiempo de juego. Se compone del tablero en el


fondo, una imagen Fin de Juego y una etiqueta de texto con la puntuacin obtenida en la
partida. Si se consigue batir las anteriores mejores puntuaciones nos avisar que hemos
conseguido un nuevo rcord. Esta pantalla se muestra en la figura 13.

Saldremos de esta escena tocando la pantalla y nos llevar a la pantalla de Ranking.

3.4.8 No Hay Movimientos.

Aparece cuando no hay combinaciones posibles sobre el tablero. En esta veremos una

31
Figura 13. Pantalla Fin de Juego

etiqueta en la parte superior que nos avisa de que el tablero se ha quedado sin movimientos
disponibles, otra etiqueta en la parte inferior que nos avisa que se est generando un nuevo
tablero, y una cuenta atrs que al llegar a cero, nos conduce otra vez a la escena juego. La
podemos ver en la figura 14.

Figura 14. Pantalla no hay movimientos

3.4.9 Diagrama entre Pantallas

Hemos explicado las transiciones entre pantallas pero vamos a mostrarlas en un grfico
para hacernos una idea visual, lo podemos ver en la figura 15.

32
- Figura 15. Las pantallas de Blocks y sus transiciones
33
3.5 Sonido.

El sonido del juego sonar la primera vez que arranque la aplicacin. El usuario podr
desactivarlo y el juego recordar la preferencia del jugador para futuras ocasiones. El
volumen podr ajustarse con los botones laterales del dispositivo mvil.

Si el sonido est activado sonar la msica durante todas las escenas del juego. Los efectos
de sonido se producirn cuando tenga lugar alguno de estos eventos.

- Al pulsar sobre cualquier botn de la interfaz de usuario (jugar, pausa, sonido,


continuar, lupa).

- Al avanzar de nivel.

- Al obtener una lupa extra.

- Al eliminar bloques.

- Al intercambiar bloques y que no formen lnea.

- Al combinar bloques de modo que formen una lnea.

- Si combinamos bloques y no forman lnea.

- Al pasar de nivel.

3.6 Puntuacin.

Los puntos se obtienen asociando bloques, en concreto 10 puntos por bloque destruido, es
decir si asociamos 3 bloques sumaremos 30 puntos, si asociamos 4 sumaremos 40, y as
respectivamente. Cada 500 puntos el jugador obtendr una lupa extra.

34
4 Diseo

En el presente captulo se presentarn los detalles de diseo del proyecto, estudiaremos


cmo trabaja un videojuego, primero definiremos los requisitos de diseo y seguidamente
nos acercaremos a un modelo de diseo muy til. ste lo utilizaremos para separar el
funcionamiento por mdulos, entendiendo las tareas que implementa cada uno y sin
acercarnos an a los detalles de la implementacin. Encontraremos en este apartado la
creacin de los recursos necesarios para la interfaz visual y sonora de nuestro juego.

4.1 Estructura de un Videojuego

Desde un punto de vista general, un videojuego es una aplicacin grfica en tiempo real en
la que existe una interaccin explcita mediante el usuario y el propio videojuego. En este
contexto, el concepto de tiempo real se refiere a la necesidad de generar una determinada
tasa de frames o imgenes por segundo, para que el usuario tenga una sensacin continua
de realidad. Por otra parte, con interaccin se entiende a la forma de comunicacin
existente entre el usuario y el videojuego. Como ya hemos visto anteriormente, en nuestro
juego esta interaccin ser tctil mediante la pantalla del dispositivo.

Desde un punto de vista abstracto, una aplicacin grfica en tiempo real se basa en un
bucle donde en cada iteracin se realizan los siguientes pasos:

El usuario visualiza una imagen renderizada por la aplicacin en la pantalla o


dispositivo de visualizacin.
El usuario acta en funcin de lo que haya visualizado, interactuando
directamente con la aplicacin.
En funcin de la accin realizada por el usuario, la aplicacin grfica genera
una salida u otra.

4.2 Restricciones de Diseo

Vamos a disear nuestro juego para una resolucin de pantalla fija de 480x320.

35
En el diseo de la aplicacin deben primar los tiempos de respuesta sobre el consumo de
recursos de espacio como la memoria principal o secundaria. Esta es la principal
restriccin que tendr el diseo de nuestro videojuego.

4.3 MVC (Modelo Vista Controlador)

Usaremos el patrn de diseo MVC (Model-View-Controller) [3], para aislar la lgica de


la parte de presentacin (interfaz de usuario). Es un modelo muy til para facilitar la
evolucin por separado de sus aspectos, y adems los convierte en flexibles y reutilizables.

La interfaz grfica ser la View (vista), el bucle de eventos har de Controller (controlador)
y las estructuras de datos internas actuaran como Model (modelo).

Figura 16. Esquema MVC.

Para ello crearemos un framework bsico que facilite el proceso y la comunicacin con el
SO que se encuentra por debajo. Se divide en varios mdulos como veremos a
continuacin:

Entrada: Gestiona los Inputs del usuario, est relacionado con el gestor de ventanas.
Archivos I/O: Para guardar, recuperar los datos de nuestro juego que
almacenaremos en una unidad de disco.
Audio: carga y reproduce cualquier sonido que emita el juego.

36
Grficos: El responsable de cargar los grficos y dibujarlos en pantalla.
Gestor de ventanas: es el responsable de la creacin de una ventana y de copiarla en
la aplicacin de Android con elementos que permitan, por ejemplo, cerrarla o
detener/continuar el juego.

Figura 17. Esquema de un Framework bsico.

4.4 Entrada

Cuando el usuario toca la pantalla para interactuar con nuestro juego se produce un evento,
es el mdulo de entrada quien se encarga de gestionar estos eventos. Los registra y los
guarda.

La pantalla tctil puede generar tres tipos de eventos, en ellos se guarda adems la posicin
relativa y un ndice del puntero:

Tocar la pantalla.
Arrastrar el dedo, previamente se deber haber tocado la pantalla.
Levantar el dedo.

El teclado del dispositivo puede generar dos tipos de eventos, en stos se guarda el cdigo
de la tecla y a veces el carcter Unicode.

Tecla presionada: cuando se presiona una tecla.


Tecla sin presionar: cuando se deja de presionar una tecla.

Estos eventos slo los manejaremos para que no se sobrecargue la memoria haciendo saltar
al colector de basura, (lo veremos ms adelante).

37
4.5 Archivo de I/O

Este mdulo nos servir para leer y escribir datos en los archivos.

En nuestro caso nos interesar leer los que empaquetaremos durante la generacin de
nuestro juego, como por ejemplo, imgenes y archivos de audio.

Por otra parte usaremos la escritura para guardar las puntuaciones mximas, la
configuracin del juego y para guardar el estado del juego cuando se produzca una
interrupcin, de modo que el usuario pueda retomarlo all donde lo dej. Evidentemente el
mdulo debe ser capaz tambin de leer los datos que guardemos.

4.6 Audio

El mdulo de Audio se encargar de reproducir cualquier sonido de nuestro juego.


Diferenciamos aqu entre la msica y los efectos de sonido de nuestro juego.

Al reproducir msica slo lo haremos de un elemento a la vez, accederemos una vez al


disco. Usaremos un archivo comprimido en MP3 para reducir el espacio que ocupe el
archivo.

Cuando reproduzcamos efectos sonoros, los cargaremos en memoria para poder


reproducirlos simultneamente, procuraremos que sean archivos pequeos para que no
ocupen mucho. Usaremos el formato OGG.

El mdulo:

Proporcionar el modo de cargar los archivos de audio para reproducirlo


sobre la marcha o desde la memoria.
Controlar la reproduccin de los archivos de msica y sonido: inicio de
reproduccin, pausa, detener, bucle, volumen.

4.6.1 Obteniendo los Recursos

Como msica usaremos una meloda en formato mp3 que hemos descargado de internet.
Se llama The Whistle Song [4], es de licencia gratuita siempre que se cite al autor de la
misma.

Para los efectos de sonido, cogeremos prestados unos que hemos encontrado en internet.

38
4.7 Grficos

Este mdulo es el que se encarga de dibujar en la pantalla las imgenes de nuestro juego.

Tareas del mdulo:

Cargar las imgenes almacenadas en el disco y guardarlas en la memoria para


dibujarlas ms tarde.
Limpiar el la pantalla con un color, borrando cualquier contenido
almacenado.
Dibujar las imgenes que hayamos cargado al inicio en la pantalla. Queremos
dibujar la imagen completa o partes de ella.

Vamos a crear ahora nuestros recursos grficos, teniendo en cuenta que usaremos la
librera grfica OpenGL ES 1.0.

4.7.1 La Pantalla

Una vez especificadas las pantallas de nuestro juego debemos crear los recursos para
colocarlos en pantalla como los diseamos. Ya dijimos que usaremos una resolucin fija de
480x320. Pero veamos qu significa esto.

La pantalla se basa en una cuadrcula, donde cada cuadro es un pxel. Su posicin viene
determinada por dos coordenadas en nmeros enteros (ancho y alto).

Figura 18. Sistema de coordenadas de una pantalla.

El origen de coordenadas se encuentra en la esquina superior izquierda de la cuadrcula.


Los valores positivos del eje x apuntan hacia la derecha y los del eje y hacia abajo. La
cuadrcula de la pantalla es finita y las coordenadas que se encuentren fuera de estos

39
lmites estn fuera de la pantalla. El valor mximo que pueden adquirir las coordenadas
sern el ancho o alto de la pantalla menos 1. Esto es as porque el origen coincide con el
pxel que se encuentra al inicio del todo. Podemos ver el sistema de coordenadas de la
pantalla en la figura 18.

4.7.2 Creando los Recursos

En OpenGL ES las dimensiones de las texturas (alto y ancho) deben ser siempre potencia
de dos (32, 64, 128, 256, 512) Debemos tenerlo en cuenta a la hora de crear los recursos
grficos de nuestro juego.

El primer elemento que generamos son los botones que necesitaremos en las diferentes
pantallas. La figura 19 muestra todos los botones del juego. Tendr un tamao total de
196x128 pxeles. Slo tenemos una flecha, porque luego podremos girar las imgenes.

Figura 19. Botones del juego, cada uno tiene un tamao 64x64 pxeles.

Generamos ahora los elementos del men principal, el logo, los botones del men y el
Fondo, en realidad ste lo usaremos tambin en la pantalla de puntuaciones, en la de juego
y para generar las pantallas de ayuda y de juego.

Figura 20. Logo del juego. 300x80 pxeles.

El fondo tendr un tamao de 480x320 pxeles (consiste en un degradado de color).


Nuestros botones de men miden 128x196 pxeles (figura 21) y el logo 300x80 pxeles
(figura 20). Aunque en principio no encajan en potencias de dos, ms tarde veremos como
los tratamos.

40
Figura 21. Botones del men principal, 128x64 pxeles cada uno.

A continuacin generamos las pantallas de ayuda, en vez de recurrir a los elementos,


generamos las imgenes directamente a pantalla completa en la resolucin establecida,
para reducir el cdigo responsable del dibujo.

Figura 22. Pantalla de Ayuda (Ayuda1.png) 512x512 pxeles.

Para la pantalla de puntuaciones mximas reutilizamos el fondo y la imagen del botn del
men principal que dice Ranking. Las puntuaciones las dibujaremos con un texto que
veremos ms adelante.

Figura 23. Imagen de juego. Es el fondo+tablero superpuesto (Juego.png). 512x512.


41
En la pantalla de juego dibujamos un tablero sobre el fondo que ya tenamos y lo
guardaremos en el archivo juego.png (figura 23). Adems esta pantalla incorpora ms
elementos de la interfaz de usuario, la etiqueta Preparado?, las entradas del men pausa
Continuar y Salir, la etiqueta Fin de Juego, y las lupas. Adems generaremos los textos de
Nivel, Puntuacin, Restantes y Tiempo que veremos ms adelante.

Figura 24. Etiquetas Preparado? Fin de Juego y botones del men pausa.

Finalmente generamos los botones lupa de 64x64 pxeles y los bloques de colores con un
tamao de 32x32 pxeles. Y la flecha de intercambio de bloques.

Figura 25. Botones Lupa 64x64pxeles cada uno,

Bloques 32x32 pxeles cada uno y Flecha 64x32 pxeles.

Para crear estos recursos grficos se ha utilizado el programa de edicin Gimp [5] que tiene
licencia de distribucin gratuita.

4.7.2.1 Trabajar con Texto Empleando Fuentes Bitmap.

Para dibujar texto en pantalla emplearemos una fuente bitmap. Una fuente bitmap contiene
unas imgenes que corresponden a un rango de caracteres ASCII. A cada carcter se le
conoce como glifo. Todos tienen un tamao fijo de 16x20 pxeles. Nosotros slo usaremos
los caracteres ASCII que se pueden imprimir. Los podemos ver en la figura 26.
42
Figura 26. Imagen Fuente bitmap.

La primera fila contiene los caracteres comprendidos entre 32 y 47, la segunda del 48 al
63, etctera. hasta el 127.

Usaremos Bitmap Font Generator (de Codehead) [5] para generar nuestra textura de
fuentes bitmap. Es una aplicacin gratuita.

Figura 27. Tabla con los caracteres ASCII y sus valores decimales.

Crearemos 96 regiones de la textura y cada una contendr un glifo. En java los caracteres
se codifican usando Unicode, que tienen los mismos valores que ASCII.

43
Para coger la regin que nos interesa en nuestro mapa de caracteres, primero obtenemos el
ndice en el array dnde guardamos las regiones, restando el carcter espacio (32) al
carcter que queremos. Si el ndice es menor de 32 o mayor de 95, tendremos un carcter
que no est incluido en nuestra fuente bitmap, por tanto lo ignoraremos.

4.7.2.2 Mapa de Texturas.

Ya hemos creado todos los recursos grficos de nuestro juego. Podramos tener muchas
texturas, cada una conteniendo la imagen de un tipo de objeto, bloques, botones, etc. Pero
OpenGL ES debe cambiar la textura cada vez que cambie de objeto. Para mejorar el
sistema de trabajo colocaremos todas las imgenes en una, esta ser el mapa de texturas.

En la figura 28 vemos el mapa de texturas de nuestro juego.

Figura 28. El mapa de texturas (Items.png) 512x512 pxeles.

44
As slo tendremos que asociarla una vez y podremos dibujar cualquier tipo de objeto que
tenga su imagen correspondiente en este mapa. Nos ahorraremos cambios de estado en
OpenGL ES mejorando as el rendimiento de nuestro programa. La llamaremos Items.png
y tendr un tamao de 512x512 pxeles, que adems s es potencia de dos.

La cuadrcula no forma parte de la imagen, y los pxeles de fondo son transparentes. El


tamao de las celdas de la cuadrcula es de 32x32 pxeles. Se han colocado las imgenes en
las esquinas del mapa casi todas las coordenadas son mltiplos de 32, para que sea ms
fcil crear regiones en la textura.

4.8 Gestor de Ventanas

El sistema operativo Android emplea ventanas, la ventana en nuestro juego har de


contenedor. Pensemos en ella como un tapiz dnde dibujaremos el contenido de nuestra
aplicacin.

Nuestro videojuego trabajar slo con una nica ventana. Esto es as para tener control
absoluto sobre el aspecto de nuestro juego y poder centrarnos en la programacin del juego
y no en la interfaz de usuario de Android (cada vez que se cambia la orientacin del
dispositivo se destruye y se crea una nueva superficie de dibujo). Esto significa que en esta
ventana iremos presentando las distintas pantallas de nuestro juego.

Podramos afirmar que el gestor de ventanas es el mdulo principal, ya que en l


enlazaremos el resto de mdulos y los intercomunicaremos para que funcionen como se
espera.

Las tareas del mdulo son:

La ventana trabaja con una interfaz de usuario (IU), para permitir a ste que
interacte con la pantalla.
Llevar a cabo la configuracin de la ventana (tamao, posicin y evitar que se
bloquee) y asegurarse que slo usa un nico componente IU para rellenarla.
El gestor de ventanas es el enlace con los otros mdulos del juego. Debe garantizar
el acceso a stos para poder cargar recursos, hacerse cargo de las entradas del
usuario, reproducir sonidos, dibujar los elementos, etctera.
Se encarga de que la pantalla se actualice y dibuje tantas veces como sea posible.
45
Llevar un registro de estado de la ventana e informar a la pantalla de estos eventos
(si el juego est detenido o reanudado).
Lo utilizaremos tambin para ver el rendimiento de nuestro juego (medir los
Frames por segundo).

4.9 Framework

En conjunto todos estos mdulos definen el framework o marco de nuestro juego. Estos
son re-aprovechables para posibles trabajos futuros, pues hemos visto que estn separados
mediante el patrn MVC. Ahora que ya hemos examinado que tareas lleva a cabo cada
mdulo vamos a comprender como funciona todo esto en pseudocdigo ignorando algunos
elementos que ahora no nos interesan.

crearVentanaYComponenteIU ();
Input entrada = new Entrada ();
Graficos graficos = new Graficos ();
Audio audio = new Audio ();
Pantalla pantallaActual = new MenuPrincipal ();
Mientras ( !usuarioNoSaleJuego () ){
pantallaActual.actualizaEstado (entrada);
pantallaActual.dibuja (graficos, audio);

borrarRecursos ();

4.10 Lgica del Juego

Aunque no lo consideremos un mdulo, veamos aqu la lgica del juego. Establece el


comportamiento del juego y se encarga de su correcto funcionamiento.

Almacenaremos un tablero con los bloques, el tiempo, el nivel en que nos encontramos,
los puntos y los bloques restantes a eliminar para avanzar de nivel.

Adems la lgica de nuestro juego deber llevar a cabo las siguientes tareas:

Necesitaremos generar un tablero aleatoriamente.


Saber si existen combinaciones de bloques disponibles.
Intercambiar bloques
Comprobar si hay combinacin, eliminando los correspondientes bloques.
46
Aplicar la gravedad a los bloques superiores, una vez eliminados los bloques
combinados y rellenar los huecos del tablero.
Actualizar el estado en que se encuentre el jugador, tiempo, puntuacin

47
48
5 Desarrollo.

Una vez definidas las especificaciones y el diseo de nuestro proyecto, nos queda el paso
ms importante, implementarlo. Aqu surge la primera dificultad al no contar con
experiencia previa programando con Android, ni OpenGL.

Dado que para entender correctamente el trabajo realizado se necesitan unos


conocimientos bsicos, empezaremos este captulo introduciendo aquellos conceptos
indispensables para entender correctamente el desarrollo llevado a cabo.

Posteriormente detallaremos el desarrollo del proyecto. Veremos cmo hemos estructurado


nuestro proyecto y conoceremos en detalle el funcionamiento de los distintos mdulos
descritos, con sus clases y su implementacin.

5.1 Conociendo Android y OpenGL.

En este apartado describiremos la instalacin de los recursos utilizados, la arquitectura del


Sistema Operativo Android, cmo se construye una aplicacin Android y la estructura de
un proyecto.

Luego veremos qu es y cmo trabaja OpenGL ES 1.0.

5.1.1 Preparando las Herramientas.

Recordemos que el sistema operativo Android se basa en el lenguaje de programacin


Java. Por tanto, necesitamos el intrprete de java (JDK). [7]

Tambin instalamos Eclipse que ser nuestro entorno de trabajo, desde l compilaremos y
ejecutaremos el cdigo de manera cmoda. [8]

Para programar aplicaciones para el SO Android necesitamos adems el kit de desarrollo


Android SDK, disponible en la pgina web de Android en la seccin de descargas. [9]

Una vez instalado el SDK, veremos las carpetas de la figura 29.

En SDK Manager se mostraran todos los paquetes a instalar. Aparecen todos los SDK (Kit
de desarrollo de software) hasta la fecha. Descargamos los SDK necesarios y tambin

49
descargamos los Google USB divers, en el apartado Extras, necesario para conectar
dispositivos mviles y probar la aplicacin en stos.

Figura 29. Carpeta instalacin herramientas SDK Android.

Con AVD Manager podremos crear mquinas virtuales que nos permitirn ver la
aplicacin en funcionamiento.

Una vez instaladas las herramientas necesarias vamos a configurar el plugin ADT Android
Developer Tools, que nos permite una completa integracin entre las dos herramientas.

Se instala directamente desde Eclipse, aadiendo una ruta en la pestaa Help - Install New
Software. [10]

5.1.2 Arquitectura del Sistema Operativo Android.

La arquitectura interna de la plataforma Android, est bsicamente formada por una serie
de componentes. Cada uno de ellos se basa en los elementos de la capa inmediatamente
inferior. La figura 30 ofrece un esquema de los principales componentes de Android.

Kernel de Linux: Comenzando por la capa de abstraccin ms cercana al hardware se


encuentra el ncleo, o kernel, de Linux. Esta parte proporciona unos servicios muy
importantes relativos a la seguridad, la memoria, los procesos, la red y los modelos de los
drivers (controladores de dispositivos).

Runtime de Android: se encuentra encima del kernel y es el responsable de reproducir y


ejecutar las aplicaciones Android. Cada una de ellas ejecuta su propio proceso a travs de
la mquina virtual Dalvkit. Dalvkit integra tambin un recolector de basuras (GC), con el
que habr que tratar ms adelante.

Libreras: Android incluye en su base de datos un set de libreras C/C++ , que son
expuestas a todos los desarrolladores a travs del framework de las aplicaciones Android
Se encargan de las tareas de clculo pesadas, como dibujo de grficos, reproduccin de
audio, acceso a base de datos.
50
Figura 30. Arquitectura Android

Framework de aplicaciones: asocia las libreras del sistema y el tiempo de ejecucin,


originando la parte del usuario de Android. Tambin gestiona las aplicaciones y
proporciona un marco de trabajo para stas. Los desarrolladores tienen acceso total al
cdigo fuente usado en las aplicaciones base. Esto ha sido diseado de esta forma, para que
no se generen cientos de componentes de aplicaciones distintas, que respondan a la misma
accin, dando la posibilidad de que los programas sean modificados o reemplazados por
cualquier usuario sin tener que empezar a programar sus aplicaciones desde el principio.

Aplicaciones: Todas las aplicaciones de la plataforma Android, han sido creadas con el
framework. Entre ellas encontramos un cliente de email, calendario, programa de SMS,
mapas, navegador, contactos, y algunos otros servicios mnimos. Todas ellas escritas en el
lenguaje de programacin Java.

5.1.3 Arquitectura Aplicacin

Debido a la filosofa utilizada por Android los elementos de una aplicacin pueden ser
utilizados por otras, si stas lo permiten. Para conseguir esto, el sistema debe ser capaz de

51
ejecutar un proceso de una aplicacin cuando una de sus partes lo necesite. Es por ello que
al contrario que la mayora de las aplicaciones en otros sistemas, las aplicaciones en
Android no tienen un solo punto de entrada para todo, es decir no hay por ejemplo una
funcin main(). En vez de ello los componentes esenciales de la aplicacin pueden ser
iniciados cuando se necesiten.

Los bloques que pueden constituir una aplicacin son los siguientes:

- Activity: Representa una interfaz grfica para una accin que el usuario puede
realizar. Acta como lo que comnmente se conoce como formulario. En
una Activity se colocan los elementos de la interfaz grfica.
- Services: Son lo que comnmente se conocen como procesos. Invisibles para
el usuario, carecen de interfaz grfica. Por ejemplo para reproducir msica de
fondo.
- Intents: Es un mecanismo para comunicar a las distintas aplicaciones y
Activities. Un Intent es un mensaje de llamada asncrono. Android est
desarrollado sobre la base de reutilizar cdigo y aplicaciones existentes, es
por eso que esta caracterstica es tan importante.
- Broadcast Recivers: Se utilizan para que una aplicacin responda a un evento
especfico del sistema. Al igual que los servicios no poseen interfaz grfica.
Por ejemplo se puede utilizar un Broadcast Reciver en un programa para que
cuando el telfono se est quedando sin batera se muestre un mensaje
advirtiendo al usuario sobre su utilizacin.
- Content Providers: Es el mecanismo encargado de administrar la informacin
que se pretende que perdure. Se puede utilizar para compartir informacin
entre aplicaciones.

5.1.3.1 La pila de Actividades

Como hemos explicado una actividad o activity, es el componente principal de una


aplicacin. Cada activity, implementada como una clase subclase de Activity, representa
una pantalla de la aplicacin con interfaz de usuario. Una aplicacin con varias actividades
tiene una pila de actividades. Cada vez que iniciemos una nueva, se colocar en dicha pila.
Cuando pasamos de una a otra, se aaden en una pila de actividades (si no la eliminamos)
y en caso de que se destruya la activity actual (por ejemplo si se aprieta la tecla de
52
retroceso), se realiza un pop (retira la ltima actividad) de la pila y se vuelve a la anterior.
Podemos ver un ejemplo en la figura 31.

Figura 31. Ejemplo de cmo funciona la pila de Actividades en Android.

Para pasar de una activity a otra, se utiliza la clase Intent, en la que indicamos la activity
origen y la activity destino. Tambin podemos utilizar el apartado Extras del Intent para
pasar informacin entre activities.

Todas las actividades de la aplicacin, tanto las que se encuentran en la pila en modo
pausado como la que est activa, comparten la misma mquina virtual y la misma porcin
de memoria.

Nuestro juego slo tendr una actividad, para controlar la visualizacin de ste, sin
embargo debemos entender cmo trabaja la pila de Actividades antes de empezar a
programar para Android.

5.1.3.2 Ciclo de Vida de una Aplicacin Android

Como se ha explicado anteriormente una aplicacin no solo tiene un punto de entrada para
todos los acontecimientos, por ello no se puede declarar el ciclo de vida de una aplicacin
en general, sino que hay que tener en cuenta el comportamiento de cada uno de sus
componentes: activities, services y broadcast recivers.

Una actividad puede encontrarse en tres estados diferente:

53
Activa: cuando est en primer plano de la pantalla. Esta actividad tiene el foco e
interacta con el usuario.
Pausada: ha perdido el foco pero es an visible para el usuario, es decir, existe una
actividad por encima de ella de modo transparente o no, ocupando la pantalla
entera, tambin cuando se bloquea la pantalla del telfono. La actividad pausada
mantiene la informacin pero debemos tener cuidado, pues el sistema puede decidir
cerrarla sin previo aviso en caso de falta de memoria.
Parada: la actividad ha sido cubierta completamente. Mantiene su estado y la
informacin pero el sistema puede eliminarla sin avisar cuando necesite ms
memoria.

En la figura 32 vemos los estados de una Actividad, stos debern sobrescribirse para
controlar la aplicacin.

Figura 32. Ciclo de vida de una Actividad.


54
El ciclo de vida de la Actividad empieza en onCreate, cuando se crea la activity por
primera vez y finaliza en onDestroy dnde la actividad se destruida irreversiblemente.
Durante este tiempo puede tener o no el foco, pasando por diferentes estados.

El mtodo onResume es llamado siempre, antes de que la activity entre en estado running.

La activity puede ser destruida silenciosamente tras onPause. Aqu tendremos que guardar
los datos persistentes, podemos llamar al mtodo isFinishing para comprobar si nuestra
activity va a ser eliminada.

Para nuestro juego:

En onCreate(): crearemos ventana, definiremos la interfaz de usuario (UI) desde donde


recibiremos las entradas de ste.

En onResume(): iniciamos o reiniciamos el hilo principal.

En onPause(): Pausaremos el hilo principal y si el mtodo isFinising() nos devuelve true,


guardaremos los estados en el disco para no perder la informacin.

5.1.4 Estructura de una Aplicacin Android

Al crear un nuevo proyecto Android en Eclipse se genera automticamente la estructura de


carpetas necesaria para poder generar posteriormente la aplicacin, vamos a echarle un
vistazo para entender cmo se construye una aplicacin Android.

En la figura 33 vemos los elementos creados inicialmente para un nuevo proyecto Android.

Figura 33. Estructura de un proyecto Android.

Carpeta / src /

Contiene el cdigo fuente de la aplicacin, aqu se encuentran los distintos paquetes que
contienen las clases Java que forman la aplicacin.

55
Carpeta / res /

Contiene todos los archivos de recursos necesarios para el proyecto: imgenes, vdeos,
cadenas de texto, etc. Los diferentes tipos de recursos se debern distribuir entre las
siguientes carpetas:

/ Es / drawable /. Contienen las imgenes que sern dibujadas para la interfaz


de usuario. Se puede dividir en / drawable-ldpi, / drawable-MDPI y /
drawable-hdpi para utilizar diferentes recursos dependiendo de la resolucin
del dispositivo.
/ Es / layout /. Contienen las plantillas de las distintas vistas en formato
XML.
/ Es / values /. Contiene otros recursos de la aplicacin como cadenas de
texto (strings.xml), estilos (styles.xml), colores (colors.xml), etc.

Carpeta / gen /

Esta carpeta generada automticamente contiene las referencias de los distintos elementos
creados. Se actualizan automticamente y no deben ser modificados de forma manual. Ver
la Figura34.

Figura 34. Estructura carpeta gen.

La clase R.java se trata de un archivo fuente para el manejo de recursos que no debemos
editar. La clase R contendr en todo momento una serie de constantes con los ID de todos
los recursos de la aplicacin incluidos en la carpeta / res /, de manera que podamos acceder
fcilmente a estos recursos desde nuestro cdigo a travs de este dato. As, por ejemplo, la

56
constante R.drawable.icon contendr la identificacin de la imagen icon.png contenida
en la carpeta /nada / drawable /.

Carpeta / assets /

Contiene todos los archivos de recursos necesarios para la aplicacin (no sern
compilados), como archivos de configuracin, de datos, audio, imgenes etc. Para nuestro
juego crearemos tres subcarpetas fx, imgenes y music, dnde almacenaremos nuestros
recursos.

Archivo AndroidManifest.xml

Es el archivo de configuracin principal de la aplicacin, contiene la definicin en XML de


los aspectos de la aplicacin,

Las principales funciones del Android Manifest son:

- Describe los paquetes Java para la aplicacin. Cada paquete tiene un


identificador nico para la aplicacin.
- Detalla los componentes de la aplicacin: actividades, servicios, receptores de
difusin y proveedores de contenido. Relaciona cada una de las clases
correspondientes a cada componente. Mediante esta declaracin el sistema
sabe qu componentes pueden ser lanzados bajo qu condiciones.
- Especifica que procesos mantendr los componentes de la aplicacin.
- Declara los permisos que necesita la aplicacin para acceder a partes
protegidas de las API.
- Se especifican tambin los permisos que se deben tener para interactuar con
los componentes de esta aplicacin.
- Especifica el level mnimo que debe tener la API de Android para hacer
funcionar la aplicacin.
- Describe las bibliotecas que la aplicacin debe enlazar

5.1.5 Rendimiento, el Recolector de Basura y Jit.

Java nos impide reservar o liberar memoria, para ello utiliza el Garbage Collector (GC).
Cuando llega a una cantidad de memoria reservada decide liberarla si es posible. Esto
presenta algunos problemas de rendimiento ya que a cada iteracin en que se ejecute el GC
detiene todo de 100 a 300 milisegundos. Esto significa que durante casi medio segundo en
57
nuestro juego no podremos dibujar en pantalla ni actualizar. Para evitarlo disearemos la
aplicacin evitando la generacin de objetos y destruccin de stos.

Android 2.2 incluye JIT (Just In Time Compilation) que incrementa el rendimiento de las
aplicaciones. Dalvik se comporta como un intrprete, es decir, a medida que va leyendo el
cdigo lo va ejecutando, con JIT Compilation, se convierten secciones completas de
cdigo en cdigo ejecutable por el procesador real, que se ejecutar sin ms interrupciones,
acelerando as la ejecucin de dicho cdigo. [11]

Figura 35. Icono JIT.

En nuestro juego prima el rendimiento sobre el uso de la memoria, teniendo en cuenta esto
recurriremos a mtodos que en programacin no estn muy bien vistos. (Mtodos statics,
variables statics, no llamaremos excesivamente a funciones (getters y setters) etc.) que
nos permitirn ahorrar algunos milisegundos.

Sobre el rendimiento de los videojuegos podemos encontrar mucha ms informacin en las


transparencias de la conferencia de Google IO 2009 de Chris Pruett de Writing Real Time
Games Android. [12]

5.1.6 El problema de la Fragmentacin

Uno de los problemas de Android es la fragmentacin, es decir ofrece diferentes


dispositivos con distintos tamaos y densidades de pantalla. Entendemos por densidad
como la cantidad de pixeles en un rea, es decir una imagen de 100100 pixeles se ver
ms pequea en una pantalla con densidad mayor. Lo podemos apreciar en la figura 36.

Ya hemos diseado los recursos para una la resolucin de 480x320 pxeles, nos
encargaremos de que OpenGL ES modifique la escala de la salida en pantalla para ajustarla
automticamente a la ventana de visualizacin segn el tamao y densidad de sta, pero

58
deberemos transformar las coordenadas del punto de contacto del dedo con la pantalla para
convertirlas a nuestra resolucin fija.

Figura 36. Los mismos elementos con tamao fijo en pantallas de distintas densidades

5.1.7 OpenGL ES 1.0

OpenGL ES (Open Graphics Library for Embedded Systems) es una variante simplificada
de la API grfica OpenGL diseada para dispositivos integrados tales como telfonos
mviles, PDAs y consolas de videojuegos.

Fue creada por el Grupo Khronos, un consorcio de empresas dedicadas al hardware y


software grfico. La versin 1.0 est basada en OpenGL 1.3 [13].

Todos los dispositivos Android son compatibles con OpenGL ES 1.0.

OpenGL es una librera de funciones que pueden usarse para dibujar escenas 2D o 3D a
partir de primitivas geomtricas simples, tales como puntos, lneas y tringulos.

Figura 37. Logotipo OpenGL ES.

Vamos a ver cmo funciona esta librera de renderizado, y conocer la estructura bsica de
un motor grfico 2D. A diferencia de usar un motor grfico ya creado, esta opcin nos
permite controlar exactamente lo que necesitamos en nuestro juego, de tal manera que
podramos adaptarlo ms adelante segn nuestras necesidades.

Antes de comenzar a ver cmo funciona OpenGL es conveniente asegurar algunos


conceptos bsicos acerca de los grficos en 3D, ya que OpenGL trabaja con stos.

59
5.1.7.1 Como se Representa una Escena

Los objetos reales poseen tres dimensiones: altura, anchura y profundidad. Para que estos
objetos puedan representarse en una pantalla que tiene dos dimensiones, tenemos que
transformar la informacin visual del objeto original para producir la ilusin de ver un
objeto tridimensional en un sistema bidimensional.

Para posicionar los objetos OpenGL trabaja con un sistema de coordenadas cartesianas, los
ejes: X, Y, Z. De tal forma que dos a dos son perpendiculares. Los ejes X e Y representan
la posicin horizontal y vertical respectivamente, y el eje Z representa la profundidad.

Trasladndolo al monitor de un ordenador, el eje X se extiende a lo ancho, el Y a lo alto, y


el Z se dirige hacia el observador desde el centro de la pantalla. Figura 38.

Figura 38. Sistema de coordenadas OpenGL

Pensemos en una habitacin vaca con una mesa en el centro, y una pelota que va
rebotando por la habitacin. Nosotros sacamos fotografas con una cmara (en 2D).
Aunque los objetos de la escena se estn moviendo, al presionar el botn de disparo la
cmara captura una imagen esttica y segn en qu posicin estemos (nosotros y los
objetos) la fotografa tendr una composicin u otra. Ver Figura39.

Figura 39. Fotogramas de una pelota rebotando.

Como tenemos un espacio definido gracias al sistema de coordenadas podemos posicionar


los objetos (modelos) y la cmara dentro de l, simplemente con especificar el punto en el
donde lo deseamos colocar.
60
Resumiendo OpenGL traslada las coordenadas tridimensionales (de los objetos) a
coordenadas bidimensionales a travs de la proyeccin de los objetos (sus puntos) en la
ventana de trabajo (fotografa).

5.1.7.2 Proyecciones

Para nuestro juego usaremos la proyeccin paralela, que es til para juegos 2D. En este
tipo de proyeccin no se tiene en cuenta la distancia entre el objeto y la cmara, es decir,
dos objetos con el mismo tamao se ven igual en la pantalla, independientemente que de
uno est ms alejado del punto de vista del observador. Por otra parte si un objeto no entra
en el espacio de trabajo no se dibuja. En la Figura 40 podemos ver los planos de
proyeccin.

Figura 40. Tipos de proyecciones.

Trabajaremos con un plano de proyeccin, podemos verlo en la figura 41. Todos los
objetos que se encuentren dentro de la caja sern visibles, todos los que estn fuera, no lo
sern. Es decir se lanza la proyeccin de los puntos (de los objetos), hacia el plano de la
cmara y si estn fuera de esta caja (planos de corte) no aparecen en la fotografa. El plano
donde se proyectan se conoce como plano de recorte cercano o plano de proyeccin y
tiene su propio sistema de coordenadas 2D.

En realidad nuestra vista de proyeccin ser plana, es decir no tendr eje z, porque
trabajaremos en 2D.

61
y

z
x

Figura 41. Plano de proyeccin paralela. Volumen de vista y planos de corte.

5.1.7.3 Matrices

OpenGL expresa las proyecciones a travs de matrices, que son las que se encargan de
generar los puntos que definimos en nuestra escena.

Una matriz codifica las transformaciones que se deben aplicar a un punto. Puede ser una
proyeccin, una traslacin (desplazamiento), una rotacin, modificacin de escala o
cualquier otra cosa. Al multiplicar una matriz por un punto, aplicaremos la transformacin
a dicho punto.

Matriz Modelo-Vista: la usaremos para mover los bloques. En vez de mover


manualmente las posiciones de los vrtices, empleamos esta matriz para dibujar
nuestro modelo, moviendo su origen de coordenadas hasta la ubicacin que
especificamos.
Matriz proyeccin: la que acta como cmara.

5.1.7.4 Sobre Vrtices y Tringulos

Como ya hemos visto OpenGL trabaja con puntos para definir los modelos (objetos). Los
modelos se crean a partir de tringulos, que a su vez estn definidos por 3 puntos, se les
llama Vrtices.

A partir de estos tringulos se generan las formas geomtricas que queramos representar. A
nosotros nos interesa el rectngulo, que ser la unin de dos tringulos.

Para ello usaremos dos tringulos que tengan 2 vrtices en la misma posicin. Pero en vez
de duplicar los vrtices usaremos slo uno de los que comparta coordenadas y a la hora de

62
dibujar indicaremos que vrtices debe usar para formar cada tringulo. Esto se llama
indexar vrtices. Podemos verlo en la figura 42.

Figura 42. Dibujar un rectngulo con seis vrtices (izquierda) o con cuatro (derecha).

El tringulo superior estar formado por los vrtices v1, v3 y v4, y el inferior por v1, v2, v3.

Indexar vrtices nos permite evitar la duplicacin de cdigo y mejorar el rendimiento


porque OpenGL ES no tendr que trabajar con ms vrtices de los estrictamente
necesarios.

5.1.7.5 Enviar Vrtices a OpenGL ES

OpenGL Es espera que le enviemos los vrtices como un array, pero como OpenGL es una
API de C no podemos recurrir a los array estndar de Java, usaremos los bfer NIO [14] de
Java, que son bloques de memoria consecutivos que se asignan en la memoria del sistema,
no en la mquina virtual.

5.1.7.6 Texturas en OpenGL

Para convertir un mapa de bits en un rectngulo tendremos que aadir las coordenadas de
la textura a cada vrtice. Qu son las coordenadas de las texturas? Las que especifican un
punto dentro de la textura (mapa de bits) que deber convertir en uno de los vrtices del
cuadrado.

Las coordenadas de la textura estn expresadas en dos dimensiones u / v. La coordenada u


es equivalente a la x de un sistema de coordenadas convencional y la v es equivalente a la
y. El eje u apunta hacia la derecha y el eje v apunta hacia abajo. El origen de coordenadas
coincide con la esquina superior izquierda del mapa de bits.

63
Figura 43. Sistema de coordenadas de una textura, despus de cargarla en OpenGL ES. Y
el modelo (vrtices) a que asociaremos cada coordenada.

As pues para convertir el mapa de bits en un rectngulo, tendremos que asociar cada
coordenada de la textura a cada vrtice del rectngulo. Ver figura 43.

5.1.7.7 Filtrar Texturas

Cuando utilicemos las texturas en la pantalla puede suceder, que el objeto sea ms grande
que la textura, en este caso estaremos empleando ms pxeles en la pantalla que los que
hay en la textura, a estos pxeles se les llaman texels. En ste caso nos encontraremos con
un efecto de ampliacin. Tambin puede que sea al contrario, que la textura sea mayor que
el objeto, aqu se trata de una reduccin.

En ambos casos deberemos indicar a OpenGL ES cmo modificar la escala de la textura.

5.1.7.8 Espacio Mundo, Espacio Modelo

El espacio mundo se refiere a la vista de nuestra proyeccin, como hemos visto nosotros
usamos la caja de la proyeccin ortogonal, pero prescindiendo del eje z. Por lo tanto slo
tendremos los ejes x / y, donde el origen de coordenadas de nuestro espacio mundo, se
encuentra en la esquina inferior izquierda. Los valores positivos del eje x apuntan hacia la
derecha y los del eje y hacia arriba. Figura 44.

Figura 44. Sistema de coordenadas OpenGL ES para nuestro juego 2D.


64
Espacio-modelo es el sistema de coordenadas en el que definimos el objeto, sin tener en
cuenta nada ms. Es decir las posiciones de los vrtices de nuestros modelos. Este lo
utilizaremos para transformar el modelo ms fcilmente (rotar, mover, etc.) sin tener que
aplicar las transformaciones a todos sus vrtices. En la figura 45, vemos un ejemplo del
espacio modelo de nuestro cuadrado. Con su sistema de coordenadas. El origen se
encuentra en el centro, el eje de las x aumenta a la derecha y el de las y hacia arriba.

Figura 45. Nuestro modelo con su espacio.

5.1.7.9 Como Trabaja OpenGL ES 1.0

Imaginemos un folio en blanco y un pintor. Bien pues OpenGL utiliza la clase


GLSurfaceView como el folio dnde pintar, y la clase GLSurfaceView.Renderer como
pintor. Utilizaremos este Renderer (renderizador) para especificar lo que queremos que
aparezca en pantalla.

OpenGL dibuja en un hilo independiente mediante la clase GLSurfaceView, para no


sobrecargar el hilo de IU. La clase GLSurfaceView se encarga de iniciar el hilo en
onResume() y lo elimina en onPause(). Aqu tenemos un problema, ya que al retomarlo
crea una nueva superficie perdiendo todos los estados configurados (texturas, etc). Se
conoce como prdida de contexto, y nos obligar a volver a cargar las texturas al volver a
retomar la aplicacin.

Los mtodos que deberemos implementar de Renderer son:

onSurfaceCreated(), este mtodo es llamado cuando la superficie es creada o es re-


creada.
onSurfaceChanged(), se llama a este mtodo cuando la superficie cambia de alguna
manera, por ejemplo al girar el mvil y colocarlo en posicin de paisaje. En
realidad no sobrescribiremos este mtodo porque bloquearemos la orientacin de la
pantalla.
65
onDrawFrame(), este mtodo es el que utilizaremos para dibujar directamente
sobre la pantalla (en realidad sobre la superficie, el folio). La aplicacin no se
ocupa de llamar a ste mtodo, de ello se encarga automticamente el hilo tantas
veces como le es posible. Una vez pintado es GLSufaceView quien se encarga de
entregar la fotografa a la GPU en forma de pxeles.

5.2 Desarrollo del Juego

En esta seccin y despus de haber adquirido los conocimientos suficientes, sobre Android
y OpenGL vamos a explicar la implementacin del juego. Veremos la estructura de nuestro
proyecto, el framework con los diferentes mdulos y las clases que los forman, que tareas
llevan a cabo y el modo de implementarlas. Finalmente veremos las clases que forman
nuestro juego.

Como complemento a la lectura de esta seccin del captulo, se recomienda tener una copia
local del cdigo del juego.

5.2.1 Estructura de Blocks

La estructura de nuestro proyecto Blocks tiene la misma estructura que cualquier proyecto
para Android, as que vamos a centrarnos en ver cmo hemos organizado la parte del
cdigo, carpeta /src/.

En la figura 46. podemos observar la estructura de nuestro proyecto Blocks.

Hemos dividido el cdigo de nuestro videojuego en cuatro paquetes. Todos empiezan por
el nombre com.games.edo.

En framework, incluimos las interfaces que utilizamos para la generacin del


framework.
En framework.andoidimplementado, encontramos las clases que implementan el
framework para Android, al paquete lo llamamos androidimplementado para
diferenciarlo de las interfaces. Aqu estn las implementaciones de los mdulos:
Entrada, Audio, Grficos, Archivos lectura/escritura y el Gestor de ventanas.
En framework.GL, hemos colocado las clases que necesitamos para trabajar con
OpenGL.

66
En juegoBlocks guardamos las clases con la implementacin del juego: Pantallas,
configuracin, tablero, especificacin de recursos y la clase principal
JuegoBlocks.java punto de entrada de nuestro videojuego.

Figura 46. Estructura del proyecto del juego Blocks

En Android Manifest definimos los permisos para nuestra aplicacin. Wake_Lock para
impedir que la pantalla entre en modo ahorro de energa, y Write_External_Storage, para
acceder a la tarjeta de memoria. Adems definimos la Actividad JuegoBlocks.java como
principal (punto de entrada) y la orientacin como Landscape para que se vea en
horizontal. Cambiamos las configuraciones para ocultar el teclado y no permitir el cambio
de orientacin al girar el mvil.

5.2.2 Framework

Vamos a empezar viendo los elementos que componen el framework del juego, sus
mdulos con sus mtodos.

5.2.2.1 Mdulo Archivos Input/Output

Recordemos que este mdulo nos sirve para guardar y recuperar los datos de nuestro
juego. Como vamos a usar la tarjeta de memoria, nos aseguraremos de haber pedido los
permisos de acceso en Android Manifest.

67
El mdulo est formado por la interfaz FileIO, y la clase AndroidFileIO que la
implementa. En ella almacenamos un AssetManager y la ruta del almacenamiento externo.
Vamos a ver sus mtodos:

public InputStream leerAsset(String nombreArchivo) throws


IOException
public InputStream leerArchivo(String nombreArchivo) throws
IOException

public OutputStream escribirArchivo (String nombreArchivo) throws


IOException

Para leer nuestros recursos utilizamos la funcin leerAsset, que se vale de la clase
AssetManager para abrir el archivo del cual le pasamos el nombre y nos devuelve un
objeto de la clase InputStream de Java que se puede usar para leer cualquier archivo.

Utilizaremos los mtodos leerArchivo, escribirArchivo para leer o escribir


respectivamente nuestro archivo de configuracin (puntuaciones y si el sonido est
activado), que devuelven objetos FileInputStream y FileOutputStream. Estos mtodos se
valen de la ruta de la unidad externa de almacenamiento que obtendremos con la funcin:
getExternalStorageDirectory().getAbsolutePath() + File.separator;

Figura 47. Tarjeta de memoria externa.

Las excepciones IOException nos permiten identificar los errores que se puedan producir
al cargar los recursos (Si no hay tarjeta SD, si el nombre del archivo es diferente, etc.).

5.2.2.2 Mdulo Entrada

Con el mdulo de entrada accederemos a los eventos relacionados con el teclado y con la
pantalla tctil. Separamos el cdigo por labores implementando las clases que desarrollan
su trabajo, tendremos un controlador de teclado y uno de pantalla.
68
Cada vez que haya una entrada del usuario se producir un evento que obtendremos con
unos listeners que suscribiremos a la IU (en nuestro caso la View donde se encuentra el
foco). As que lo que haremos ser dejar que entren los eventos y registrarlos, para ms
tarde procesarlos.

5.2.2.2.1 La clase Pool


En nuestro controlador de eventos de entrada se estarn creando instancias de TouchEvents
y de KeyEvents (en el caso que el dispositivo tenga teclas) constantemente. Cada vez que
presione una tecla o se toque la pantalla, el sistema de entrada de Android dispara varios de
estos eventos, con lo que creamos instancias nuevas de forma continua. stas van a parar al
poco tiempo al recolector de basura. Ya hemos visto que el Garbage Collector es un
enemigo para el rendimiento de nuestro juego, as que con la clase Pool vamos a intentar
evitarlo.

Con Pool en vez de crear nuevas instancias constantemente y posteriormente destruirlas


(con GC), nos limitaremos a guardarlas para despus poder reutilizarlas. [15]

Para ello implementamos una clase genrica, es decir que nos permite almacenar objetos
de cualquier tipo. En ella guardaremos un ArrayList, donde guardaremos los objetos del
pool, PoolObjectFactory que lo utilizaremos para generar nuevas instancias del tipo de la
clase que contenga, y un miembro que almacena el nmero mximo de objetos que
podemos incluir.

En el constructor simplemente recibimos un objeto PoolObjectFactory y el nmero de


objetos que guardaremos y los almacenamos.

Sus mtodos de la clase son:

public T newObject()

Crea un nuevo objeto en el ArrayList en el caso que no haya ninguno, o nos devuelve la
instancia de un objeto ya reciclado.

public void free(T object)

Nos permite guardar los objetos que no vayamos a utilizar ms, para reutilizarlos ms
tarde, siempre y cuando quede espacio libre.

69
5.2.2.2.2 El Controlador de Teclado
La clase KeyboardHandler implementa el controlador de teclado, debemos implementarlo
porque hay dispositivos con teclado que pueden usar la aplicacin y generar muchos de
estos eventos disparando al GC. La intencin al principio del proyecto tambin era manejar
la tecla Back del dispositivo.

Se encarga de la vista a travs de la cual se reciben los eventos del teclado, toma nota del
estado de cada tecla guardndola en un pool, lleva un registro de instancias TouchEvent y
lo sincroniza todo porque recibe los eventos desde la interfaz de usuario mientras los
guardamos en el pool del juego, que se estar ejecutando desde otro hilo diferente.

KeyboardHandler implementa la interfaz onKeyListener para recibir los eventos de la


View. Guardaremos un array pressedKeys con el estado de cada tecla (pulsada o no), el
Pool keyEventPool para reciclar las instancias de nuestra clase keyEvent. En
KeysEventsBuffer guardaremos los eventos que se generen y an no vayamos tratando. Y
como doble buffer usaremos tambin keyEvents.

En el constructor recibe como parmetro la vista dnde se suceden los eventos de teclado.
Creamos la instancia a Pool y configuramos el listener para la vista.

Veamos ahora sus mtodos:

public boolean onKey(View v, int keyCode, android.view.KeyEvent


event)

Es llamado cada vez que recibamos un evento de teclado desde el hilo de IU. En l
cogemos una instancia del Pool, nueva o reciclada, miramos la tecla el tipo de evento y lo
aadimos a nuestra lista KeysEventsBuffer.

public List<KeyEvent> getKeyEvents()

Nos devuelve una lista con los eventos de teclado que se han ido almacenando. Para ello
utilizaremos el doble buffer. Primero Guardamos en el pool los eventos de KeysEvents.
Luego limpiaremos este buffer para ms tarde volcar los eventos de KeysEventsBuffer.
Terminamos limpiando KeysEventsBuffer, para que no se llene.

public boolean isKeyPressed(int keyCode)

70
Nos indica si la tecla que le pasamos se ha presionado o no, consultando su estado en el
array de teclas pulsadas.

5.2.2.2.3 El Controlador Tctil


Como slo vamos a usar un dedo para jugar, haremos nuestro controlador para pantallas
mono tctiles. Est compuesto por la interfaz TouchHandler y la implementacin
SingleTouchHandler que a su vez implementa a onTouchListener. Guardaremos un
booleano para saber si se ha tocado, dos enteros para la posicin (x e y), la lista Pool para
reciclar eventos y de nuevo usaremos un doble buffer, TouchEvents y TouchEventsBuffer.
Usaremos los valores scaleX, scaleY para tratar diferentes resoluciones de pantalla.

En el constructor recibimos como parmetros la Vista y las escalas horizontal y vertical,


igual que antes registramos el Pool, configuramos el listener para la vista y acabamos
almacenando los valores de escala.

Figura 48. Mvil Android con teclado y pantalla tctil.

Los mtodos de SingleTouchHandler son:

public boolean onTouch(View v, MotionEvent event)

Cada vez que se produce un evento en la pantalla desde la IU se llama a este mtodo, en l
cogemos una instancia del Pool nueva o reciclada, miramos la tecla el tipo de evento, lo
aadimos a nuestra lista touchEventsBuffer y multiplicamos las coordenadas x e y por el
factor de escala.

public boolean isTouchDown(int pointer)


public int getTouchX(int pointer)
public int getTouchY(int pointer)

71
Estos mtodos permiten conocer el estado de la pantalla. Slo usaremos un dedo, el
identificador del primer dedo que toca la pantalla siempre es 0, as que slo manejaremos
los eventos que tengan este identificador (puntero). El primero indica si el dedo ha tocado
la pantalla y los dos siguientes nos dan la coordenada del eje en que se toc.

public List<TouchEvent> getTouchEvents()

Nos servir para obtener los eventos TouchEvent y as gestionar estas entradas. Deberemos
llamarlo frecuentemente para evitar que la lista se llene.

5.2.2.2.4 Juntando las Entradas


La interfaz input que est implementada por la clase AndroidInput, que es el que hace de
controlador de entradas.

En la interfaz input definimos nuestros tipos de eventos, touchEvent y keyEvent con sus
atributos. De TouchEvent guardaremos el tipo (toca, suelta, arrastra), la posicin y el
identificador puntero que se le da mientras est tocando. Para keyEvent similar, el tipo
(pulsada, soltada), cdigo y carcter.

La clase AndroidInput simplemente configurar el controlador tctil y el controlador de


teclado. No explicamos sus mtodos porque simplemente llaman a los mtodos del
controlador apropiado que ya hemos visto:

public boolean isTouchDown(int pointer)


public int getTouchX(int pointer)
public int getTouchY(int pointer)
public boolean isKeyPressed(int keyCode)
public List<TouchEvent> getTouchEvents()

public List<KeyEvent> getKeyEvents()

5.2.2.3 Mdulo Audio

Este mdulo est compuesto por las interfaces: Musica, Sonido y Audio y por las clases
AndroidMusica, AndroidSonido y AndroidAudio.

72
Android tiene diferentes Streams de audio, segn donde se encuentre al subir o bajar el
volumen con los botones laterales veremos que hace una cosa u otra, en una llamada, en un
juego, en el reproductor de audio

Primero debemos asegurarnos que controlamos el Stream de audio correcto. Utilizaremos


el Stream de Android Msica.

5.2.2.3.1 Msica
La clase AndroidMusica implementa onCompletionListener (la usamos para comprobar si
se ha completado la reproduccin del sonido) y nuestra interfaz Musica, con ella
controlamos la reproduccin del contenido del archivo de msica.

Lo que hace esta clase es enviar a la tarjeta de sonido del dispositivo el contenido del
archivo de msica almacenado en el disco. Para ello utilizamos una instancia MediaPlayer
(la clase que nos reprodce el archivo de audio), junto con un booleano, para saber el estado
de MediaPlayer.

En el constructor creamos el MediaPlayer, lo iniciamos con el AssetDescriptor que


recibimos por parmetro, e indicamos que est preparado, finalmente registramos como
detector OnCompletionListener.

Sus mtodos son:

public void play()

public void stop()

public void pause()


Sirven para controlar la reproduccin de la msica. En play() prepararemos Mediaplayer y
lo iniciamos, en un bloque sincronizado debido a la interfaz OnCompletionListener podra
hacer la verificacin de si est preparado en un hilo independiente.

public void setLooping(boolean looping) Nos permite reproducir el sonido


en un bucle, es decir cuando termina vuelve a empezar.
public void setVolume(float volume) Define el volumen.

public boolean isPlaying()

public boolean isStopped()

73
public boolean isLooping()
Sirven para consultar el estado de la reproduccin.
public void dispose() Detiene la reproduccin si est en marcha y libera el
recurso.

5.2.2.3.2 Efectos de Sonido


AndroidSonido implementa la interfaz Sonido, que nos permite reproducir efectos de
sonido cargados en la memoria RAM.

Aqu usaremos y clase SoundPool que nos facilita la reproduccin de efectos sonoros.
Manejaremos el archivo con el identificador que asigna al cargarlo.

Los mtodos son:

public void play(float volume) Para reproducir el sonido

public void dispose() Para liberar el recurso.

5.2.2.3.3 Juntando el Audio


La interfaz Audio se utiliza para crear nuevas instancias tanto de msica como de sonido
desde los archivos de recursos. La clase AndroidAudio implementa esta interfaz.

En el constructor le pasamos la actividad para definir el volumen (usando el Stream Music)


y guardamos una instancia de AssetManager que nos proporcionar el directorio assets
dnde guardamos nuestros ficheros y otra de SoundPool, configurndola para 20 efectos
sonoros a la vez.

Figura 49. Icono sonido en Android.

74
Sus mtodos son:

public Musica nuevaMusica(String nombreArchivo)

public Sonido nuevoSonido(String nombreArchivo)

El mtodo nuevaMusica crea una instancia de AndroidMusica tomando el descriptor de


AssetManager que nos proporcionar el directorio assets dnde guardamos nuestros
ficheros.

El mtodo nuevoSonido lo usamos para cargar en la memoria un efecto sonoro que est
guardado en un archivo de audio, se vale del descriptor de AssetManager para obtener la
ruta dnde est el fichero y nos devuelve el id del sonido cargado en memoria.

5.2.2.4 Mdulo Grficos

Por la complejidad de este mdulo, hemos agrupado todas las clases que tengan que ver
con la parte grfica en el paquete com.games.edo.framework.GL.

5.2.2.4.1 GLGraficos
Usaremos esa clase para llevar un registro de GL10 (que nos permite enviar comandos a
OpenGL ES) y de GLSurfaceView.

Sus mtodos son:

public GL10 getGL()

void setGL(GL10 gl)

public int getWidth()

public int getHeight()

Que nos sirven para enviar y obtener los datos.

5.2.2.4.2 Vector
Creamos la clase Vector2D que tratar con un vector en 2D. La podremos usar para
representar, posicin, velocidad, direccin y distancia (Figura 50). Tambin nos servir
para rotar o modificar la escala, as como para ajustar la imagen automticamente al
volumen de la vista de la ventana.
75
Por definicin un vector es:

v = (x,y) (0)

Figura 50. Usando un vector como posicin, velocidad direccin y distancia.

Guardaremos los miembros x e y, y definiremos unas constantes para poder pasar el ngulo
de grados a radianes y viceversa, slo deberemos multiplicar el ngulo por la constantes
indicada.

Los mtodos de esta clase implementan un poco de lgebra y trigonometra:

public Vector2 cpy()

Devuelve una copia el vector.

public Vector2 add(float x, float y), public Vector2 add(Vector2


vec)

Estos mtodos nos devuelve la suma de nuestro vector con otro, o con argumentos.
Recordemos la frmula (1)

v + u = (v.x + u.x, v.y + u.y) (1)

public Vector2 sub(float x, float y), public Vector2 sub(Vector2


other)

Estos mtodos nos devuelve la resta de nuestro vector con otro, o con argumentos.
Podemos ver la frmula a continuacin (2)

v - u = (v.x - u.x, v.y + u.y) (2)

public Vector2 mul(float scalar)

Multiplica nuestro vector por un escalar. Ver frmula (3)

76
u*k = (x*k, y *k) (3)

public float len()

Nos indica la longitud del vector. Frmula (4)

|u| = raz( x^2 + y^2) (4)

public Vector2 nor()

Normaliza un vector hasta su longitud unitaria. Primero calculamos su longitud y si no es


cero, dividimos cada componente por sta, obteniendo as uno de longitud unitaria.

public float angle()

Nos devuelve el ngulo existente entre el eje x y nuestro vector. La frmula la encontramos
en (5) y podemos ver la representacin grfica en la figura 51. Si es menor que 0, le
sumaremos 360.

angulo = arctg(y, x) (5)

Figura 51. ngulo entre un vector y el sistema de coordenadas.

public Vector2 rotate(float angulo)

public float dist(Vector2 vec), public float dist(float x, float


y),

Calcula la distancia entre nuestro vector y el vector o coordenadas que le pasamos.


Usaremos la frmula (6)
77
dist = Raz( (x1-x2)^2 + (y1-y2)^2 ) (6)

public float distSquared(Vector2 other) , public float


distSquared(float x, float y)

Nos devuelve la distancia al cuadrado entre nuestro vector y el vector o coordenadas que le
pasamos.

public Vector2 set(float x, float y), public Vector2 set(Vector2


other)

Nos permite establecer los componentes x e y de nuestro vector, como argumentos o con
otro vector.

5.2.2.4.3 La Cmara
Recordemos que usaremos el plano de proyeccin paralelo y adems ste ser plano, es
decir no tendr eje z, porque trabajaremos en 2D. Lo podemos ver en la figura 52.

Figura 52. El volumen de la vista de nuestro mundo 2D.

Vamos a ver la clase camara2D, que usaremos para definir la ventana de visualizacin y la
matriz de proyeccin correctamente.

En esta clase almacenaremos la posicin, el ancho y el alto de la vista y el factor de zoom,


tambin necesitaremos una instancia a GLGraficos.

En el constructor, almacenaremos la instancia a GLGraficos, el ancho y alto de la vista.


Definiremos la posicin de la cmara en el centro de la ventana de visualizacin, que como

78
vemos en la figura 52 est comprendida entre (0,0,1) y (frustumWidth, frustumHeight, -1)
y establecemos el zoom como 1.

Los mtodos implementados de la clase camara2D son:

public void setVolumenvistayMatrices()

Con este mtodo establecemos el volumen de la vista, como la ventana de visualizacin y


configuramos la matriz de proyeccin con los parmetros de la cmara. Primero obtenemos
GL10 para poder enviar comandos a OpenGL. Despus definimos el Volumen de la vista, a
pantalla completa, establecemos la matriz de proyeccin y cargamos la identidad,
configuramos la matriz de proyeccin definiendo las coordenadas del borde de la cmara y
al final dirigimos las operaciones a la matriz modelo-vista y que las cargue en una matriz
identidad.

public void toqueEnMundo(Vector2D touch)

Transforma las coordenadas de un punto de contacto transformndolas al punto de contacto


dentro del espacio de nuestra vista. Primero normalizamos las coordenadas x e y del punto
de contacto dividiendo por ancho y alto de la pantalla, obtenemos as un rango entre 0 y 1,
luego multiplicamos por ancho y alto del volumen de la vista para expresarlo en trminos
del espacio del mundo virtual.

touch.x = (touch.x /(float) glGraficos.getWidth()) * frustumWidth * zoom;


touch.y (1 - touch.y /(float)glGraficos.getHeight())*frustumHeight* zoom;

Finalmente calculamos el factor de la posicin del volumen de la vista y del zoom.

touch.add(posicion).sub(frustumWidth * zoom / 2, frustumHeight * zoom/2);

5.2.2.4.4 Vrtices
Creamos la clase Vertices para almacenar los vrtices e ndices de los modelos que
usaremos y enviarlos a OpenGL ES cuando dibujemos en pantalla. Recordemos que
usaremos un bfer NIO de Java para enviar los vrtices a OpenGL ES 1.0.

Almacenaremos una instancia a GLGraficos, un par de booleanos para consultar si guardan


color o tienen textura. Como reservaremos memoria para los vrtices necesitamos saber el
tamao que ocupar cada vrtice en memoria, que guardaremos en un entero. Finalmente
para almacenar los vrtices utilizaremos un IntBuffer y manejaremos tambin un
79
ShortBuffer para los ndices (para usar los vrtices indexados), adems emplearemos un
array de enteros temporal para volcar las coordenadas de los vrtices que le pasaremos
como array estndar.

Nuestro bfer de vrtices tendr el aspecto que muestra la figura 53.

Figura 53. El bfer de vrtices, las direcciones en que empieza a leer OpenGL, y los
saltos.

En el constructor enviaremos la instancia a los grficos, el mximo de vrtices e ndices


que podremos almacenar y si tienen color o textura. Dentro almacenaremos estos valores,
determinaremos el tamao que ocupar cada vrtice en memoria e iniciaremos los bferes.
Comprobaremos si usaremos vrtices indexados y si es as iniciaremos el bfer de ndices.

Los mtodos de la clase Vertices.java son:

public void setVertices(float[] vertices, int offset, int length)

Guarda los vrtices en nuestra clase, recibe como parmetro un array estndar que guarda
las coordenadas de los vrtices, adems pasamos la longitud y el desplazamiento. Primero
limpiaremos nuestro bfer, calcularemos el tamao con el desplazamiento y longitud, y
volcaremos el array con los vrtices en nuestro bfer temporal, para acabar transfirindolo
al bfer de vrtices, y estableciendo el tamao de ste.

public void setIndices(short[] indices, int offset, int length)

Nos permite guardar los ndices de los vrtices que recibe como parmetro, junto con el
desplazamiento y la longitud. Limpiamos el contenido del bfer ndices, copiamos los
ndices que recibimos como parmetro y acabamos indicando el nuevo tamao de nuestro
bfer ndices.

public void draw(int primitiveType, int offset, int numVertices)

80
Nos permite dibujar, toma el tipo de primitiva, (GL10.GL_TRIANGLES), el
desplazamiento y el nmero de vrtices que vamos a dibujar.

Si trabajamos con los vrtices indexados calculamos el desplazamiento y dibujamos, sino


los utilizamos dibujamos directamente los vrtices.

public void bind()

Con ste mtodo asociamos los vrtices a los atributos de color o a las texturas, si tienen.
Primero cogemos la instancia de GL10 para enviar comandos a OpenGL, despus le
avisamos a OpenGl que pasamos los vrtices y le decimos dnde encontrar los datos
(posicin 0 del bfer), el tamao (2: x e y) y el salto para cada uno(vertexSize) (figura 53),
luego miramos si tienen color y hacemos lo mismo: avisamos a OpenGL que pasamos el
color, le decimos dnde los tiene que coger, el tamao (4: r,g,b,a), el desplazamiento para
el siguiente. Finalmente miramos si el vrtice lleva textura y hacemos lo mismo.

public void unbind()

Nos permite liberar los atributos de los vrtices una vez hemos terminado de dibujar.
Simplemente miramos si los vrtices tienen color y/o textura y pedimos a OpenGL que los
deshabilite.

5.2.2.4.5 Texturas
Para cargar los grficos utilizaremos dos clases, Textura y RegionTextura. Con Textura se
podremos cargar un mapa de bits almacenado como recurso. La segunda RegionTextura,
nos sirve para coger porciones del mapa de texturas.

Veamos primero la clase Textura.

Utilizaremos una instancia a GLGraficos para cargar la textura en OpenGl, una referencia
FileIO y un String para leerla desde nuestro archivo e indicarle el nombre de ste. Un
entero que nos guardar el identificador de la textura para que podamos trabajar con ella.
Finalmente guardamos cuatro enteros ms. Los dos primeros nos permiten especificar los
filtros (de reduccin y ampliacin) y los siguientes nos guardaran el tamao de la textura,
ancho y alto.

81
En el constructor le pasaremos una referencia a glJuego y el nombre del archivo en que se
encuentra la textura. Obtendremos las referencias al mdulo de grficos (GLGraficos) y al
mdulo ArchivoIO (FileIO) del parmetro glJuego y almacenaremos el nombre de archivo
para poder cargar ms tarde la textura.

Vamos a ver sus mtodos:

private void load()

Utilizaremos este mtodo para cargar una textura. En l lo que hacemos primero es obtener
GL10 para poder enviar comandos a OpenGL ES. Despus creamos el objeto textura en
OpenGL que an estar vaco, nos devolver un identificador para la textura y ste lo
utilizaremos para indicarle a OpenGL las operaciones que queramos hacer con ella.
Seguidamente leeremos la imagen del archivo y la decodificamos como un Bitmap, y
asociamos este Bitmap con la textura que habamos creado en OpenGL, a partir de aqu el
objeto textura y su imagen asociada estar almacenado en la RAM de vdeo, (por eso se
pierde cuando se destruye OpenGL). A continuacin especificamos filtros, eliminamos la
asociacin porque no la vamos a usar ms, guardamos los datos de ancho y alto y
terminamos liberando el Bitmap. En el caso de no encontrar el archivo con la textura
obtendremos un error.

public void reload()

ste es el mtodo que usaremos para recargar una textura una vez OpenGL pierda el
contexto, es decir cuando se pause la aplicacin.

public void setFilters(int minFilter, int magFilter)

Con este mtodo establecemos los filtros de ampliacin y reduccin para las texturas. Aqu
los parmetros son enteros que indican el filtro que asociar OpenGL para la textura.

public void bind()

Nos permite asociar la textura a OpenGL.

public void dispose()

Sirve para liberar el objeto textura de la RAM de video, lo que hacemos es liberar la
asociacin de la textura, y la borramos de OpenGL ES.

82
Vamos a ver ahora la clase RegionTextura, que nos permite definir una regin dentro de
una textura. La usamos para dibujar una parte de una textura, en nuestro caso para coger
los elementos de nuestro mapa de texturas.

En ella almacenaremos las coordenadas de la esquina superior izquierda (la coordenada del
elemento dentro del mapa de texturas), y las coordenadas de la esquina inferior izquierda,
junto con la textura, de la que forma parte.

Figura 54. Ejemplo de regiones de Textura, con la coordenada superior izquierda.

Llamaremos al constructor envindole la textura, la coordenada superior izquierda, y el


alto y ancho de la regin.

En la figura 54 podemos observar algunas regiones de nuestro mapa de texturas


correspondientes a los botones, con sus coordenadas superior izquierda.

5.2.2.4.6 Dibujando Texto


Para escribir texto en nuestro juego, hemos visto que vamos a utilizar una fuente bitmap
que cargaremos desde el mapa de texturas. Para ello nos valdremos de la clase Fuente que
almacena los caracteres de la fuente bitmap.

Para ello usaremos las variables textura para coger los caracteres de sta, y el ancho y alto
de los glifos (todos los caracteres tienen el mismo). Y con un array de TextureRegion
almacenaremos la regin de cada carcter en el constructor. El primer elemento contiene la
regin con el carcter espacio que tiene el cdigo ASCII 32, el siguiente la exclamacin
cdigo 33, etctera y el ltimo aqul cuyo cdigo es 127. Ver la figura 55. En el
constructor le pasaremos cuantos glifos tenemos por fila y la esquina superior izquierda del
rea de la fuente bitmap en el mapa de texturas.

83
Con el mtodo public void drawText(SpriteBatcher batcher, String text,
float x, float y) podremos escribir una lnea de texto que le pasemos, en la posicin
que especifiquemos. Para ello obtendremos el ndice del carcter comprobar si tenemos
glifo para l y dibujarlo usando SpriteBatcher. Despus incrementamos x para escribir el
siguiente carcter.

Figura 55. Tabla con los caracteres ASCII y sus valores decimales.

5.2.2.4.7 Lote de Modelos


Ya hemos visto que tenemos casi todas las imgenes del juego cargadas en el mapa de
texturas para no tener que ir cambiando de textura. La clase SpriteBatcher implementa un
lote de modelos, es decir nos permite dibujar un grupo de sprites (modelo + textura) en una
nica operacin. Eso s siempre de la misma textura.

84
En la clase guardaremos: un array con las posiciones de los vrtices del lote, un entero que
indica el ndice del bfer para empezar a escribir las posiciones de los vrtices, una
instancia a Vertices para enviar los vrtices a OpenGL y que los dibuje, y otro entero que
contendr el nmero de sprites que dibujaremos en el lote.

Al constructor lo llamaremos con la referencia a GLGraficos y con el nmero mximo de


Sprites (modelos) que puede almacenar el lote. En l inicializamos el array de vrtices,
configuramos la instancia a Vertices (4 vrtices por modelo y 6 ndices), inicializamos el
ndice de del array vrtices y el nmero de Sprites dibujados. Finalmente creamos un bfer
para guardar los ndices indexados de los modelos, e inicializamos sus valores. Para
hacerlo recorremos el bfer ndices generando los valores para cada modelo, el primero
tendr los ndices 0,1,2,2,3,0 el segundo 4,5,6,6,7,4 el tercero 8,9,10,10,9,8 y as
sucesivamente (Figura 55). Finalmente entraremos los ndices en la instancia Vertices y ya
no tendremos que definirlos ms ya que stos no cambiarn aunque cambien los modelos.

Figura 55. Indexando ndices para los modelos.

Los mtodos de la clase son:

public void beginBatch(Textura textura)

Asocia la textura que le pasamos e reinicia los valores para empezar a trabajar con el lote.

public void drawSprite(float x, float y, float ancho, float alto,


RegionTextura region)

Con este mtodo preparamos un sprite (modelo+textura) en el lote, para cuando los
tengamos todos dibujarlos de una llamada. Le pasamos las coordenadas del centro del
modelo, x e y, el ancho y el alto y la regin RegionTextura. Calculamos las coordenadas de
las esquinas del sprite (inferior derecha y superior izquierda), ver figura 56, y
almacenamos en nuestro array las coordenadas de cada vrtice del modelo con las

85
correspondientes a su RegionTextura. Finalizamos incrementando el valor del nmero de
sprites en el lote.

Figura 56. Calculando los vrtices del modelo

public void drawSprite(float x, float y, float ancho, float alto,


float angulo, RegionTextura region)

Con este mtodo tambin preparamos un sprite (modelo+textura) en el lote, pero lo


rotaremos el angulo que le pasamos como parmetro. El resto de prametros son igual que
el anterior mtodo. Calculamos las coordenadas de las esquinas del sprite, para ello
cogemos el angulo lo pasamos a radianes y calculamos el seno y el coseno para obtener los
vrtices (1). Y almacenamos en nuestro array las coordenadas de cada vrtice del modelo
con las correspondientes a su RegionTextura. Finalizamos incrementando el valor del
nmero de sprites en el lote.

La frmula que usamos para rotar los puntos un determinado ngulo es:

v.x = cos(angulo) * v.x sin (angulo) * v.y (7)

v.y = sin(angulo) * v.x + cos (angulo) * v.y

public void endBatch()

Con este mtodo indicamos que hemos completado el proceso de dibujo del lote, es decir
que hemos preparado todos los sprites que vamos a dibujar con drawSprite, y lo que hace
es enviar a la GPU todos los datos para presentarlos en pantalla. En l transferimos los
vrtices a la instancia Vertices, los asociamos, los dibujamos y finalmente los liberamos la
asociacin.

86
Figura 57. Rotacin de un vector como posicin.

5.2.2.4.8 Medir el Rendimiento


Creamos la clase FPSContador para medir cuntos frames (fotogramas) por segundo
consigue dibujar nuestro juego. El resultado lo visualizaremos en el Log del sistema.

Es muy sencilla guardaremos el tiempo de inicio, y un contador de frames, tenemos un


mtodo public void logFrame() al que llamamos cada vez que la superficie convoque
al dibujo, incrementaremos el valor de frames y el tiempo transcurrido, si ste es mayor de
un segundo sacamos el resultado por el Log y reiniciamos las variables.

5.2.2.4.9 Otras Clases


Con tal de dar soporte a la parte de interfaz de usuario, creamos un par de clases ms que
incluimos en mismo paquete con la parte de OpenGL, Boton y DentrodeBoton.

La clase Boton la usaremos para definir los botones de los mens (estos sern
rectangulares), en ella almacenaremos la posicin de la esquina inferior izquierda
utilizando Vector2D, y el alto y ancho del botn.

La clase DentrodeBoton la utilizamos para saber si un toque en la pantalla se ha producido


dentro de un botn definido, en ella no almacenamos nada tan slo contiene los mtodos:

public static boolean pointInRectangle(Boton r, Vector2D p)

public static boolean pointInRectangle(Boton r, float x, float y)

87
En los que comprobamos si la posicin (definida como vector2D o como posicin x e y) se
encuentra dentro del botn recibido por parmetro.

Esta clase la hemos separado para crear sus mtodos como static, as al llamarlos no se
crea el objeto DentrodeBoton evitando as al Recolector de basura.

5.2.2.5 Mdulo Gestor de Ventanas

GLJuego, es nuestro de gestor de ventanas. Recordemos que el Gestor de Ventanas hace de


mdulo principal, el que enlaza el resto de mdulos y los comunica.

Desde l trabajaremos con la interfaz de usuario, para que ste interacte con la aplicacin
y dirigiremos sus eventos al resto de mdulos.

La ventana trabajar con una interfaz de usuario (IU), para permitir a ste que
interacte con la pantalla.

Configura la actividad y la vista, inicia y dirige las referencias destinadas a


GLGrficos, Audio, FileIO e Input a las partes seleccionadas,

Gestionar la Pantalla con el ciclo vital de la actividad, haciendo de renderizador


(hace que la pantalla se muestre en cada iteracin).

Lleva un registro de estado de la ventana e informar a la pantalla de los eventos (si


el juego est detenido o reanudado).

Llevar cuenta del rendimiento de nuestro juego (Frames por Segundo).

Iniciar el bucle principal.

Recordemos que el juego trabajar con varios hilos, as que debemos tener especial
cuidado en sincronizar el hilo de ejecucin con el hilo de dibujo, para que las Pantallas
dependan slo del hilo de ejecucin, ya que slo podemos acceder a OpenGL ES desde el
hilo de dibujo.

Almacenaremos instancias a GLSurfaceView, GLGraphics, tambin a los distintos


mdulos del framework, Audio, Input, FileIO, y Pantalla. Usamos state como el
enumerador de GLState para saber el estado en que se encuentra. stateChanged lo
usaremos para sincronizar los hilos de ejecucin de la interfaz de usuario y de dibujo. Con
88
startTime controlaremos el intervalo de tiempo y con WakeLock evitaremos que la pantalla
entre en modo ahorro de energa.

Como extiende de Activity posse sus mtodos:

public void onCreate(Bundle savedInstanceState)

Aqu configuramos la vista (GLSurfaceView como vista), la ponemos a pantalla completa y


desactivamos el ahorro de energa de pantalla (con WakeLock) e iniciamos las clases que
implementan el framework (Input, Audio, FileIO). La escala de coordenadas ser 1.

public void onPause()

En este mtodo lo llamaremos desde el hilo de ejecucin de la IU cuando se pause la


actividad, y lo usaremos para notificar a la actividad que estamos pausando la aplicacin.

Configuramos el estado dependiendo de si slo se pausa o si se cierra y esperamos a que el


hilo de dibujo tambin entre en modo pausa (lo veremos a continuacin). Para finalizar
liberamos WakeLock y pausamos GLSurfaceView y la propia actividad. Esto provocar la
perdida de contexto de OpenGL ES.

public void onResume()

Aqu dejaremos que GLSurfaceView utilice su metdo onResume() y obtendremos de


nuevo el wakeLock.

Adems GLJuego tambin implementa la interfaz GLSurfaceView.Renderer de OpenGL


implementando estos mtodos:

public void onSurfaceCreated(GL10 gl, EGLConfig config)

Este mtodo se llama desde el hilo de dibujo, utiliza el estado para mirar si es la primera
vez que inicia la aplicacin, si es as llama al mtodo getStartScreen() que nos devuelve la
pantalla de inicio del juego. Cambiamos el estado a running y hacemos resume() de la
pantalla. Finalmente tomamos nota de la hora para calcular ms tarde el intervalo de
tiempo.

public void onSurfaceChanged(GL10 gl, int width, int height)

Lo llama el hilo de dibujo cuando cambia la superficie (al girar el mvil), en l no haremos
nada, ya que definimos la orientacin de nuestro juego en el archivo Android Manifest.
89
public void onDrawFrame(GL10 gl)

Este mtodo es el responsable de dibujar en la pantalla, lo llama automticamente el hilo


de ejecucin responsable de dibujar, tantas veces como le es posible. Primero
sincronizamos el acceso al estado para asegurarnos que onPause() no est usndolo.
Luego comprobamos cmo se encuentra y reaccionamos en consecuencia.

Si est ejecutndose, calculamos el tiempo y actualizamos la Pantalla activa (segn los


eventos de IU) y la dibujamos, despus medimos el rendimiento (cuntos FPS alcanza
nuestro juego).

Si est pausado, pausaremos la Pantalla y notificamos que hemos recibido la peticin de


pausa desde la IU (que estar esperando) y le avisamos que hemos terminado de dibujar y
ya puede pausar la aplicacin.

Finalmente si se est cerrando, pararemos la Pantalla y la liberaremos, e igual que antes


notificamos al hilo de IU que hemos terminado, para que pueda terminar de cerrar la
aplicacin.

Nuestra clase GLJuego tambin implementa la interfaz juego, los mtodos de sta son:

public GLGraficos getGLGraficos()


Nos devuelve la instancia GLGraficos para poder acceder a la interfaz GL10 con la que
enviaremos comandos a OpenGL ES.

public Input getInput()


public FileIO getFileIO()
public Audio getAudio()
Con estos obtendremos las instancias al resto de mdulos.

public void setScreen(Pantalla pantalla)


Este mtodo pone como pantalla activa, la pantalla que le pasamos como parmetro.

Primero comprobamos que no sea nula, despus pausamos la pantalla que est activa en
ese momento y la liberamos, entonces activamos la pantalla que pasamos al mtodo como
parmetro, la actualizamos (para que las entradas entren en la nueva pantalla y no en la
anterior) y la establecemos como pantalla actual.

public Pantalla getCurrentScreen()

90
Este mtodo nos sirve para consultar la pantalla activa.

5.2.3 Los elementos del Juego

Vamos a ver ahora los elementos que forman nuestro juego, stos estn incluidos en el
paquete com.games.edo.JuegoBlocks, usan el framework para trabajar y componer nuestro
juego.

5.2.3.1 Configuracin

Con la clase Configuraciones registraremos las puntuaciones mximas y las opciones del
usuario (si el audio est activado o no).

Figura 58. Icono configuracin Android

En ella guardaremos un booleano para indicar si el audio est activado y un array de


enteros que guardar las nueve puntuaciones ms altas ordenadas de mayor a menor.

Veamos ahora lo mtodos:

public static void save(FileIO archivo)

Con este mtodo guardaremos la configuracin actual en el archivo llamado .blocks en la


unidad externa de almacenamiento. En l guardaremos en lneas separadas las entradas de
las puntuaciones mximas y la configuracin del sonido. Si hay algn error (como que no
est disponible la tarjeta) ignoraremos el fallo y continuaremos con la configuracin
predeterminada.

public static void load(FileIO archivo)

91
Intentar cargar la configuracin del archivo llamado .blocks que est en la unidad externa
de almacenamiento, sabiendo que las entradas estn en lneas separadas. Si hay algn error
ignoramos el fallo y continuamos con la configuracin predeterminada.

public static void anadirPuntuacion(int puntuacion)

Aade la puntuacin que recibe como parmetro al array de puntuaciones mximas si


supera alguna de stas, desplazando las inferiores en el array.

5.2.3.2 Recursos

Con la clase Assets almacenaremos las referencias a las variables estticas de nuestros
recursos. Contendr todos los recursos, a excepcin de las texturas de la pantalla de ayuda.
Sern instancias Textura, RegionTextura, Animacion, Musica y Sonido.

Sus mtodos son:

public static void load(GLJuego game)

Lo llamaremos al iniciar el juego, cargar los recursos y crear las RegionTextura


necesarias. Tambin instancia la clase Font que utilizaremos para dibujar el texto, con la
fuente bitmap incluida en el mapa de texturas. Finalmente cargar los recursos de audio y
consultando la clase configuraciones arrancar la msica o no.

public static void reload()

Lo usaremos para recargar las texturas cuando OpenGL ES pierda el contexto, (es decir
cuando la aplicacin entra en modo pausa: cuando llaman o tocamos la tecla home), en
caso que el sonido est activado tambin retomamos su reproduccin.

public static void playSound(Sonido sonido)

Este mtodo lo usaremos para comprobar si el sonido est activado y reproducirlo, lo


usaremos en el resto del cdigo.

92
5.2.3.3 La Actividad Principal

La actividad que acta como entrada de punto del juego es JuegoBlocks, esta extiende de
GLJuego en ella simplemente guardamos un booleano que nos indica si es la primera vez
que se crea el juego.

Sus mtodos son:

public Pantalla getStartScreen()

Nos devuelve la pantalla de inicio del juego, que es PantallaMenuPrincipal.

public void onSurfaceCreated(GL10 gl, EGLConfig config)

Sobrescribimos el mtodo que se llamar cada vez que se vuelva a crear el contexto de
OpenGL ES, miraremos mediante el booleano si es la primera vez que carga el juego, si es
as cargaremos las configuraciones y los recursos, si por el contrario ya haba cargado
antes deberemos recuperar el contexto recargando las texturas e iniciar la msica si se
encontraba activado.

public void onPause()

Este mtodo se llamar cuando se detenga la actividad, en l solamente nos encargamos de


pausar la msica si el sonido est activado.

5.2.3.4 Pantallas

Como ya hemos visto nuestro juego se divide en pantallas, cada una tiene sus
funcionalidad, y por eso difieren en los elementos que utilizan, (la pantalla men tiene 4
botones y un logo, la pantalla de ranking posee un ttulo, las puntuaciones y un botn, etc.)

La clase GLPantalla est incluida en el paquete framework.andoidimplementado. En ella


almacenamos una instancia a GLGraficos, para poder dibujar en OpenGL ES y otra
instancia al mdulo gestor de ventanas GLJuego para obtener el acceso al framewok.

En el constructor simplemente le pasamos cmo parmetro una referencia a GLJuego, la


almacenamos y obtenemos la referencia a GLGraficos.

Todas las pantallas de Blocks proceden de esta clase que adems hereda la interfaz
Pantalla as pues todas comparten los mtodos bsicos especificados en esta interfaz.
93
Vamos a describir que hacen estos mtodos para luego ver cada clase pantalla con sus
elementos y cmo los lleva a cabo:

public abstract void dibuja(float deltaTime)


Este mtodo se encarga de dibujar directamente en la pantalla lo que le especifiquemos
aqu.

public abstract void pause()


Este mtodo lo llamaremos cuando se pause la actividad, su implementacin depender de
la pantalla en la que estemos.

public abstract void resume()


Nos servirn para controlar el estado de la pantalla.
public abstract void dispose()

Para liberar una pantalla una vez utilizada.

public abstract void update(float deltaTime)

Este mtodo es el que se encarga de recibir los eventos de entrada y actualizar la pantalla
en consecuencia.

Veamos pues las clases que implementan las pantallas de nuestro juego.

5.2.3.4.1 Men Principal


PantallaMenuPrincipal, implementa el Men del juego, es la pantalla de inicio de ste. En
ella veremos el logo del juego, los botones para acceder a las distintas partes del juego, y el
botn para activar/desactivar el sonido. La podemos ver en la Figura 59.

Figura 59. Pantalla Men Principal


94
En esta clase guardamos un objeto camara2D, un lote de modelos SpriteBatcher para
dibujar los elementos, los botones que definen las partes tctiles (Jugar, Ranking, Ayuda,
Sonido), tambin guardamos un vector2D que usaremos para saber en qu punto el usuario
toca la pantalla, y unas variables para el efecto de animacin del logo en que guardamos el
angulo, y el tamao de escala.

En el constructor configuramos la cmara para nuestra resolucin fija, definimos el lote de


modelos, y colocamos los botones tctiles en sus posiciones, indicando el tamao.
Finalmente definimos los valores para el efecto de rotacin y escalado del logo del juego.

Veamos sus mtodos:

public abstract void update(float deltaTime)

En el mtodo cogemos los eventos de teclado, para garantizar que no salte el garbage
collector, despus recorremos los eventos de toque comprobando si se ha levantado el
dedo, transformamos a coordenadas del mundo virtual, y si se ha producido en alguno de
los botones, Jugar, Ranking, Ayuda, iniciaremos la transicin de pantalla, si se ha
producido en el botn de Sonido lo activaremos/desactivaremos segn su estado actual.

public abstract void dibuja(float deltaTime)


Aqu, limpiamos la pantalla, definimos las matrices, preparamos en el lote de modelos el
fondo y lo dibujamos, despus preparamos todos los elementos de la interfaz y al acabar
los dibujamos, finalmente calculamos los nuevos valores para el efecto del logo.

public abstract void pause()


Aqu guardamos las configuraciones de nuestro juego en la tarjeta SD.

5.2.3.4.2 Pantallas de Ayuda


Hemos dividido la ayuda en un total de tres pantallas, las clases que las implementan son
PantallaAyuda, PantallaAyuda2 y PantallaAyudaFinal. En ellas cargaremos la imagen
correspondiente de su pantalla de ayuda (ayuda1.png, ayuda2.png, ayuda3.png), y
mostraremos los botones para avanzar/retroceder (segn en qu pantalla nos encontremos)
en la esquina inferior derecha y el botn para volver al men en la esquina inferior
izquierda. Las pantallas de ayuda slo difieren de la imagen y de los botones
avanzar/retroceder.

95
Los miembros de estas clases son prcticamente iguales a los del men principal, por un
lado tenemos la camara2D, el lote de modelos SpriteBatcher para dibujar los elementos, y
los botones que definen las partes tctiles (botonAtras, botonSiguiente, botonSalir), el
vector2D para saber en qu punto el usuario toca la pantalla, y cmo usaremos una imagen
necesitamos una Textura y una RegionTextura.

El constructor es igual al del men principal, configuramos la cmara para nuestra


resolucin fija, colocamos los botones tctiles en sus posiciones con su tamao, creamos el
vector para el punto tctil y definimos el lote de modelos.

Veamos sus mtodos:

public void resume()

Aqu tan slo cargamos la Textura, y creamos su regin correspondiente.

public void pause()

Cuando se pause, lo nico que hacemos es liberar la textura para ahorrar memoria.

public void update(float deltaTime)

Este mtodo funciona igual que el del men principal, nos limitamos a comprobar si
pulsamos algn botn para iniciar as la transicin de pantalla correspondiente.

public void dibuja(float deltaTime)

El mtodo de dibujar tambin es igual al del men principal, limpiamos la pantalla,


definimos las matrices, dibujamos la imagen de ayuda y despus los botones
correspondientes.

5.2.3.4.3 Pantalla Ranking


En la pantalla de Ranking utilizaremos como ttulo parte de la etiqueta que mostramos en
la pantalla principal (Ranking) y dibujaremos las puntuaciones mximas que guardamos en
Configuraciones, tambin tendr un botn para regresar al men Principal.

Los miembros de estas clases vuelven a ser iguales, por un lado tenemos la camara2D, el
lote de modelos SpriteBatcher, el boton para volver al men principal, el vector2D para
determinar el punto en que el usuario toca la pantalla, y finalmente guardaremos un array
96
de Strings con las puntuaciones y valor con el desplazamiento con el que calcularemos la
distancia para que las puntuaciones queden centradas en pantalla.

En el constructor volvemos a configurar la cmara, colocamos el boton salir, creamos el


vector para el punto tctil, definimos el lote de modelos, aqu el nmero de modelos
mximo debe ser un poco alto porque no sabemos cuntos caracteres deberemos dibujar y
debemos asegurarnos que podemos trabajar con todos, si calculamos que cada lnea tendr
un mximo de 9 caracteres y hay 9 lneas, con el lote configurado a 100 modelos nos
sobra, despus configuramos las cadenas de puntuaciones colocando el valor, un punto y la
puntuacin. Calculamos el valor del desplazamiento mirando qu cadena es la ms larga
(multiplicando el nmero de caracteres por el ancho de glifo), y finalmente colocamos el
valor en el centro de la pantalla restando el desplazamiento dividido entre 2 y sumando el
ancho del glifo dividido entre dos (necesitamos sumarle este ltimo porque emplea el
centro del glifo en vez de sus esquinas).

Veamos sus mtodos:

public void update(float deltaTime)

Este mtodo funciona igual, nos limitamos a comprobar si pulsamos el botn para volver a
la pantalla del men principal.

public void dibuja(float deltaTime)

El mtodo de dibujar vuelve a ser igual al del men principal, limpiamos la pantalla,
definimos las matrices, dibujamos el fondo y despus los elementos: la etiqueta Ranking,
las lneas con las puntuaciones y el botn de volver, para las puntuaciones usamos el valor
de desplazamiento que calculamos en el constructor y la altura la vamos definiendo en
cada lnea.

5.2.3.4.4 Pantalla Juego


PantallaJuego es la clase que muestra la accin del juego. Se divide en distintas pantallas:
preparado, juego corriendo, pausado, fin de juego y sin movimientos. Estas pantallas no
las cargamos con distintas clases sino que desde PantallaJuego, mostramos u ocultamos
los elementos que necesitemos, segn en qu pantalla se encuentre el jugador.

97
Veamos los miembros de esta clase: empezamos definiendo las constantes para el estado
en que se encuentra el juego: preparado, corriendo, pausado, fin de juego, o sin
movimientos. Adems tambin definimos las constantes con las direcciones en que
movemos los bloques al jugar: arriba, abajo, izquierda, derecha. Por otro lado guardamos
el estado del juego, la camara2D, el lote de modelos SpriteBatcher para dibujar los
elementos, y los botones (botonSonido, botonPausa, botonContinuar, botonSalir,
botonLupa1, botonLupa2, botonLupa3), el vector2D para saber en qu punto el usuario
toca la pantalla. Guardaremos una instancia al tablero del juego, otra para el que se
encarga de dibujarlo en pantalla tableroRender (lee los elementos del tablero y los dibuja
con el mismo lote de modelos, lo veremos ms adelante) y la instancia tableroListener que
nos servir para reproducir los efectos de sonido cuando se produzca uno de estos eventos.

Figura 60. Pantalla Juego (corriendo).

Usaremos varios Strings para mostrar informacin en la pantalla: puntosString para la


puntuacin, tiempoString para mostrar el tiempo restante de juego y para llevar la cuenta
atrs cuando no haya movimientos, nivelString para mostrar el nivel actual y
restantesString para mostrar cuantos bloques nos restan para pasar de nivel. Utilizamos un
NumberFormat para que el tiempo slo muestre dos decimales en pantalla. Con los enteros
ultimaPuntuacion, ultimosRestantes y ultimoNivel comprobaremos si han cambiado los
valores y necesitamos actualizar los Strings, los utilizamos para no generar cada vez los
Strings y que no salte el recolector de basura. Para controlar los eventos de toque nos
valdremos de las variables downX y downY que utilizaremos para controlar el arrastre del
dedo en pantalla y del booleano cambiado para saber si se ha procesado el evento de toque
desde el tablero. Por ltimo tenemos las variables que controlan el tiempo en la transicin
entre la pantalla de No hay movimientos y la de Juego ejecutndose, tiempo que guarda el
98
tiempo a transcurrir entre estas dos pantallas (la cuenta atrs) y tiempoActual,
tiempoAnterior con el que calculamos el tiempo transcurrido.

En el constructor iniciamos las variables: ponemos el estado como preparado,


configuramos la cmara, creamos el vector para el punto tctil, definimos el lote de
modelos, con 100 modelos nos sobra (40 bloques + 3 lupas + 1 Boton pausa + los
caracteres de los strings que calculamos un mximo de 50), despus creamos el detector de
fx tableroListener como clase interna y despus configuramos tablero para que registre
ste detector, (desde tablero generaremos los eventos para reproducir los efectos de
sonido), iniciamos el tableroRenderer, y despus los elementos de la interfaz (botones,
lupas), terminamos configurando las variables para el inicio del juego.

Ahora vamos a conocer los mtodos de la clase, ya hemos visto que segn el estado en que
se encuentre el juego dibujaremos ciertos elementos u otros, as pues al actualizar las
entradas del usuario tambin depender del propio estado. Veamos los mtodos de
actualizacin:

public void update(float deltaTime)

El mtodo de actualizacin de la pantalla hace de maestro, mira en qu estado nos


encontramos (pantalla) para llamar a los mtodos de actualizacin correspondientes.

private void updatePreparado()

En ste mtodo lo nico que hacemos es esperar a que el usuario pulse la pantalla y levante
el dedo para entonces poner el estado del juego a Corriendo.

private void updatePaused()

En este mtodo comprobamos si el usuario toca cualquiera de los botones: Continuar,


Salir, Sonido de la interfaz de usuario para actuar en consecuencia.

private void updateNoMoves()

Cuando el tablero se quede sin movimientos mostraremos la pantalla de No hay


movimientos con una cuenta atrs de dos segundos para retomar el juego.

Aqu generaremos la cuenta atrs para que pasen los tres segundos, y poner el estado a
Corriendo. Llamaremos al mtodo cuentaAtras().

99
private void cuentaAtras()

Es el mtodo que lleva a cabo la cuenta atrs para retomar el juego, en l tomamos el
tiempo de entrada al mtodo inicio, y lo vamos actualizando para restarlo a los dos
segundos deseados, una vez transcurridos ponemos el estado a Corriendo y reiniciamos los
valores por si volvemos a quedarnos sin movimientos, finalmente llamamos a
tablero.noMoves() que generar un tablero nuevo y listo para jugar.

private void updateGameOver()

Cuando acabe el juego esperaremos a que el usuario pulse la pantalla y levante el dedo
para entonces cambiar la pantalla actual por la pantalla de Ranking.

private void updateRunning()

En este mtodo empezamos comprobando los eventos del usuario, primero miramos si el
usuario toca el botn pausa, en caso afirmativo pondremos el estado a Pausa, despus
miramos si el usuario pulsa sobre las lupas, comprobando si tiene disponibles, en caso
afirmativo llamamos a tablero.lupas() . Despus miramos si el usuario arrastra el dedo por
la pantalla y en qu direccin con el mtodo eventoDireccion() que veremos a
continuacin. Una vez comprobados los eventos del usuario, actualizamos el tiempo del
tablero (desde aqu para que se muestre en pantalla) y comprobamos si han cambiado los
Strings en cuyo caso los actualizaremos. Acto seguido comprobamos si el estado del
tablero es Fin de Juego, en cuyo caso actualizamos el estado de la pantalla a Fin de Juego
y generamos la cadena de carcter de Puntos acorde si se ha establecido un nuevo rcord o
no y aadiremos la puntuacin a Configuraciones y salvamos la configuracin del juego.
Finalizamos comprobando si el estado del tablero es Sin Movimientos, en cuyo caso
cambiamos el estado de la pantalla a Sin Movimientos.

private void eventoDireccion(TouchEvent event)

Con ste mtodo miramos los eventos que produce el jugador dentro del tablero del juego
y actualizamos el tablero en consecuencia. Para ello lo primero que hacemos es
transformar las coordenadas de toque a coordenadas OpenGL, despus comprobamos si el
evento est dentro del tablero. Si lo est comprobamos el tipo de evento: si toca la pantalla
guardamos estas coordenadas para calcular la fila y columna del tablero en la que toca, si
arrastra el dedo por el tablero en este caso comprobamos que el arrastre sea entre una

100
casilla del tablero y calculamos la direccin en que lo hace. Finalmente actualizamos el
tablero con los datos calculados (columna, fila y direccin). La columna y la fila los
obtenemos, dividiendo la coordenada de toque por el tamao (alto/ancho) de una casilla del
tablero.

Para dibujar la pantalla de Juego, lo que hacemos es dibujar el fondo con el tablero,
despus los elementos de la interfaz segn el estado del juego y si est corriendo los
bloques del tablero. Veamos los mtodos:

public void dibuja(float deltaTime)

Hace de mtodo maestro igual que el mtodo de actualizacin update(), miramos en qu


estado se encuentra para llamar a los mtodos de dibujo correspondientes, a fin de dibujar
unos elementos u otros. Primero limpiamos la pantalla, definimos las matrices, preparamos
en el lote de modelos el tablero y lo dibujamos, despus preparamos la fusin para los
elementos a dibujar y es entonces cuando miramos el estado del juego para dibujar lo que
corresponda.

private void dibujaPreparado()

En dibuja preparado tan slo dibujamos la etiqueta preparado.

private void dibujaPaused()

Aqu dibujamos la etiqueta del men de pausa y el botn de sonido.

private void dibujaNoMoves()

Es el mtodo que dibuja cuando no hay movimientos, dibujamos tres strings. Uno que nos
avisa de que no hay movimientos disponibles, el segundo nos informa que se est
generando un tablero aleatorio, y el tercero es una cuenta atrs que al llegar a cero cambia
la pantalla. Calculamos el ancho de los strings a fin de centrar su dibujo en la pantalla.

private void dibujaGameOver()

En este mtodo dibujamos la etiqueta de Fin de juego y la puntuacin obtenida, sta la


centramos en la pantalla calculando el ancho del string.

101
Figura 61. Pantalla Juego (Fin de juego).

private void renderizaLupas()

Se encarga de dibujar las lupas de la interfaz, para ello comprobamos cuantas lupas hay
disponibles en el tablero y dibujamos en consecuencia.

private void dibujaRunning()

ste es el mtodo que dibuja cuando el juego est en marcha, lo primero que hacemos es
dibujar los elementos de la interfaz: Puntuacin, Tiempo, bloques restantes, nivel y el
botn de pausa. Seguidamente dibujamos las lupas con renderizaLupas() y finalmente el
tablero de juego, mediante su renderizador tableroRenderer que veremos un poco ms
adelante.

public void pause()

Aqu nos encargamos de poner el estado de juego a pausa, solamente si estaba corriendo.
Si se encuentra en preparado o en Fin de Juego no hacemos nada.

5.2.3.5 Definir el Tablero de Juego

El tablero de juego, es el que se encarga de la simulacin de la lgica del juego. Utilizamos


la clase Bloque para definir cada bloque del tablero. La clase tablero contendr el tablero
con todos los bloques y permite interactuar con ellos. Finalmente para separar el modelo de
la vista (Modelo MVC) tenemos la clase tableroRenderer que se encarga de dibujar en
pantalla los bloques del tablero. sta crea adems la animacin de los bloques para que
parezca que se desplazan por la pantalla (cuando se intercambian o caen por gravedad),
102
actualizando la posicin de stos. Esto nos supone un problema ya que el renderizador del
tablero tarda ms en llevar a cabo la animacin que el propio tablero en realizar las
operaciones de intercambiar bloques o bajarlos por gravedad, as que deberemos
sincronizar estas dos clases. Tambin necesitamos pasar las entradas del usuario que
recibimos desde la pantalla de juego al tablero, para que ste opere en consecuencia, y
generar un tablero nuevo cuando no haya movimientos disponibles y termine la cuenta
atrs de la pantalla Sin movimientos.

Vamos a ver en pseudocdigo cmo tratamos el arrastre de Bloque para que quede claro y
podamos ver quien realiza la accin.

tablero_actualiza(entrada)
si (entrada == arrastre){
animaBloque();
intercambiaBloque();
si ( !Linea()){ //si no forman los volvemos a su posicin
animaBloqueContrario();
intercambiaBloque();
} sino{
eliminaBloques();
animaGravedad();
aplicaGravedad();
rellenaTablero();
}
}

5.2.3.5.1 Bloque
Esta clase es muy sencilla, almacena la informacin que necesitamos de un bloque.
Guardamos el color, las coordenadas en pantalla x e y, un booleano moviendo que nos sirve
para saber si el bloque se est desplazando mientras dura la animacin, un booleano
cambiado que lo emplearemos para controlar en el intercambio de bloques si forman lnea
o no, y un entero dir que nos informar de la direccin en que se mueve el bloque.

5.2.3.5.2 Tablero
La clase tablero es la que contiene todos los bloques e implementa la simulacin del juego.

103
Lo primero que hacemos es definir la interfaz TableroListener que utilizamos para
reproducir efectos de sonido con el listener, registramos las siguientes llamadas a los
sonidos:

linea() cuando se forme una lnea y se eliminen bloques.

nivelSuperado() se reproduce al superar un nivel.

noCombinacion() lo llamaremos al intercambiar dos bloques y stos no formen


lnea.

LupaPulsada() al tocar el comodn de lupa.

LupaObtenida() al conseguir una puntuacin que proporcione una lupa extra.

Despus definimos nuestras constantes, para los movimientos del dedo del jugador: toca,
arriba, abajo, derecha, izquierda y levanta. Las constantes para el tamao del tablero:
tablero alto y tablero ancho y del estado del juego: corriendo, nivel siguiente, fin de juego,
sin movimientos. Despus definimos las constantes incremento de puntuacin y tiempo por
nivel. Finalmente las constantes que utilizamos para definir la posicin de inicio del primer
bloque en pantalla yInicio, xInicio, y las constantes offsetX offsetY como desplazamiento
entre columnas y filas para los siguientes bloques.

Figura 63. El Tablero de juego.

Ahora vemos las variables que utilizamos: guardaremos el nivel en que nos encontremos,
los puntos del jugador, los bloques restantes para pasar de nivel, el tiempo restante y el
estado de juego. Utilizaremos tiempoAnterior y tiempoActual para calcular el tiempo
transcurrido, y el listener TableroListener para reproducir los efectos fx. Necesitamos
guardar una matriz de bloques, y utilizaremos dos arrays x_removes e y_removes para
104
guardar los ndices de la matriz de los bloques a eliminar junto con un contador.
Guardaremos aleatorio y rand que los utilizaremos para generar el color de los bloques
aleatoriamente.

Utilizaremos posX, posY para generar las posiciones de los bloques en pantalla. Y dos
matrices posicionesX y posicionesY para guardar las posiciones en pantalla dnde dibujar
los bloques cuando no se mueven.

Finalmente usamos los booleanos aplicandoGravedad y dibujaLupa para sincronizar con


el Renderizador, y despus almacenamos variables que usaran los mtodos de la clase, para
evitar la creacin y destruccin de objetos para que no se ejecute el Recolector de basura:
i,j,k que usaremos para recorrer la matriz de bloques, ret que indica si hay bloques a
eliminar, x e y para calcular intercambio de bloques y tmp como bloque temporal para
realizar el intercambio, finalmente x1, y1, x2, y2 almacenarn posiciones de bloques
intercambiables.

El constructor inicia los miembros y guarda el detector TableroListener que se le pasa por
parmetro, inicia los bloques con sus posiciones en pantalla, asigna los colores
aleatoriamente y llama a limpiaTablero() que deja el tablero listo para jugar, lo veremos
ms adelante, finalmente comprueba si hay movimientos y si no es as cambia el estado de
juego.

Los mtodos de la clase Tablero son:

public boolean update(int dir, int fila, int col, boolean cambiado)

Este mtodo lo llamaremos desde la pantalla de juego. Actualiza el tablero respondiendo al


evento que produzca el jugador, dir indica la direccin en donde moveremos el bloque o si
no lo moveremos (slo se ha tocado), fila y col definen la posicin del bloque dentro de la
matriz de bloques con el que ha interactuado el usuario. Utilizamos el booleano cambiado
para controlar que no repitamos el cambio de un bloque, ya que debido a que se generan
muchos eventos de arrastre nos cambiara el bloque de posicin varias veces. El mtodo
devuelve este booleano una vez lo hemos procesado.

Lo que hace es mirar si la direccin es un evento de arrastre, en cuyo caso llamamos a la


funcin arrastraBloque() para mover el bloque a la direccin deseada e indica que se ha
cambiado el bloque, si dir indica que se ha tocado la pantalla comprueba si el bloque
105
tocado es un comodn y si es as calcula aleatoriamente el color de bloques a eliminar,
elimina el bloque del comodn y llama a comodin() para eliminar todos los bloques del
color generado, e indica que ha procesado el evento del bloque, finalmente el devuelve el
booleano cambiado.

private void comodin(int color)

En este mtodo recibimos el color de los bloques a eliminar, y recorremos la matriz de


bloques eliminando los bloques que lo guarden (establecemos el color como -1), y
llamando a puntua() para que actualice el estado de las variables de juego, finalmente
comprobamos si no hay un cambio de nivel, en cuyo caso avisamos al renderizador que
debe iniciar la animacin de gravedad.

private boolean compruebaBloque(int x, int y, int color)

Esta funcin la utilizamos para determinar si el bloque indicado en la posicin que toma
como parmetro contiene el color recibido. Primero comprobamos si la posicin recibida
est dentro del tablero y si es as comprobamos si el color es equivalente al recibido, en
caso afirmativo devolveremos verdadero sino devolveremos falso.

private boolean formaLinea( int x, int y)

Con este mtodo comprobamos si el bloque con la posicin que recibe por parmetro,
forma lnea dentro del tablero. Lo que hace es desde la posicin especificada comprobar si
el color es el mismo que el de los dos bloques que le rodean (en vertical y en horizontal), lo
podemos ver en la figura 64, con la funcin compruebaBloque().

private boolean eliminaBloques()

Lo utilizaremos para eliminar los bloques que formen una lnea de tres o ms dentro del
tablero. Lo que hace es recorrer la matriz de bloques comprobando cada uno si forman
lnea, en cuyo caso copia la posicin del bloque dentro de la matriz en los arrays que usa
para eliminar x_removes e y_removes e incrementa un contador de bloques a eliminar. Una
vez terminado comprueba si hay bloques a eliminar consultando el contador y recorre los
arrays de posiciones a borrar, cambiando el color de las posiciones almacenadas por un
bloque vaco, es decir le damos a color el valor -1, y llama a la funcin puntua() si el
estado de juego est en marcha.

106
Figura 64. Posibilidades de formar lnea con los dos bloques adyacentes de una posicin.

private void puntua()

Esta funcin la llamamos cada vez que eliminamos un bloque, en ella simplemente
incrementamos la puntuacin, restamos los bloques restantes, activamos el evento para que
suene el fx de bloque eliminado, y comprobamos si el jugador obtiene una lupa extra
(recordemos cada 500 puntos), mirando si el resto de la divisin entre la puntuacin y 500
es cero, en cuyo caso incrementamos las lupas siempre y cuando no tenga ya las tres,
finalmente activamos el evento de fx de lupa obtenida.

private void limpiaTablero()

Este mtodo lo llamaremos cada vez que debamos generar un tablero nuevo (al pasar de
nivel, al quedarnos sin movimientos). En l limpiamos el tablero y lo dejamos listo para
jugar, lo que hacemos es llamar a eliminabloques() que eliminar los bloques que formen
lnea, y despus rellenamos los bloques vacos.

private void arrastraBloque(int dir, int fila, int col)

Con esta funcin indicaremos al renderizador del tablero debe hacer la animacin del
intercambio de bloques. Recibe como parmetro la fila y columna el bloque que arrastra el
jugador y la direccin en que lo hace. Primero calculamos el bloque con el que se va a
intercambiar con la direccin del arrastre. Despus comprobamos que ninguno de los dos
bloques se est moviendo ya, en cuyo caso activa el estado de moviendo en ambos, con
esto indicamos al renderizador que debe hacer la animacin de intercambio y evitamos que
107
se puedan intercambiar los bloques mientras se produce la animacin. Despus damos la
direccin recibida al bloque original, y desactiva la direccin del bloque con el que
intercambia, ya que se encargar el renderizador de mover ambos bloques a la vez.
Finalmente ponemos el booleano cambiado del bloque original a falso para indicar que an
no hemos intercambiado los bloques.

public void compruebaCambioSiLinea(int x, int y , int x2, int y2)

Esta funcin la llama el renderizador del tablero cuando ha terminado de animar los
bloques que estaba moviendo, con ella intercambiaremos los dos bloques en el tablero y
comprobaremos si forman lnea, en el caso que no la formen volveremos a iniciar la
animacin a la inversa, para ello activamos el estado de moviendo activando la direccin
anterior al bloque intercambiado, despus indicaremos con el booleano cambiado que
hemos cambiado los bloques pero no forman lnea, para que sea el renderizador quien los
vuelva a su posicin inicial. En el caso que los bloques cambiados forman lnea
comprobamos si hay un cambio de nivel y si no es as avisamos al renderizador que debe
aplicar la animacin de gravedad con el booleano correspondiente.

private boolean cambioNivel()

Sirve para avanzar de nivel si se han eliminado los bloques que se requeran en el nivel en
que se encuentra el jugador. Primero comprueba si quedan bloques restantes en cuyo caso
sale devolviendo un falso. En caso de que no queden bloques restantes, pone el estado de
juego como siguiente nivel, incrementa el nivel actual, actualiza el nmero de bloques
restantes y el tiempo, despus genera un tablero nuevo listo para jugar, comprueba que
haya movimientos disponibles y desactiva el movimiento de los bloques que pueda estar
animando el renderizador y devolvindolos a la posicin original, finalmente activa el
evento para el sonido de cambio de nivel y termina devolviendo un verdadero.

void intercambiaBloques(int x, int y, int x2, int y2)

Este mtodo cambia dos bloques de posicin en la matriz, segn los parmetros recibidos.
Lo nico que hace es comprobar que las posiciones se encuentren dentro de la matriz y
entonces intercambia los bloques usando un temporal para la copia.

private void aplicaGravedad()

108
La funcin que aplica la gravedad a los bloques. Recorre la matriz de bloques
comprobando si han sido eliminados, en cuyo caso desplaza los superiores hacia abajo.

public void animadaAplicaGravedad()

Lo llamaremos una vez que el renderizador haya terminado de animar los bloques con la
de gravedad. Aplicaremos la gravedad a los bloques y rellenaremos los bloques borrados,
comprobaremos si no hay movimientos disponibles en cuyo caso cambiaremos el estado a
Sin Movimientos. Continuamos comprobando si al aplicar gravedad y rellenar el tablero
hay nuevas lneas a eliminar con eliminaBloques() eliminando los bloques que formen
lnea y comprobamos si hay un cambio de nivel, si no es as y se han eliminado nuevos
bloques activamos el booleano de aplicagravedad para indicar al renderizador que genere
la animacin de gravedad de nuevo.

private void tableroAleatorio()

Este mtodo da colores aleatorios a todos los bloques de la matriz. Simplemente


recorremos la matriz, creando un color aleatorio y asignndolo a la posicin actual, si el
color es un comodn volvemos a generar un color aleatorio, para reducir la probabilidad de
que se produzcan.

private void rellenaTablero()

Esta funcin lo que hace es rellenar con un color aleatorio las casillas del tablero que
encuentre vacas, es decir cuando el color del bloque sea -1. Para ello recorremos la matriz
y cuando encontramos una casilla vaca generamos un color aleatorio, si es un comodn
volvemos a generar para reducir la probabilidad de que se produzca.

private boolean buscaMovimientos()

Devuelve verdadero si existe al menos un movimiento disponible en el tablero que forme


lnea, tambin registra el valor de las posiciones de los bloques que al cambiar forman
lnea, por si el jugador pulsa sobre la lupa. Devuelve falso en el caso contrario. Para ello
recorremos la matriz de bloques intercambiando el bloque actual con bloque superior
mediante intercambiaBloques(), comprobamos si forman lnea, en cuyo caso devolvemos
los bloques a su posicin inicial registramos las posiciones de los bloques y salimos del
mtodo devolviendo true. En caso contrario volvemos a intercambiar los bloques para

109
volverlos a su posicin inicial, y hacemos exactamente lo mismo que hasta ahora con el
bloque inferior, despus con el izquierdo y finalmente con el de la derecha. Finalmente si
ningn bloque forma lnea en cruz devolvemos un false.

public void tiempoCorre()

Lo llamaremos desde PantallaJuego y sirve para actualizar el tiempo. Primero


comprobamos si el estado se encuentra es Sin Movimientos en cuyo caso, no trascurre el
tiempo y ponemos el tiempoAnterior a 0 para indicar que hemos parado el contador de
tiempo. Si hay movimientos cogemos el tiempo de inicio si es la primera vez que se inicia
el juego, si ha sido pausado o si nos habamos quedado sin movimientos, sino cogemos el
tiempo actual para calcular el tiempo transcurrido. Se lo restamos al tiempo de juego y
reiniciamos el tiempo anterior para la siguiente llamada. Finalmente comprobamos si el
tiempo de juego ha finalizado en cuyo caso pondremos el estado a fin de juego.

public void noMoves()

Este mtodo lo llamamos desde PantallaJuego cuando termina la cuenta atrs de la


pantalla Sin Movimientos. En el generamos un nuevo tablero con tableroAleatorio() y lo
dejamos listo para jugar con limpiaTablero(), finalmente comprobamos que haya
movimientos disponibles sino cambiamos el estado a Sin Movimientos.

public void lupa()

Cuando el jugador pulsa sobre una lupa llamamos a este mtodo. Aqu tan slo
decrementamos las lupas disponibles, activamos el listener de lupa pulsada y activamos el
boolano dibujaLupa para que el renderizador sepa que debe dibujar la ayuda al usuario.

5.2.3.5.3 TableroRenderer
Esta clase es la que se encarga de dibujar los bloques que son los que componen el tablero
de juego.

Primero definimos las constantes, para los colores de los bloques, azul, rojo, amarillo,
blanco, morado, verde, comodn y borrado. Despus para las animaciones de los bloques:
arriba, abajo, izquierda, derecha y gravedad. Finalmente las constantes que definen las
posiciones en pantalla de los bloques: xInicio e yInicio que es la posicin del primer bloque

110
y offsetX y offsetY que indican el desplazamiento entre bloques, cuando estn sin
movimiento en el tablero. Ver figura 65.

Figura 65. Posiciones (fijas) de los bloques en pantalla.

Despus definimos las variables: tendremos una instancia a tablero y una al lote de
modelos con el que dibujaremos los bloques. Guardaremos dos matrices posicionesX y
posicionesY con las que guardaremos las posiciones fijas de los bloques en la pantalla
cuando no se estn moviendo, las usaremos para comparar cuando animemos los bloques.
Emplearemos posX y posY para calcular estas posiciones. Usaremos una matriz gravedad
para crear el efecto de animacin de cada de los bloques, en ella guardaremos la
coordenada Y hasta dnde caern. Usaremos fila y columna para calcular el intercambio de
bloques. Finalmente utilizamos las variables i, j, a, b, y k para recorrer la matriz de bloques
evitando la creacin y destruccin de objetos impidiendo as que se ejecute el Recolector
de basura.

El constructor guarda las instancias al tablero y al lote de modelos que se recibe por
parmetro, e inicia los miembros correspondientemente.

Los mtodos de la clase son:

public void render()

Con este mtodo dibujamos los bloques en pantalla. Primero comprobamos si desde el
tablero se ha activado el booleano de aplicarGravedad, en caso afirmativo significa
significa que se han eliminado bloques y debemos crear la animacin de cada por
gravedad, as que llamamos al mtodo animandoGravedad() que mira que bloques deben
111
animarse y calcula la coordenada Y hasta la que debern caer los bloques. Despus
recorremos la matriz de bloques, comprobando si tablero ha activado el movimiento de
alguno con el booleano moviendo, en cuyo caso llamamos al mtodo animandoBloques()
para que se inicie la animacin de intercambio de bloques, despus dibujamos el bloque
con la funcin dibujaBloque() y en ltimo lugar comprobamos si se activ el booleano
dibujaLupa que significa que el usuario toc la ayuda, en este caso la dibujaremos con
dibujaAyuda().

public void animandoBloques(int i, int j)

Es el mtodo que usamos para crear el efecto de animacin de los bloques, tanto para el
intercambio como la gravedad. En l actualizamos la posicin en pantalla del bloque del
cual recibe la posicin por parmetro. Primero mira en qu direccin vamos a animar. Si la
direccin de la animacin es cualquier intercambio de bloques (derecha, izquierda, arriba o
abajo), calculamos la fila y columna del bloque con el que vamos hacer el intercambio.
Comprobamos si la posicin del bloque que se est moviendo coincide con la posicin que
debe alcanzar, comparando en la matriz de posiciones fijas correspondiente, si no ha
llegado an a su posicin actualizamos las coordenadas correspondientes a los dos bloques
que se estn intercambiando. Despus miramos si ha finalizado de animar comprobando la
posicin otra vez en cuyo caso desactivamos el booleano moviendo de los bloques,
llamamos a restablecePos() para fijar los bloques en las posiciones fijas y entonces
comprobamos si no los habamos cambiado ya (cuando no forman lnea) en cuyo caso
sincronizamos con tablero para que los intercambie y compruebe si forman lnea, si ste
detecta que no forman lnea volver a indicar que deben animarse en direccin contraria e
indicar con el booleano cambiado que los hemos cambiado pero no forman lnea. Si por el
contrario ya los habamos intercambiado, le decimos a tablero que los intercambie para que
vuelvan a su posicin inicial y marcamos de nuevo el booleano cambiado a false.

Si la direccin del bloque es Gravedad hacemos lo mismo, comprobamos si la posicin del


bloque ha alcanzado la que debe, esta vez comparando con la matriz de gravedad, si no es
as decrementamos la posicin. Despus miramos si hemos terminado de animar,
comprobando si ha llegado a la posicin que debe, en cuyo caso indicamos que hemos
terminado de animar el bloque, poniendo el booleano moviendo a false y la direccin a 0.
Despus comprobamos si hemos terminado de aplicar la gravedad a todos los bloques

112
llamando a animandoGravedad(), si es as sincronizamos con el tablero para que aplique la
gravedad.

private void restablecePos()

Este mtodo lo llamamos despus de hacer la animacin de intercambio de bloques, en l


actualizamos la posicin de los bloques intercambiados a la posicin fija de pantalla que
tenemos almacenada en las matrices de posicionesX y posicionesY.

public boolean animandoGravedad()

Esta funcin recorre la matriz de bloques comprobando an se est aplicando la gravedad


en algn bloque en cuyo caso nos devuelve un true y si no es as nos devuelve un false.

public void aplicandoGravedad()

Este mtodo calcula las nuevas coordenadas en pantalla que debern alcanzar los bloques a
los que se le va aplicar la animacin de gravedad y las guarda en la matriz gravedad. Para
ello recorre la matriz de bloques a lo ancho, comprobando las filas. Esta vez empezando
por la fila de abajo y mira si hay un bloque eliminados, guarda la fila en que se encuentra
en la variable k, comprueba si es la primera fila, si es as guardamos la misma coordenada
Y en la matriz gravedad porque ya est en la ltima fila y no se desplazar, pero activa el
booleano moviendo para que sincronice con el tablero desde la funcin
animandoBloques(). Luego bajamos la posicin de todos los bloques que se encuentren por
encima, decrementando k hasta la fila 0 indicamos la animacin de gravedad a los bloques.
Guardando la posicin a la que caern, a la fila siguiente ms el contador, (que indica los
bloques eliminados de la columna). Finalmente cuando termina de recorrer la matriz
cambia el booleano aplicandoGravedad del tablero a false.

dibujaBloque(int x, int y)

El mtodo dibuja el bloque de la matriz indicado en la posicin x,y usando el lote de


modelos. Para ello comprueba el color del bloque para dibujar la regin de la textura
correspondiente en las coordenadas de la pantalla del bloque.

public void dibujaAyuda()

Con sta funcin dibujamos en el tablero una flecha con un intercambio posible de
bloques, cuando el usuario haya pulsado una lupa. Comparamos la posicin de los bloques
113
a intercambiar para saber dnde dibujar la flecha, y la dibujamos en el medio de los dos
bloques, (posicin ms la mitad del desplazamiento). En el caso que sea vertical dibujamos
la flecha rotada noventa grados.

114
6 Evaluacin

Para llevar a cabo la evaluacin del proyecto las pruebas se han realizado en los siguientes
dispositivos:

Huawei U8650 con Sistema Operativo Android 2.3 y una pantalla de 480x320
pixeles.

Samsung Galaxy Mini, con Sistema Operativo Android 2.2 y una pantalla de
240X320 pixeles.

Figura 66. Samsung Galaxy Mini y Huawei U8650.

La evaluacin del correcto funcionamiento de las distintas partes del framework se ha ido
realizando a medida que se iban implementando.

Por otra parte una vez implementadas las pantallas y las transiciones se ha comprobado que
funcionen correctamente.

Comprobamos tambin que el juego guarda la configuracin cuando recibe una


interrupcin (pulsando la tecla home o al recibir una llamada en el telfono) As pues al
retomar el juego, regresa en el estado en que se encontraba (sonido, puntuaciones, las
texturas se recargan) y vuelve en la pantalla dnde estbamos, si estbamos en la pantalla
de juego, al retomarlo se encontrar en el men pausa.

La mecnica de juego responde como se esperaba, los bloques se intercambian, forman


lneas, desaparecen y se aplica la gravedad generando nuevos bloques aleatorios. El
comodn elimina todos los bloques del tablero de un color. El tiempo y los bloques
restantes se restablecen al pasar de nivel y termina el juego al acabarse el tiempo. Cuando

115
el tablero se queda sin movimientos aparece la pantalla Sin Movimientos con la cuenta
atrs, durante este tiempo el tiempo de juego restante no se altera.

Grficamente se aprecia la diferencia entre las resoluciones de los dos mviles. Esto es
debido a que OpenGl ES escala los grficos en el Samsung Galaxy mini, perdiendo calidad
sobre todo en lo que refiere a las fuentes Bitmap.

En lo que refiere al rendimiento, hemos comprobado los fps (fotogramas por segundo)
gracias a la clase implementada, tanto en el Huawei como en el Samsung Galaxy mini
alcanzan una tasa estable de unos 60fps. Observamos que alguna vez se activa el Colector
de Basura, pero comprobamos que apenas se nota cuando jugamos. Figura 67.

Figura 66. Midiendo el rendimiendo desde el log del sistema. Huawei.

En cuanto a velocidad en el dispositivo Huawei apreciamos las animaciones un poco ms


lentas que en Samsung Galaxy Mini, esto es debido a que a menor resolucin OpenGl
trabaja ms rpido, y no tuvimos en cuenta el tiempo de las animaciones.

116
7 Coste

El propsito de este proyecto era aprender sobre Android y videojuegos con el sub-
objetivo de no invertir capital en l. Gracias a que las herramientas de desarrollo para
Android son gratuitas, los recursos grficos los hemos generado para el proyecto y los
recursos sonoros estn cogidos prestados, se ha logrado este objetivo, el capital
invertido es cero.
Sin embargo con ciertos cambios y una pequea inversin, podramos intentar hacer
rentable este proyecto a travs de Google Play.
Google Play, anteriormente conocida como Android Market es una tienda de software
en lnea para dispositivos Android. A nivel de desarrollador representa una manera de
publicar la aplicacin e intentar rentabilizarla. Para ello se debe pagar una nica tasa de
25 dlares estadounidenses (unos 18) para obtener una cuenta de desarrollador. A
partir de aqu existen dos formas de sacar rentabilidad a las aplicaciones:

Subirlas como aplicacin de pago con un precio mnimo de 0,50 el desarrollador


se lleva un 70% de las ganancias.
Incluyendo banners de publicidad en la aplicaciones con libreras como las
proporcionadas por AdMob[16] de la propia Google, algo parecido al servicio de
publicidad por internet AdSense.

Figura 67. Icono Market y ejemplo AdMob, publicidad en la aplicacin.

117
Los cambios que deberamos llevar a cabo en este proyecto son los siguientes:

La msica tiene licencia libre, pero el autor exige que se le acredite en el juego.
Los efectos de sonido habra que cambiarlos, pues han sido cogidos prestados.
Tambin habra que investigar si la fuente usada para los textos del juego, es de
licencia libre, sino habra que pagarla o cambiarla.

118
8 Trabajos Futuros

Teniendo en cuenta que hemos creado un framework para Android totalmente reutilizable,
podramos crear un nuevo videojuego/aplicacin con slo especificar, disear e
implementar sus partes.

Por otra parte Blocks podra mejorar con un poco ms de tiempo invertido en l.

Los diseadores exponen que para que un videojuego sea bueno debe tener una buena
MDA (Mecnica Dinmica Esttica) [16].

La mecnica hace referencia a las reglas del juego.

La dinmica a cmo se comporta el juego mientras se ejecuta.

La esttica a la experiencia emocional del jugador con el juego.

La mecnica est comprobada que funciona ya que el juego es un clon de Bejeweled, quiz
podramos aadir elementos de cara al futuro por ejemplo: tableros distintos, bloques
especiales con efectos, incluso cambios de gravedad.

En lo que refiere a la dinmica de juego podra mejorarse para tener un acabado ms


profesional (crear animaciones, comprobar el rendimiento en distintos dispositivos, que los
bloques se generen ms rpido y no aparezcan de la nada, cambiar el contador de tiempo
por una barra que se vaya gastando, aadir nuevos sonidos). Tambin podran generarse
grficos en distintas resoluciones para que el juego se adaptase a distintas pantallas sin
perder calidad.

Seguramente lo que refiere a la esttica mejorara con lograr implementar una buena
dinmica y quiz aadiendo algn modo de juego ms como un modo historia con niveles
desbloqueables.

El juego est implementado la versin 2.2 de Android aunque seguramente funciona en


versiones anteriores, debera verificarse. OpenGL ES 1.0 prcticamente es compatible con
todas las versiones de Android.

119
120
9 Conclusiones

Personalmente el proyecto me entusiasm desde el principio, unir las nuevas tecnologas


con el desarrollo de un videojuego me pareci un buen reto para el final de carrera.
Durante el desarrollo han ido surgiendo muchos problemas, uno de los ms remarcables es
una mala planificacin temporal, seguramente debida a la falta de conocimientos previos e
inexperiencia que han provocado que el trabajo de documentacin y sobre todo de pruebas
haya sido extenso.

La correccin de errores en la sincronizacin de las animaciones tambin se ha convertido


en verdaderos quebraderos de cabeza, creo que fall a la hora de disearlas puesto que las
implement posteriormente a la lgica del juego y no tuve en cuenta varios factores, opino
que con ms tiempo hubiese mejorado el rendimiento del cdigo y de la memoria gastada.

En general estoy muy satisfecho con el resultado obtenido ya que puedo decir que he
logrado cumplir todos los objetivos que habamos marcado al principio del proyecto: Se ha
realizado un videojuego para mvil completamente funcional desde cero, de partidas cortas
y rpidas, con mecnica sencilla pero adictiva, multidispositivo y que gestiona las
interrupciones correctamente, adems se ha creado un framework para posibles futuros
proyectos.

A nivel de conocimientos adquiridos tambin se han logrado los objetivos planteados: He


aprendido cmo funciona el sistema Android y el desarrollo de aplicaciones para ste
sistema operativo. Tambin me ha ayudado a aprender sobre diseo y desarrollo de
videojuegos, y a utilizar la tecnologa de OpenGL ES.

Tengo consciencia de las limitaciones del juego, s en qu podra mejorar y cmo debera
hacerlo sin embargo estoy muy contento con el resultado de mi primera aplicacin Android
y a la vez mi primer videojuego.

El hecho de haber trabajado en un proyecto con tecnologa muy actual y con un gran futuro
por delante, me hace ser optimista sobre lo que personalmente puedo aportar a las
empresas interesadas en este mbito, por ello estoy convencido de que me facilitar la tarea
de buscar trabajo.

121
122
10 Recursos Utilizados

Hardware:

PC con CPU AMD 2Ghz, 1Gb RAM con Windows XP

Mvil Huawei U8650, CPU 600Mhz, 256MB RAM

Mvil Samsung Galaxy Mini

Software:

Eclipse

J2SE 1.4.2 de Sun Microsystems

SDK Android

AVD

OpenGL ES 1.0

Bitmap Font Generator

Gimp

Microsoft Office

Gantt project

123
124
11 Planning Temporal.

El proyecto no se ha desarrollado siguiendo un calendario estricto, dado que era imposible


cuantificar el tiempo que tomara el adquirir las bases tericas necesarias para poder
afrontarlo con garantas. Hacemos un diagrama de Gantt para ver el tiempo empleado en
cada una de las fases. Hemos utilizado el programa de distribucin libre Gantt Project [17].

Figura 68. Diagrama de Gantt.


125
126
12 Referencias

[1] [ESRB, estadsticas industria del Videojuego] Diciembre 2012


http://www.esrb.org/about/video-game-industry-statistics.jsp

[2] [Wikipedia, sobre Bejeweled] Diciembre 2012


http://en.wikipedia.org/wiki/Bejeweled.

[3] [Wikipedia, Patrn MVC Modelo Vista Controlador] Diciembre 2012


http://es.wikipedia.org/wiki/Modelo_Vista_Controlador

[4] [The Whistle Song, Free Music] Diciembre 2012


http://www.pedroalonsopablos.com/en/free-music/

[5] [Gimp] Diciembre 2012


http://www.gimp.org/

[6] [Bitmap Font Generator] Diciembre 2012


http://www.codehead.co.uk/cbfg/

[7] [JDK Java] Enero 2012


http://www.oracle.com/technetwork/java/javase/downloads/index.html

[8] [Eclipse] Enero 2012


http://www.eclipse.org/downloads/

[9] [SDK Android] Enero 2012


http://developer.android.com/sdk/index.html

[10] [Plugin ADT para Eclipse] Enero 2012


http://developer.android.com/intl/es/tools/sdk/eclipse-adt.html

[11] [Google, Compilador Jit para Android Dalvik] Diciembre 2012


http://www.google.com/intl/es-CL/events/io/2010/sessions/jit-compiler-androids-dalvik-vm.html

[12] [conferencia de Google IO Writing Real Time Games Android.] Diciembre 2012
http://www.google.com/events/io/2009/sessions/WritingRealTimeGamesAndroid.html

[13] [Khronos Group, OpenGL ES 1.X] Diciembre 2012


http://www.khronos.org/opengles/1_X

[14] [Documentacin oficial de Java] Febrero 2012


http://docs.oracle.com/javase/1.4.2/docs/api/java/nio/Buffer.html

[15] [Pooling, Wikipedia] Febrero 2012


http://en.wikipedia.org/wiki/Pool_%28computer_science%29

[16] [Diseo de videojuegos, Mecnica, Dinmica, Esttica] Febrero 2012


http://www.cs.northwestern.edu/%7Ehunicke/MDA.pdf

127
[17] AdMob, publicidad en las aplicaciones.] Diciembre 2012
http://www.google.com/ads/admob/

[18] [Gantt Project] Febrero 2012


http://www.ganttproject.biz/

128

Вам также может понравиться