Академический Документы
Профессиональный Документы
Культура Документы
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 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
9
3.4.3 Ranking. ......................................................................................................... 29
4 Diseo .......................................................................................................................... 35
10
4.9 Framework ........................................................................................................... 46
5 Desarrollo. ................................................................................................................... 49
5.1.7.2 Proyecciones........................................................................................... 61
11
5.2.1 Estructura de Blocks ...................................................................................... 66
12
5.2.3 Los elementos del Juego ................................................................................ 91
9 Conclusiones.............................................................................................................. 121
13
14
1 Introduccin
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
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.
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.
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]
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.
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.
Un sistema Operativo para mvil est pensado para controlar un dispositivo porttil como
un SmartPhone o tableta.
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.
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.
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
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.
1.4.4 BlackBerry OS
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
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.
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.
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
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:
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.
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.
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.
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.
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.
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.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.
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:
27
Para salir del juego bastar con pulsar el botn atrs del dispositivo mvil en cualquier
momento.
3.4.2 Ayuda.
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 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
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.
3.4.4 Preparado.
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.
Sobre el tablero veremos los bloques. En la figura 11 podremos observar una imagen de la
escena 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:
Adems en la parte inferior izquierda se encontrar el botn tctil con el icono sonido, para
activar o desactivar el audio del juego.
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.
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 avanzar de nivel.
- Al eliminar bloques.
- 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
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:
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.
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).
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.
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.
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:
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.
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).
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.
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.
40
Figura 21. Botones del men principal, 128x64 pxeles cada uno.
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 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.
Para crear estos recursos grficos se ha utilizado el programa de edicin Gimp [5] que tiene
licencia de distribucin gratuita.
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.
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.
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.
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.
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 ();
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:
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.
Tambin instalamos Eclipse que ser nuestro entorno de trabajo, desde l compilaremos y
ejecutaremos el cdigo de manera cmoda. [8]
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.
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]
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.
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
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.
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.
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.
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.
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.
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.
En la figura 33 vemos los elementos creados inicialmente para un nuevo 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:
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.
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
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]
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.
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
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.
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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/.
Hemos dividido el cdigo de nuestro videojuego en cuatro paquetes. Todos empiezan por
el nombre com.games.edo.
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.
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.
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:
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.
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.).
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.
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.
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.
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.
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.
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.
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.
70
Nos indica si la tecla que le pasamos se ha presionado o no, consultando su estado en el
array de teclas pulsadas.
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.
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.
Nos servir para obtener los eventos TouchEvent y as gestionar estas entradas. Deberemos
llamarlo frecuentemente para evitar que la lista se llene.
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.
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
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.
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.
Aqu usaremos y clase SoundPool que nos facilita la reproduccin de efectos sonoros.
Manejaremos el archivo con el identificador que asigna al cargarlo.
74
Sus mtodos son:
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.
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.
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)
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.
Estos mtodos nos devuelve la suma de nuestro vector con otro, o con argumentos.
Recordemos la frmula (1)
Estos mtodos nos devuelve la resta de nuestro vector con otro, o con argumentos.
Podemos ver la frmula a continuacin (2)
76
u*k = (x*k, y *k) (3)
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.
Nos devuelve la distancia al cuadrado entre nuestro vector y el vector o coordenadas que le
pasamos.
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.
Vamos a ver la clase camara2D, que usaremos para definir la ventana de visualizacin y la
matriz de proyeccin correctamente.
78
vemos en la figura 52 est comprendida entre (0,0,1) y (frustumWidth, frustumHeight, -1)
y establecemos el zoom como 1.
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.
Figura 53. El bfer de vrtices, las direcciones en que empieza a leer OpenGL, y los
saltos.
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.
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.
80
Nos permite dibujar, toma el tipo de primitiva, (GL10.GL_TRIANGLES), el
desplazamiento y el nmero de vrtices que vamos a dibujar.
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.
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.
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.
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.
ste es el mtodo que usaremos para recargar una textura una vez OpenGL pierda el
contexto, es decir cuando se pause la aplicacin.
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.
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.
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.
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.
Asocia la textura que le pasamos e reinicia los valores para empezar a trabajar con el lote.
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.
La frmula que usamos para rotar los puntos un determinado ngulo es:
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.
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.
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.
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.
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.
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.
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)
Nuestra clase GLJuego tambin implementa la interfaz juego, los mtodos de sta son:
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.
90
Este mtodo nos sirve para consultar la pantalla activa.
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).
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.
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.
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.
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.
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.
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.)
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:
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.
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.
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.
Cuando se pause, lo nico que hacemos es liberar la textura para ahorrar memoria.
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.
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.
Este mtodo funciona igual, nos limitamos a comprobar si pulsamos el botn para volver a
la pantalla del men principal.
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.
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.
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:
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.
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.
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.
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.
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:
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.
101
Figura 61. Pantalla Juego (Fin de juego).
Se encarga de dibujar las lupas de la interfaz, para ello comprobamos cuantas lupas hay
disponibles en el tablero y dibujamos en consecuencia.
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.
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.
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:
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.
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.
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.
public boolean update(int dir, int fila, int col, boolean cambiado)
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.
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().
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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().
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.
112
llamando a animandoGravedad(), si es as sincronizamos con el tablero para que aplique la
gravedad.
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)
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.
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.
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.
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:
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 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.
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.
119
120
9 Conclusiones
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.
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:
Software:
Eclipse
SDK Android
AVD
OpenGL ES 1.0
Gimp
Microsoft Office
Gantt project
123
124
11 Planning Temporal.
[12] [conferencia de Google IO Writing Real Time Games Android.] Diciembre 2012
http://www.google.com/events/io/2009/sessions/WritingRealTimeGamesAndroid.html
127
[17] AdMob, publicidad en las aplicaciones.] Diciembre 2012
http://www.google.com/ads/admob/
128