Desarrollo de un videojuego para Nintendo DS

Transcripción

Desarrollo de un videojuego para Nintendo DS
Departament d’Enginyeria Informàtica i M atemàtiques
Desarrollo de un videojuego para Nintendo DS
TITULACIÓN: Ingeniería Técnica en Informática de Gestión.
AUTORA: Noemí Ferrer Ortiz.
DIRECTOR: Pere Millán Marco.
FECHA: Junio / 2010
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Índice
1 – Objetivos del proyecto
2
2 – Especificaciones del proyecto
2.1 – Especificación del Hardware de la Nintendo DS
2.2 – SDK disponibles
2.3 – Librería Palib
2.3.1– Entrada / Salida
2.3.2– Sonido
2.3.3– Sprites
2.3.4– Backgrounds
2.3.5– Texto 16bit y Custom Font
2.3.6– Sistema de ficheros FAT
3
3
3
4
6
7
9
13
14
15
3 – Diseño
3.1 – Desarrollo de la partida
3.2 – Evolución de la mascota
3.3 – Minijuego del Simón
17
17
23
27
4 – Desarrollo
4.1 – Estructura de ficheros
4.1.1 – Fichero main.cpp
4.1.2 – Clase partida
4.1.3 – Clase botones
4.1.4 – Clase pantalla
4.1.5 – Clase de idiomas
31
31
32
34
36
37
39
5 – Evaluación
5.1 – Posibles ampliaciones
40
40
6 – Conclusiones
41
7 – Recursos utilizados
42
8 – Anexos
44
1
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
1- OBJETIVOS DEL PROYECTO
El objetivo de este proyecto de final de carrera es desarrollar un juego para Nintendo DS. En
concreto, el juego consiste en una mascota virtual, a la que se ha de alimentar y jugar con ella para
que se desarrolle.
La idea está basada en uno de los primeros juegos de mascotas virtuales llamado
Tamagotchi, que fue creado en 1996 por Aki Maita y comercializado por Bandai.
En este juego se utilizará básicamente la touch screen, para mostrar el potencial de una
consola portátil con capacidad táctil.
El juego está disponible en 3 idiomas: Inglés, Castellano y Catalán. De esta manera el juego
es accesible a más personas. En un futuro pueden añadirse más idiomas al juego modificando una
clase.
El nombre del video juego es Virtual Kachiku, donde Kachiku significa mascota en japonés.
2
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
2 – Especificaciones del proyecto
En este juego el usuario deberá escoger una de las cuatro mascotas disponibles, darle un
nombre y así empezará el juego.
Todos los gráficos del juego son de diseño propio y están realizados en Flash y retocados con
Photoshop para adaptarlos a la paleta de colores de NDS.
Uno de los objetivos de utilizar estos gráficos es que el juego tenga una interfaz amigable para
cualquier tipo de jugador, ya sea niño, adulto o anciano.
El sistema de sonido avisa cuando a la mascota le falta algún cuidado, como por ejemplo si tiene
hambre, es feliz o no, o si está mal de salud.
El jugador puede interactuar con su mascota dándole de comer escogiendo entre una gran variedad
de platos, cada uno con unas características únicas que hacen que se tenga que ser cuidadoso a la
hora de alimentarlo, si se quiere que la mascota tenga buena salud y crezca bien.
Para que la mascota sea feliz y ayudarla a tener una vida saludable, el usuario podrá jugar a un
minijuego incorporado, que consiste en repetir con la pantalla táctil una secuencia de colores que se
mostrarán por pantalla. Tiene 3 rondas y la dificultad es progresiva.
Finalmente, dependiendo de la salud, el hambre y la felicidad de la mascota, ésta evolucionará de
una forma u otra y su aspecto cambiará entre dos estados diferentes.
A lo largo del día el escenario cambiará dependiendo de si es de día o de noche. Esto se consigue
gracias a las funciones de interacción con el hardware que ofrece Palib, estas funciones nos indican
la hora real en la que nos encontramos.
2.1 - Especificación de hardware de la Nintendo DS
Nintendo DS es una consola portátil creada por la compañía Nintendo en el año 2004. Desde
el lanzamiento de su primer modelo (DS), han aparecido nuevas versiones: DS Lite, Dsi, Dsi XL, y
3DS (que está en desarrollo y fue anunciada el 23 de marzo de 2010). La consola es capaz de
procesar operaciones gráficas 3D por hardware.
Podemos elegir entre diversas librerías para el desarrollo del juego. En este caso
utilizaremos una librería opensource. Las librerías opensource disponibles son Libnds y Palib.
Libnds es una librería que trabaja a más bajo nivel. Palib utiliza Libnds e implementa una librería de
más alto nivel. Este proyecto ha sido desarrollado con una DS Lite utilizando la librería Palib.
2.2 – SDK Disponibles
Para empezar a programar el proyecto, se ha de elegir un SDK (software development kit).
Podemos elegir entre dos bien diferenciados:
El SDK oficial llamado CodeWarrior Development Studio de la compañía Metroworks.
− Ventajas:
• Acceso total a los recursos de la consola.
3
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
• Soporte oficial de Nintendo y Metroworks.
• Genera software de calidad profesional.
− Desventajas
• Hay que solicitar a Nintendo ser desarrollador.
• Hay que pagar el precio de la licencia del SDK a Metroworks.
DevKitARM + PALib:
− Ventajas:
• Es gratuito.
• Es compatible con Windows, Linux y Mac Os X.
− Desventajas
• No aprovecha al máximo los recursos de la consola.
• No tiene soporte oficial.
• Se necesita un emulador para probar el juego, y una tarjeta flash card para poder
utilizar el juego en la consola.
2.3 - Librería Palib
PALib es una librería especial para Nintendo DS creada para poder desarrollar aplicaciones
de homebrew. Se denomina homebrew a todas aquellas aplicaciones y juegos programados por
aficionados. PALib esta basada en la librería Libnds, que trabaja a más bajo nivel.
Para poder ejecutar nuestros juegos y aplicaciones desarrollados en PALib, necesitaremos
una tarjeta flashcard compatible con nuestra consola.
Para empezar a trabajar con PALib, instalaremos DevKitPro. DevKitPro es un paquete de
herramientas para el desarrollo de homebrew, en el que se incluyen las librerías necesarias para
programar en diferentes consolas, tales como GameBoy Advance (GBA), Nintendo DS, Nintendo
Wii, GameCube, PSP y GP32. DevKitPro está disponible en diferentes sistemas operativos:
Windows, Mac y Linux.
A la hora de instalar DevKitPro, tendremos la opción de instalar las librerías para Nintendo
DS y GBA (devkitARM), las de GameCube y Wii (devkitPPC) y las dedicadas a PSP (devkitPSP).
En este caso escojeremos el paquete de desarrollo para Nintendo DS (devkitARM) tal y como
muestra la siguiente imagen:
4
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Figura 1- Instalación de DevkitPro
Es importante también tener instalado .NET Framework, ya que sin esto, PALib no
funcionará correctamente. Debemos tener en cuenta que DevKitPro y PALib no podemos instalarlos
en carpetas cuyos nombres contengan espacios, ya que sinó no funcionarán. La mejor opción es
instalar ambas herramientas en la ruta C:\devkitPro en el caso de Windows.
Al ejecutar el instalador de PALib podremos elegir qué queremos instalar y qué no, tal y
como se muestra a continuación:
5
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Figura 2 – Instalación de PALib
Es recomendable instalar la documentació de PALib y sus ejemplos, aunque no sean
necesarios para su funcionamiento, ya que son una gran ayuda para el desarrollo de las aplicaciones.
Cuando tengamos todo instalado, deberíamos tener una carpeta como la siguiente:
Figura 3 – Carpeta de devkitPro
2.3.1 - Entrada/Salida
En Nintendo DS disponemos de varias opciones de entrada y salida de datos: el stylus (lápiz
o puntero), Pad (botones), micrófono, pantalla, etc.
Palib nos permite utilizar todos estos recursos para poder elaborar juegos con una alta
6
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
capacidad de interacción con el usuario.
En nuestro juego tendremos que comprobar los estados de los dispositivos de entrada y
salida en cada frame. Se denomida frame a una iteración del bucle de nuestro juego.
Pad: es el conjunto de botones de la consola (A, B, X, Y, R, L, up, down, left, right, select y
start). El pad se actualiza a cada frame y utiliza los estados Held, Released y Newpress. Held tiene
como valor inicial 0 y cambia al valor 1 cuando se presiona el botón. Released toma el valor 1
cuando se deja de apretar un botón y Newpressed toma el valor 1 cuando se presiona un botón
(estos dos últimos casos permanecen con el valor 1 un solo frame).
Un ejemplo de utilización del pad con las funciones de Palib.
if(Pad.Held.Up)
{
MoveUp();
}
if(Pad.Held.Down)
{
MoveDown();
}
Stylus: al igual que el pad, se actualiza en cada frame y tiene los estados Held, Released y
Newpressed, que funcionan igual que con el pad. Además tiene los atributos X e Y que nos informa
de las coordenadas donde se ha producido el evento.
Un ejemplo de utilización del stylus con funciones Palib:
if (Stylus.Held)
{
PA_OutputSimpleText(1,0,0,"Stylus activo");
}
2.3.2– Sonido
Palib no puede reproducir sonidos mp3 o wav directamente, por lo que tendremos que
utilizar una de las dos librerías que ofrece: ASlib o Maxmod. En este caso se ha utilizado la librería
Aslib, con la que se pueden llegar a reproducir sonidos mp3 y raw.
En un principio podríamos pensar que el formato mp3 sería un buen candidato para
reproducir nuestros sonidos, pero en realidad es mejor no utilizar mp3 en nuestras aplicaciones para
Nintendo DS ya que su reproducción ocupa mucha memoria y no es óptimo. En vez de mp3,
utilizaremos sonidos en formato raw.
Para conseguir un sonido en raw utilizaremos Switch, un programa para convertir sonidos
entre diferentes formatos. A continuación se puede observar una imagen del programa:
7
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Figura 4 - Switch
Haremos click en Encoder Options y pondremos la siguiente configuración. De esta manera
optimizaremos el espacio y la calidad que tendrá el fichero de acuerdo a las características de la
consola.
Figura 5 – Características del formato raw
Cuando ya tenemos el archivo de sonido convertido al formato raw, lo copiamos a la carpeta
/data de nuestro proyecto. Para poder utilizar el sonido tendremos que inicializar el sistema de
sonido de la consola en nuestro código, además de incluir el sonido como si de una librería se
tratara:
#include "simon1.h"
sonido::sonido(){
//Inicializamos el sonido del juego (raw)
AS_Init(AS_MODE_SURROUND | AS_MODE_16CH);
AS_SetDefaultSettings(AS_PCM_8BIT, 11025, AS_SURROUND);
canal = AS_SoundDefaultPlay((u8*)musica1,musica1_size, 127, 64,
true, 0);
}
Para reproducir el sonido, simplemente tendremos que utilizar la función AS_SoundQuickPlay
que nos ofrece Palib:
8
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
void sonido::Play(int opcion){
switch(opcion){
case BOTON: AS_SoundQuickPlay(boton); break;
case SONIDO_BOTON_AMARILLO: AS_SoundQuickPlay(simon1); break;
case SONIDO_BOTON_ROJO: AS_SoundQuickPlay(simon2); break;
case SONIDO_BOTON_AZUL: AS_SoundQuickPlay(simon3); break;
case SONIDO_BOTON_VERDE: AS_SoundQuickPlay(simon4); break;
case INCORRECTO: AS_SoundQuickPlay(incorrecto); break;
case JUEGO_GANADO: AS_SoundQuickPlay(ganar); break;
case SONIDO_EVOLUCION: AS_SoundQuickPlay(evolucion); break;
case ATENCION: AS_SoundQuickPlay(atencion); break;
}
}
Para reproducir la música de fondo del juego también utilizamos la librería Aslib y el
formato raw. En concreto se utiliza un archivo de sonido que puede repetirse formando un bucle.
Aslib nos ofrece una función para la reproducción continua de un archivo, donde si marcamos loop
como true, hará un blucle con el archivo de sonido; si loop es false, el archivo sólo se reproducirá
una vez:
AS_SoundDefaultPlay(u8 *data, u32 size, u8 volume, u8 pan, u8 loop, u8 prio)
Si queremos parar la reproducción, simplemente tendremos que utilizar la función:
AS_SoundStop(canal);
2.3.3 – Sprites
Los sprites son un tipo de mapa de bits, generalmente de pequeño tamaño, de forma
rectangular o cuadrada y que contiene espacios transparentes. De esta manera podemos hacer
cualquier dibujo dentro de este rectángulo. En Nintendo DS son muy utilizados los sprites, ya que
ocupan poca memoria y son más óptimos que si crearamos nuestros personajes y objetos en 3D.
La consola puede mostrar hasta 128 sprites a la vez por cada pantalla, lo que hace un total de 256
sprites. Además cada sprite puede ser rotado, movido, escalado, etc.
Por cada modificación del sprite (rotación, escalado) se creará un rotset. La memoria de la
consola tiene la limitación de que sólo puede almacenar 32 rotsets diferentes. Varios sprites pueden
asociarse al mismo rotset. Se denomina rotset a un conjunto de funciones que modifican un sprite,
un rotset puede contener funciones de escalado y/o rotación.
Como hemos dicho antes, los sprites son rectangulares y de pequeño tamaño. En Nintendo
DS además contamos con una tabla que nos dice qué tamaños pueden usarse para crear nuestros
sprites:
9
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
8
16
32
8
8x8
16x8
32x8
16
8x16
16x16
32x16
32
8x32
16x32
32x32
64x32
32x64
64x64
64
64
Además del tamaño del sprite, también tenemos que elegir el modo de color del mismo,
pudiendo elegir entre sprites con paletas de 16 o 256 colores, o sprites de 16 bits (65536 colores) sin
paleta.
Los sprites con paletas de 16 colores consumen menos memoria y eran muy utilizados en
GBA (Game Boy Advance), pero con Nintendo DS ya no son tan utilizados ya que disponemos de
más memoria. Este tipo de sprites admite hasta 16 paletas diferentes por pantalla.
Normalmente utilizaremos los sprites con paletas de 256 colores. Al igual que los de 16
colores, también podemos contar con hasta 16 paletas diferentes por pantalla.
Los sprites de 16 bits no tienen una paleta de colores asignada y no son muy utilizados ya
que consumen mucho espacio y memoria de vídeo, por lo que no son óptimos en comparación con
los anteriores mencionados.
A continuación se muestra una imagen de la Nintendo DS donde se especifica el tamaño en
píxeles y tiles de ambas pantallas. La imagen nos servirá de referencia a la hora de elegir el tamaño
de nuestros sprites y colocarlos en la pantalla. Se denomina tile a un conjunto de 8x8 píxeles, que se
utilizan para definir imágenes de fondo de pantalla.
Figura 6 – Nintendo DS
Al crear nuestros sprites deberemos tener en cuenta que también crearemos una paleta de
colores. Pero deberemos tener cuidado de no crear una paleta por cada sprite, ya que si tenemos más
de 16 sprites, habremos gastado la memoria de paletas. Lo más optimo es compartir paletas entre
10
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
sprites.
En Nintendo DS no podemos crear sprites en formato bmp y cargarlos directamente. Antes
tendremos que convertirlos a un formato específico para que la consola los entienda y sepa
interpretarlo. Para ello utilizaremos un programa llamado PAGfx, en el que fácilmente cargamos los
sprites que deseamos convertir y le indicamos qué nombre de paleta queremos que tenga. Si
ponemos el mismo nombre de paleta para diferentes sprites querrá decir que comparten esa paleta.
En la siguiente imagen se muestra como hemos cargado los sprites de comida que
posteriormente se utilizarán en el juego. Se le asigna la paleta de 256 colores y además, para todos
los sprites, les asignamos la paleta comida, ya que con una sola paleta de 256 colores tenemos
suficientes colores para todos estos sprites.
Figura 7 - PAGfx
Tendremos que especificar cuál será nuestro color transparente. En éste caso se ha elegido el
magenta, que suele ser el más utilizado, aunque también se puede especificar otro color. Cuando ya
tenemos todos los sprites en el programa, seleccionamos Save and Convert y nos aparecerá una lista
de ficheros en la carpeta /bin de PAGFx.
11
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Figura 8 - Sprites
Se nos habrán creado ficheros con extensión bin, de los cuales, comida_Pal.bin es la paleta
correspondiente para todos nuestros sprites. Lo último que nos quedará por hacer será cargar los
sprites al juego con las funciones de PA_LoadSpritePal, que carga una paleta de colores asociada al
identificador del sprite. Posteriormente, cargaremos el sprite con PA_CreateSprite que asigna al
identificador del sprite el fichero bin correspondiente (se especifica su tamaño):
PA_LoadSpritePal(0, PIZZA, (void*)Pal_Pal);
PA_CreateSprite(0,PIZZA,(void*) pizza_Sprite, OBJ_SIZE_64X64, 1, 0, x, y);
En ocasiones necesitaremos sprites animados que simulen el movimiento de un personaje, o
también como en el caso de este juego, botones animados para que cambien de color cuando se
activen.
Figura 9 – Sprites animados
Estos sprites se cargan igual que los simples, sólo tendremos que utilizar una función extra
que nos ofrece PALib para indicar cuál será la animación del sprite y cómo será. En el caso de los
botones tendremos 3 frames diferentes, cada uno de 32x32 píxeles respetando los tamaños posibles.
En el caso de las mascotas, tendremos 2 frames diferentes de 64x64 píxeles.
12
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
2.3.4 – Backgrounds
Para cargar backgrounds en el juego, utilizaremos el mismo programa que para los sprites, el
Pagfx, con la diferencia de que añadiremos la imagen de fondo a convertir en la pestaña de
backgrounds y no en la de sprites.
Nintendo DS puede mostrar hasta 4 fondos diferentes por cada pantalla. En el caso de los
fondos, no se pueden compartir paletas de colores como en los sprites, por lo que tendremos que
tener este detalle en cuenta. La consola también puede mostrar hasta dos fondos rotándose o
escalándose por pantalla. PALib nos ofrece seis modos diferentes de fondos, el modo de fondo lo
tendremos que especificar en el conversor PAGfx en la columna BbMode. Los diferentes modos son
los listados a continuación:
· 8bit: utiliza una imagen de mapa de bit de 8 bits.
· 16bit: utiliza una imagen de mapa de bit de 16 bits.
· TiledBg: se utiliza en fondos planos. Los tamaños posibles son: 256×256, 512×256,
256×512 y 512×512.
· LargeMap: es un modo similar a TiledBg, pero permite tamaños de fondo más grandes,
como cualquier tipo de tamaño.
· RotBg: se utiliza con fondos rotativos con diferentes tamaños: 128×128, 256×256,
512×512 y 1024×1024.
· EasyBg: automáticamente selecciona entre TiledBg y LargeBg, por lo que es el modo más
utilizado.
Podemos utilizar fondos de 8 y 16 bits, pero tienen varios inconvenientes en comparación
con TiledBg y LargeMap. Estos ocupan mucho espacio en la memoria de vídeo, los fondos 8bit
ocupan aproximadamente un 37,5% de la VRAM y los 16bit un 75%, por lo que no son muy
óptimos. Además son muy lentos de pintar en pantalla porque se pintan pixel a pixel, mientras que
los TiledBg y los LargeMap se pintan por tiles.
También tienen algunas ventajas respecto a los TiledBg y LargeMap, y es que al poder usar
fondos de 16 bits no tendremos limitación de paleta de colores y podremos representar todos los
colores que queramos.
Figura 10 - PAGfx
13
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
A diferencia de los sprites, los fondos no pueden compartir paletas, por lo que cada fondo
tendrá su propia paleta de 256 colores.
Figura 11 – Archivos de fondo
PAGfx nos genera este código que tendremos que añadir a nuestra cabecera all_gfx.h:
// Backgrounds:
extern const int simon_Info[3] __attribute__((aligned (4)));
extern const unsigned int simon_Map[768] __attribute__((aligned (4)));
extern const unsigned char simon_Tiles[13888] __attribute__((aligned
(4)));
// Palettes:
extern const unsigned short simon_Pal[256] __attribute__((aligned (4)));
2.3.5 – Texto de 16bit y Custom Font
En PALib tenemos varias opciones para mostrar texto por la pantalla de la consola. En este
proyecto utilizaremos texto de 16bit, que permite fácilmente mostrar un texto con un tamaño, un
color y una posición en la pantalla específica. La ventaja de este texto respecto al texto simple, es
que podemos definir un color y un tamaño, mientras que el otro tipo de texto no puede ser
modificado.
PA_Init16cBg(PANTALLA_INFERIOR, 2);
PA_16cText(0,30, 50, 230,250,"Texto en 16bit”,10, 2,1000);
PA_16cText(pantalla,x, y, x_max,y_max,texto,color, tamaño,limite_texto);
Los parámetros que utiliza la función PA_16cText son los siguientes:
- Pantalla: indicamos la pantalla en la que queremos mostrar el texto: 1 para la pantalla
superior y 0 para la inferior.
- X: coordenada X donde comenzará el texto.
- Y: coordenada Y donde comenzará el texto.
- X_max: coordenada X límite del texto.
14
Noemí Ferrer Ortiz
-
____..............................................PFC: Videojuego para Nintendo DS
Y_max: coordenada Y límite del texto.
Texto: texto que queremos mostrar.
Color: indicamos el color que deseamos con un número entre 1 y 10.
Tamaño: indicamos el tamaño que deseamos para la fuente del texto con un número
entre 0 y 4.
Límite_texto: indica cuál será el número máximo de carácteres que se mostrarán del
texto
Custom font permite personalizar la fuente básica que nos ofrece PALib. Para ello
importaremos los gráficos de la fuente custom a nuestro proyecto. Los gráficos de las fuentes se han
de convertir a un formato compatible con Nintendo DS tal y como hacemos con los backgrounds.
La fuente custom que se ha utilizado en el proyecto es la siguiente:
Figura 12 – Imagen de fuente
Si queremos crear nuestra propia fuente custom, es importante que editemos cada letra
dentro de su correspondiente celda de 8x8 píxeles.
Figura 13 – Imagen de fuente con rejilla para edición
Una vez convertida la imagen, tendremos que indicar en el código que queremos la custom
font asociada con el texto normal de PALib.
//Inicializamos la fuente custom en la pantalla superior
//nuestra fuente custom se llama "font"
PA_InitCustomText(1,0,font);
2.3.6 – Sistema de ficheros FAT
En PALib disponemos de dos opciones a la hora de guardar información en la memoria: FAT
y EFS. Con FAT podremos guardar ficheros en la flashcard, a los cuales podremos acceder
posteriormente desde el ordenador. EFS incrusta datos en la rom del juego, por lo que no serán
accesibles desde cualquier otro sitio.
La FAT (File Allocation Table) es un sistema de ficheros, que fue desarrollado en 1977 por
Bill Gates y Marc McDonald, para MS-DOS. Al ser un sistema de ficheros relativamente sencillo,
se ha incorporado en diferentes sistemas, tales como sistemas operativos varios, tarjetas de memoria
y dispositivos similares.
15
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
En el caso de este proyecto, se ha escogido el sistema FAT para crear el fichero de partidas
del juego. Para inicializar el sistema FAT, utilizaremos la función correspondiente de la librería:
fatInitDefault();
La lectura y escritura en el sistema FAT de Nintendo DS se realiza con las funciones
habituales del lenguaje C de lectura y escritura en ficheros. En la clase partida realizaremos una
lectura del fichero binario de la siguiente manera:
void partida::Init(){
FILE *f;
f = fopen("NDS/VirtualKachiku.sav", "rb");
if(f==NULL){
//El fichero no existe, crearemos uno nuevo con partidas
//vacías
f = fopen("NDS/VirtualKachiku.sav", "wb");
fwrite(&buffer, sizeof(save), MAX_PARTIDA, f);
fclose(f);
}
else{
//Existe un fichero de partidas guardadas
//Cargamos la información del fichero a nuestro búffer de
//partidas
fread(&buffer, sizeof(save), MAX_PARTIDA, f);
MostrarPartidas();
fclose(f);
}
}
16
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
3 – DISEÑO
3.1 – Desarrollo de la partida
Cuando carguemos la rom en nuestra consola nos aparecerá la siguiente pantalla, donde
deberemos escojer el idioma en el que deseamos jugar:
Figura 14 – Pantalla de inicio
Una vez escojido el idioma, tendremos la opción de escojer una nueva partida o de cargar
una partida anterior. Si escojemos la opción de continuar, nos aparecerá una lista con 3 slots para
guardar partidas. Si no teníamos ninguna partida guardada, nos aparecerá el mensaje Ninguna
partida guardada, pero si ya teníamos alguna partida, nos saldrá una breve información de ella, tal
como el nombre del usuario y el nombre de la mascota.
17
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Figura 15 – Pantalla de nuevo juego/continuar
Figura 16 – Pantalla de partidas guardadas
Si escojemos la opción Continuar y seleccionamos una de las partidas guardadas, el juego
cargará los datos almacenados en el fichero binario en la clase partida. La función utilizada es muy
sencilla: se trata de la función Load de la clase partida, a la que le pasaremos el número del slot (0
para el primero, 1 para el segundo y 2 para el tercero) y nos cargará la información del fichero
binario en la clase partida. La función devuelve 1 si todo ha ocurrido correctamente, 0 en el caso
contrario.
int partida::Load(int i){
if(buffer[i].idpartida!=-1){
setIdPartida(buffer[i].idpartida);
setIdMascota(buffer[i].idmascota);
setEdad(buffer[i].edad);
setPeso(buffer[i].peso);
setHambre(buffer[i].hambre);
setFelicidad(buffer[i].felicidad);
setNombre(buffer[i].mascota);
setUser(buffer[i].nombre);
return 1;
}
else{
return 0;
}
}
Si escojemos la opción de nuevo juego, nos aparecerá un teclado para introducir nuestro
nombre de usuario y el nombre de la mascota. El nombre de ambos ha de tener un mínimo de tres
letras para que se considere correcto y se pueda continuar. Si se introduce uno de los dos nombres
con menos de 3 letras, se le informa al usuario y se espera a que se introduzca un nombre de tres
letras o más.
El teclado que aparece en la pantalla, es un teclado proporcionado por la librería de PALib.
18
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
La decisión de utilizar este teclado de la librería y no uno propio es que el diseño del teclado de
PALib es mucho más logrado. Al hacer un teclado propio, se han de programar todas las teclas y
carácteres especiales, lo que complica su realización.
Figura 17– Nuevo jugador
Figura 18 – Nombre de jugador mal introducido
Para utilizar el teclado de PALib simplemente tendremos que inicializarlo y posteriormente
mostrarlo por pantalla, con la función PA_SetKeyboardColor(1,0). Además podremos modificar el
esquema de colores del teclado:
PA_InitKeyboard(1);
PA_KeyboardIn(23, 90);
PA_SetKeyboardColor(1, 0);
Una vez escojido el nombre de usuario y de la mascota, tendremos que elegir una de entre 4
mascotas diferentes. La que elijamos será la que deberemos alimentar y cuidar para que evolucione
a una mascota buena.
19
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Figura 19 – Selección de mascota
Cuando seleccionamos una de las mascotas, o en el caso de que hayamos cargado una
partida, nos aparecerá la pantalla de juego principal, donde estará nuestra mascota moviéndose por
la habitación. El fondo del juego cambia según la hora del día.
Figura 20 – Pantalla de juego
Entre las 7 de la mañana y las 8 de la tarde se mostrará el fondo de día, y desde las 8 de la
tarde hasta las 7 de la mañana siguiente se mostrará el fondo de noche. Para saber qué fondo
debemos cargar según la hora, utilizaremos las herramientas que PALib nos ofrece para recojer
información del Hardware de la Nintendo DS. La variable de PALib PA_RTC.Hour nos indica la
hora del sistema:
20
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
/*
Pantalla del juego
Habitación de la mascota
*/
void pantalla::FondoJuego(){
c.cls(PANTALLA_INFERIOR);
PA_Init16cBg(PANTALLA_SUPERIOR, 2);
c.cls(PANTALLA_SUPERIOR);
PA_EasyBgLoad(PANTALLA_SUPERIOR, 3, fondo3);
if(PA_RTC.Hour<20){
if(juego.getIdioma()==SPANISH){
PA_EasyBgLoad(PANTALLA_INFERIOR,
}
else if(juego.getIdioma()==ENGLISH){
PA_EasyBgLoad(PANTALLA_INFERIOR,
}
else if(juego.getIdioma()==CATALAN){
PA_EasyBgLoad(PANTALLA_INFERIOR,
}
}
else{
if(juego.getIdioma()==SPANISH){
PA_EasyBgLoad(PANTALLA_INFERIOR,
}
else if(juego.getIdioma()==ENGLISH){
PA_EasyBgLoad(PANTALLA_INFERIOR,
}
else if(juego.getIdioma()==CATALAN){
PA_EasyBgLoad(PANTALLA_INFERIOR,
}
}
3, habitacion_dia);
3, habitaciondia_en);
3, habitaciondia_ca);
3, habitacion_noche);
3, habitacionnoche_en);
3, habitacionnoche_ca);
Stylus.X=0;
Stylus.Y=0;
PA_SetTextCol(PANTALLA_SUPERIOR, 31, 31, 31);
PA_SetTextCol(PANTALLA_INFERIOR, 31, 31, 31);
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PJ1BEBE,
PJ2BEBE,
PJ3BEBE,
PJ4BEBE,
-128,
-128,
-128,
-128,
-128);
-128);
-128);
-128);
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PA_SetSpriteXY(PANTALLA_INFERIOR,
PIZZA, -128, -128);
HOTDOG, -128, -128);
ENSALADA, -128, -128);
HAMBURGUESA, -128, -128);
SOPA, -128, -128);
HELADO, -128, -128);
PUDDING, -128, -128);
SUSHI, -128, -128);
PASTEL, -128, -128);
PA_SetSpriteXY(0, juego.getIdMascota(), 30, 100);
}
En el lado izquierdo de la pantalla aparecen unos iconos que indican si la mascota tiene
hambre, si quiere jugar o si no está muy sana. Al mostrar los iconos, además sonará un sonido para
avisar al usuario de que la mascota necesita cuidados. Los iconos son los siguientes:
21
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Figura 21 – Iconos de estados
Cuando se muestra el corazón en la pantalla quiere decir que la mascota tiene poca salud y
que el usuario ha de jugar con ella para que mejore su salud. Si se muestra el dibujo de la cara se
refiere a que la mascota no está del todo feliz y el usuario tendrá que jugar con ella para que su
nivel de felicidad aumente. El pastelito nos indicará que la mascota tiene hambre y tendremos que
alimentarla con alguno de los alimentos disponibles que tenemos.
Dependiendo de la comida que suministremos a nuestra mascota, el nivel de sus estados
variará. Cuando seleccionemos el alimento en cuestión, un texto nos indicará una breve descripción
de la comida y los estados que modifica. En el caso siguiente se muestra la información del Helado:
Figura 22 – Pantalla de selección de comida
En el caso del Helado veremos que aumenta el estado de alimentación de nuestra mascota en
1 punto, le aumenta 3 puntos de felicidad, pero le quitará 2 puntos de salud, lo que querrá decir que
no es tan bueno para su salud como si comiera la ensalada, pero a cambio le hará más feliz.
Gracias a los diferentes estados que modifica cada alimento, conseguimos una manera más
dinámica y divertida de jugar, ya que deberemos saber escojer qué alimentos suministrar a nuestra
mascota para que crezca sana y feliz.
22
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
3.2 – Evolución de la mascota
Durante el desarrollo del juego, se comprobará el estado de la mascota y el tiempo de juego
transcurrido. Todas las funciones relacionadas con el control de la mascota se encuentran en el
fichero control.cpp.
En todos los videojuegos deberemos implementar una función, normalmente llamada Idle(),
que se ejecuta en cada iteración del programa. En esta función llevamos a cabo todo el control de la
evolución de la mascota y la modificación de sus estados.
void control::Idle(){
if(fondo==JUEGO){
tiempo++;
juego.setEdad(juego.getEdad()+1);
}
/*
Cada 2 minutos actualizamos el estado de la mascota
disminuyendo los estados de hambre y felicidad.
*/
if(tiempo>=(MINUTO*2)){
tiempo=0;
if(juego.getHambre()>0)
juego.setHambre(juego.getHambre()-1);
if(juego.getFelicidad()>0)
juego.setFelicidad(juego.getFelicidad()-1);
}
/*
Han pasado 3 minutos. La mascota crecerá y evolucionará
con un aspecto u otro dependiendo de si estaba bien
cuidada o no.
*/
if(juego.getEdad()==MINUTO){
s.Play(ATENCION);
waitS(3);
PA_SetSpriteXY(0, EVOLUCION, PA_GetSpriteX(0,
juego.getIdMascota()), PA_GetSpriteY(0, juego.getIdMascota()));
//Empieza la animación de la evolución
s.Play(SONIDO_EVOLUCION);
PA_SetSpriteAnim(0, EVOLUCION, 5);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 4);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 3);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 2);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 1);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 0);
PA_SetSpriteXY(0, juego.getIdMascota(), -128, -128);
//Cambiamos el sprite de la mascota según su estado
if((juego.getFelicidad()*juego.getHambre())>=9){
PA_SetSpriteXY(0, juego.getIdMascota(), -128, -128);
23
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
switch(juego.getIdMascota()){
case PJ1BEBE: juego.setIdMascota(PJ1BUENO);
case PJ2BEBE: juego.setIdMascota(PJ2BUENO);
case PJ3BEBE: juego.setIdMascota(PJ3BUENO);
case PJ4BEBE: juego.setIdMascota(PJ4BUENO);
}
break;
break;
break;
break;
}
else{
switch(juego.getIdMascota()){
case PJ1BEBE: juego.setIdMascota(PJ1MALO);
case PJ2BEBE: juego.setIdMascota(PJ2MALO);
case PJ3BEBE: juego.setIdMascota(PJ3MALO);
case PJ4BEBE: juego.setIdMascota(PJ4MALO);
}
break;
break;
break;
break;
}
PA_SetSpriteXY(0, juego.getIdMascota(), PA_GetSpriteX(0,
EVOLUCION), PA_GetSpriteY(0, EVOLUCION));
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 1);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 2);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 3);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 4);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 5);
PA_SetSpriteXY(0,EVOLUCION, -128, -128);
waitS(1);
}
}
A continuación se describe el código anterior, explicando qué hace exactamente cada parte
de la función.
Si estamos jugando con la mascota, es decir, si nos encontramos en la pantalla de juego, la
mascota se irá haciendo mayor, por lo que su edad debe aumentar:
if(fondo==JUEGO){
tiempo++;
juego.setEdad(juego.getEdad()+1);
}
Cada dos minutos modificaremos el hambre y la felicidad, disminuyéndolos en una unidad.
De esta manera el juego será más interactivo y el usuario tendrá que estar pendiente del estado de su
mascota:
if(tiempo>=(MINUTO*2)){
tiempo=0;
if(juego.getHambre()>0)
juego.setHambre(juego.getHambre()-1);
if(juego.getFelicidad()>0)
juego.setFelicidad(juego.getFelicidad()-1);
}
24
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Cuando pasen tres minutos de tiempo jugado, la mascota evolucionará, y dependiendo de su
estado, se convertirá en una mascota evolucionada u otra. Se han elegido tres minutos para poder
hacer pruebas sin tener que esperar mucho tiempo a comprobar la evolución.
Al evolucionar la mascota, aparece la animación de una especie de humo, con la que
desaparecerá la mascota antigua, y aparecerá la nueva evolución:
if(juego.getEdad()==MINUTO*3){
s.Play(ATENCION);
waitS(3);
PA_SetSpriteXY(0, EVOLUCION, PA_GetSpriteX(0,
juego.getIdMascota()), PA_GetSpriteY(0, juego.getIdMascota()));
//Empieza la animacion de la evolucion
s.Play(SONIDO_EVOLUCION);
PA_SetSpriteAnim(0, EVOLUCION, 5);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 4);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 3);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 2);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 1);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 0);
PA_SetSpriteXY(0, juego.getIdMascota(), -128, -128);
Una vez ejecutada la primera parte de la evolución, se comprueba qué mascota será la
evolucionada que aparecerá al final de la animación del humo. La condición con la que sabremos si
la mascota evolucionará bien o mal es muy sencilla: comprobaremos que su felicidad está como
mínimo a la mitad de su valor posible, igual que el hambre que tenga, y que su peso no sea muy alto
y esté en un valor medio.
Los valores de felicidad, hambre y peso pueden variar de 0 a 10.
//Cambiamos el sprite de la mascota según su estado
if((juego.getFelicidad()>4) && (juego.getHambre()>4) &&
(juego.getPeso()<5) ){
PA_SetSpriteXY(0, juego.getIdMascota(), -128, -128);
switch(juego.getIdMascota()){
case PJ1BEBE: juego.setIdMascota(PJ1BUENO); break;
case PJ2BEBE: juego.setIdMascota(PJ2BUENO); break;
case PJ3BEBE: juego.setIdMascota(PJ3BUENO); break;
case PJ4BEBE: juego.setIdMascota(PJ4BUENO); break;
}
}
else{
switch(juego.getIdMascota()){
case PJ1BEBE: juego.setIdMascota(PJ1MALO); break;
case PJ2BEBE: juego.setIdMascota(PJ2MALO); break;
case PJ3BEBE: juego.setIdMascota(PJ3MALO); break;
case PJ4BEBE: juego.setIdMascota(PJ4MALO); break;
}
}
Para acabar, una vez escojida la mascota evolucionada, se termina la animación de la
evolución:
25
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
PA_SetSpriteXY(0, juego.getIdMascota(), PA_GetSpriteX(0,
EVOLUCION), PA_GetSpriteY(0, EVOLUCION));
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 1);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 2);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 3);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 4);
wait(40);
PA_SetSpriteAnim(0, EVOLUCION, 5);
PA_SetSpriteXY(0,EVOLUCION, -128, -128);
waitS(1);
}
}
Una de las funciones principales para controlar los estados de la mascota y si se ha de
modificar el fondo de pantalla según la hora de la consola, será la función Time de la clase control.
En esta función actualizaremos el reloj en cada iteración (éste reloj se muestra en la pantalla
del juego). Posteriormente comprobamos la hora actual para saber si hemos de cambiar el fondo de
pantalla de día al fondo de noche y viceversa
int control::Time(){
int hora=0;
PA_OutputText(0,26, 23, "%02d:%02d", PA_RTC.Hour, PA_RTC.Minutes);
//Comprobamos si hay algun cambio de hora, para saber si hemos
//de cambiar el fondo del juego
if((PA_RTC.Hour==20)&&(PA_RTC.Minutes==0)&&(PA_RTC.Seconds==0)){
hora=1;
}
if((PA_RTC.Hour==7)&&(PA_RTC.Minutes==0)&&(PA_RTC.Seconds==0)){
hora=1;
}
if(fondo==JUEGO){
//Comprobamos si la mascota tiene hambre, está triste o
//tiene poca salud. Si es así, mostramos el sprite
//correspondiente a su estado
if(juego.getHambre()<5){
PA_SetSpriteXY(PANTALLA_INFERIOR, HAMBRE, 3, 30);
}
if(juego.getFelicidad()<5){
PA_SetSpriteXY(PANTALLA_INFERIOR, FELICIDAD, 3, 65);
}
if(juego.getPeso()>10){
PA_SetSpriteXY(PANTALLA_INFERIOR, SALUD, 3, 90);
}
//Si necesita alguna atención y hace más de 2 minutos
//que sonó el último aviso, activamos el sonido
//de aviso
if( (juego.getHambre()<5) || (juego.getFelicidad()<5) ||
(juego.getPeso()>5) ){
sonidoatencion++;
if(sonidoatencion>=2*MINUTO){
sonidoatencion=0;
s.Play(ATENCION);
}
}
26
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
}
return hora;
}
3.3 – Minijuego del Simón
Para que nuestra mascota se ponga contenta, se ha de jugar con ella. Por ello se ha
implementado un minijuego para interactuar con la mascota, el del Simón. El juego consistirá en
apretar los botones de colores en el mismo orden que aparecen en la pantalla, durante una serie de
turnos. Si el usuario acierta una cantidad específica de turnos, se considera que ha ganado la partida,
por lo cual la mascota aumentará su nivel de felicidad en función de la cantidad de turnos que el
usuario haya acertado.
Figura 23 – Pantalla de juego de Simón
El juego tendrá cuatro turnos, cada uno con un nivel de dificultad progresivo. Al empezar el
turno, se verá la secuencia de botones a introducir. El número de botones que se iluminarán en cada
turno es:
- Primer turno: 4 botones.
- Segundo turno: 5 botones.
- Tercer turno: 6 botones.
- Cuarto turno: 8 botones.
En un futuro podría modificarse fácilmente el número de botones de cada turno, además del
número de turnos, ya que la función básica que implementa el minijuego del Simón es muy sencilla
y fácilmente modificable, tal y como podemos comprobar en el código siguiente:
void simon::Start(){
27
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
//Por cada turno crearemos unos números aleatorios que
//corresponderán a los botones de colores.
msg(1);
Turno(4);
msg(2);
Turno(5);
msg(3);
Turno(6);
msg(4);
Turno(8);
if(aciertos>2){
//Juego ganado
juego.setFelicidad(juego.getFelicidad()+2);
ganar(1);
}
if(aciertos==2){
//Juego ganado
juego.setFelicidad(juego.getFelicidad()+1);
ganar(1);
}
if(aciertos==4){
//Juego ganado
juego.setFelicidad(juego.getFelicidad()+4);
ganar(1);
}
if(aciertos<2){
//Juego perdido
juego.setFelicidad(juego.getFelicidad()-1);
ganar(0);
}
aciertos=0;
c.waitS(1);
s.PlayMusic();
}
En el futuro, si deseáramos modificar el número de botones de cada turno, sólo deberíamos
modificar su parámetro, es decir, Turno(1) crea un turno con un único boton en su secuencia,
Turno(30) crearía un turno con una secuencia de 30 botones. Cada botón de la secuencia se calcula
de manera aleatoria.
Con la función Turno, creamos un turno de la partida con tantos botones en la secuencia
como indiquemos en el parámetro, y esperamos a que el usuario presione los botones. Esta función
además se encarga de controlar cuántos botones acierta el usuario.
El código de la función Turno es el siguiente:
void simon::Turno(int pulsaciones){
int i=0;
int j=0;
PartidaAcabada=0;
//Generamos la secuencia de colores del juego
while(i<pulsaciones){
//Haremos un random para saber qué botón se iluminará
opciones[i]=PA_Rand()%4;
switch(opciones[i]){
case 0: boton_amarillo(); break;
28
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
case 1: boton_rojo(); break;
case 2: boton_azul(); break;
case 3: boton_verde(); break;
}
i++;
}
i=0;
while((i<pulsaciones)&&(PartidaAcabada==0)){
while(!Stylus.Newpress) c.wait();
if(PA_SpriteTouched(BOTON_ROJO)){
s.Play(SONIDO_BOTON_ROJO);
PA_SetSpriteAnim(0, BOTON_ROJO, 2);
while(!Stylus.Released) c.wait();
PA_SetSpriteAnim(0, BOTON_ROJO, 0);
if( (opciones[i]+13)!=BOTON_ROJO) {
s.Play(INCORRECTO);
c.waitS(1);
PartidaAcabada=1;
}
i++;
}
if(PA_SpriteTouched(BOTON_AZUL)){
s.Play(SONIDO_BOTON_AZUL);
PA_SetSpriteAnim(0, BOTON_AZUL, 2);
while(!Stylus.Released) c.wait();
PA_SetSpriteAnim(0, BOTON_AZUL, 0);
if((opciones[i]+13)!=BOTON_AZUL){
s.Play(INCORRECTO);
c.waitS(1);
PartidaAcabada=1;
}
i++;
}
if(PA_SpriteTouched(BOTON_AMARILLO)){
s.Play(SONIDO_BOTON_AMARILLO);
PA_SetSpriteAnim(0, BOTON_AMARILLO, 2);
while(!Stylus.Released) c.wait();
PA_SetSpriteAnim(0, BOTON_AMARILLO, 0);
if((opciones[i]+13)!=BOTON_AMARILLO){
s.Play(INCORRECTO);
c.waitS(1);
PartidaAcabada=1;
}
i++;
}
if(PA_SpriteTouched(BOTON_VERDE)){
s.Play(SONIDO_BOTON_VERDE);
PA_SetSpriteAnim(0, BOTON_VERDE, 2);
while(!Stylus.Released) c.wait();
PA_SetSpriteAnim(0, BOTON_VERDE, 0);
if((opciones[i]+13)!=BOTON_VERDE){
s.Play(INCORRECTO);
c.waitS(1);
PartidaAcabada=1;
}
i++;
}
29
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
}
//Si ha acertado la secuencia de botones sumamos un punto
if(i>=pulsaciones) aciertos++;
}
Al acabar todos los turnos evaluaremos el número de aciertos o fallos que haya hecho el
usuario. Cuantos más aciertos hagamos, más feliz será nuestra mascota, como podemos observar en
las siguientes condiciones.
Si el jugador acierta un mínimo de tres turnos, la felicidad de la mascota aumentará en dos
unidades:
if(aciertos>2){
//Juego ganado
juego.setFelicidad(juego.getFelicidad()+2);
ganar(1);
}
Si el usuario sólo acierta la mitad de los turnos, su mascota sólo obtendría una unidad de
felicidad, como se puede observar en el codigo.
if(aciertos==2){
//Juego ganado
juego.setFelicidad(juego.getFelicidad()+1);
ganar(1);
}
La mayor cantidad de felicidad, cuatro unidades, la recibirá cuando el usuario haga una
partida perfecta. Esto quiere decir que no cometa ningun fallo en los cuatro turnos en los que se
desarrolla el juego.
if(aciertos==4){
//Juego ganado
juego.setFelicidad(juego.getFelicidad()+4);
ganar(1);
}
Si el usuario sólo acertase un turno, se considerará el juego como perdido y su mascota
disminuirá su felicidad en una unidad, como se observa en el código. En consecuencia, el usuario
debería volver a jugar con ella para aumentar su felicidad.
if(aciertos<2){
//Juego perdido
juego.setFelicidad(juego.getFelicidad()-1);
ganar(0);
}
30
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
4 – DESARROLLO
4.1– Estructura de ficheros
El lenguaje en el que se ha desarrollado el juego es C++, ya que obtendremos las ventajas de
trabajar con un lenguaje orientado a objetos.
C++ es un lenguaje de programación orientado a objetos fruto de la evolución del lenguaje
C. Fue creado en 1980 por Bjarne Stroustrup con la intención de obtener un lenguaje que permitiera
a los usuarios manipular objetos, cosa que con el lenguaje C no se podía entonces y así mejorar
sustancialmente ese lenguaje.
Al principio su autor llamo a su obra “C con clases” pero fue en 1983 cuando este lenguaje fue
utilizado por primera vez en un laboratorio científico donde empezaron a llamarlo como se le
conoce hoy en dia, C++, siendo este “++” un significado de incremento de C, refiriéndose a que
este lenguaje es una extensión del C.
La estructura de ficheros utilizada es la que aparece en la imagen:
Figura 24 – Estructura de ficheros
Dispondremos de diferentes carpetas y ficheros, las cuales se describen a continuación:
· build: contiene ficheros que genera el compilador.
· data: en esta carpeta se guardan los sonidos del juego, el logo de la rom, y archivos de
recurso que posteriormente serán utilizados en el juego.
· source: la carpeta contiene todos los ficheros de código fuente, cabeceras, ficheros binarios
de sprites y backgrounds (fondos).
31
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
4.1.1 – Fichero main.cpp
El fichero main indica qué funciones serán las primeras en ejecutarse y su orden. Como en
todos los juegos, necesitaremos un bucle infinito, donde en cada iteración comprobaremos el estado
de la mascota.
int main(){
InitGame();
p.SeleccionarBackground(IDIOMAS);
while (1){
b.BotonPresionado();
switch(fondo){
case JUEGO: m.MoverMascota(juego.getIdMascota());
if(c.Time()==1)
p.SeleccionarBackground(JUEGO);
break;
case NUEVO_JUGADOR: b.Teclado();
break;
case MINIJUEGO:
minijuego.Start();
b.Minijuego();
break;
}
c.Idle();
PA_WaitForVBL();
}
return 0;
}
Las variables p, b, m y c hacen referencia a las clases que utilizamos y están definidas en el
fichero main.h de la siguiente manera:
//Declaramos los objetos de clase
pantalla p;
sonido s;
botones b;
movimiento m;
partida juego;
control c;
simon minijuego;
lang idioma;
La primera función que se ejecuta es InitGame() que se encargará de llamar a todas las
funciones de inicialización del sistema de librerías de PALib y nuestras propias funciones de
inicialización.
void InitGame(){
//Inicializa la libreria PALib
PA_Init();
//Inicializa el sistema de PALib para su sincronismo
//en cada iteración
32
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
PA_InitVBL();
//Inicializa el sistema de ficheros FAT
fatInitDefault();
//Inicia el sistema random
PA_InitRand();
//Inicializa las partidas del juego
juego.Init();
//Inicializa el texto con la fuente elegida
PA_InitCustomText(1,0,font);
PA_InitCustomText(0,0,font);
//Inicializa el texto de 16bit
PA_Init16cBg(PANTALLA_INFERIOR, 2);
nomuser = (char*) malloc(sizeof(char)*50);
nommascota = (char*) malloc(sizeof(char)*50);
//Cargamos los sprites del juego
p.Init();
}
33
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
4.1.2 – Clase partida
En esta clase guardaremos la información de la partida actual, los estados de la mascota, su
nombre y el del usuario. Según se avance en el juego, los datos del estado de la mascota se
actualizarán en esta clase.
class partida{
save buffer[MAX_PARTIDA];
int idpartida;
int idmascota;
int edad;
int peso;
int hambre;
int felicidad;
char* nombre;
char* user;
int idiomaJuego;
public:
partida();
void setIdPartida(int);
void setIdMascota(int);
void setEdad(int edad);
void setPeso(int peso);
void setHambre(int hambre);
void setFelicidad(int felicidad);
void setNombre(char* nombre);
void setUser(char* user);
void setIdioma(int);
int getIdPartida() const;
int getIdMascota() const;
int getEdad() const;
int getPeso() const;
int getHambre() const;
int getFelicidad() const;
char* getNombre() const;
char* getUser() const;
int getIdioma() const;
void Init();
void MostrarPartidas();
int Load(int);
void Save(int);
void Alimentar(int);
~partida();
protected:
void IniBuffer();
};
Cuando empieza el juego, la función Init() de la clase partida es llamada en el fichero
main.cpp. Ésta función se encarga de cargar datos de partidas anteriores a la memoria. Comprueba
si ya existe un fichero del juego con datos guardados; si este existe, leerá el fichero y cargará los
datos a memoria, mostrándolos posteriormente por pantalla con la función MostrarPartidas(). Si no
hay ningún fichero con partidas anteriores guardadas, entonces procederá a crear un nuevo fichero
en el que posteriormente serán guardados los datos de nuestra partida.
34
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
void partida::Init(){
FILE *f;
f = fopen("NDS/VirtualKachiku.sav", "rb");
if(f==NULL){
//El fichero no existe, crearemos uno nuevo con partidas vacias
f = fopen("NDS/VirtualKachiku.sav", "wb");
fwrite(&buffer, sizeof(save), MAX_PARTIDA, f);
fclose(f);
}
else{
//Existe un fichero de partidas guardadas
//Cargamos la información del fichero a nuestro buffer de partidas
fread(&buffer, sizeof(save), MAX_PARTIDA, f);
MostrarPartidas();
fclose(f);
}
}
35
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
4.1.3 – Clase botones
Ésta será la clase encargada de gestionar el funcionamiento de la interacción del usuario con
el juego.
class botones{
public:
botones();
void BotonPresionado();
void Alimentar();
void Minijuego();
void Teclado();
~botones();
private:
void Idiomas();
void BotonesJuego();
void BotonesInicio();
void BotonesSeleccion();
void CargarPartida();
void Estado();
void FuncionComida(int);
};
En el fichero main.cpp utilizamos la función BotonPresionado() dentro del bucle infinito
para comprobar en cada iteración si se aprieta alguno de los botones de la consola. Según la pantalla
en la que nos encontremos (en inicio, en selección de idioma, en cargar partida, etc.) en la función
BotonPresionado llamaremos a una función u otra de la clase Botones, para controlar las acciones
que se deban llevar a cabo.
void botones::BotonPresionado(){
if(Stylus.Newpress){
switch(fondo){
case JUEGO:
case INICIO:
case SELECCION:
case ESTADO:
case CARGAR_PARTIDA:
case MINIJUEGO:
case IDIOMAS:
case COCINA:
}
}
}
36
BotonesJuego(); break;
BotonesInicio(); break;
BotonesSeleccion(); break;
Estado(); break;
CargarPartida(); break;
Minijuego(); break;
Idiomas(); break;
Alimentar(); break;
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
4.1.4 – Clase pantalla
Es la clase encargada de gestionar los cambios de las imágenes de fondo de las 2 pantallas
de la consola.
class pantalla{
public:
pantalla();
void SeleccionarBackground(int fondo);
void Init();
~pantalla();
private:
void FondoInicio();
void FondoSeleccion();
void FondoJuego();
void Estado();
void NuevoJugador();
void CargarPartida();
void Idiomas();
void FondoCocina();
void FondoMinijuego();
void CargarMascota(int id_mascota, void* sprite, int x, int y);
void CargarEvolucion(int id_evolucion, void* sprite, int x, int y);
void CargarComida(int id_comida, void* sprite, int x, int y);
void CargarCuadroTexto(int id_cuadro, void* sprite, int x, int y);
void CargarBoton(int id_boton, void* sprite, int x, int y);
void CargarFondo(int);
};
En la función InitGame() del fichero main.cpp llamamos a la función Init() de la clase
pantalla, que se encargará de cargar los sprites a memoria para poderlos utilizar más adelante:
void pantalla::Init(){
CargarMascota(PJ1BEBE, (void*)m1bebe_Sprite, -128, -128);
CargarMascota(PJ1BUENO, (void*)m1bueno_Sprite, -128, -128);
CargarMascota(PJ1MALO, (void*)m1malo_Sprite, -128, -128);
CargarMascota(PJ2BEBE, (void*)m2bebe_Sprite, -128, -128);
CargarMascota(PJ2BUENO, (void*)m2bueno_Sprite, -128, -128);
CargarMascota(PJ2MALO, (void*)m2malo_Sprite, -128, -128);
CargarMascota(PJ3BEBE, (void*)m3bebe_Sprite, -128, -128);
CargarMascota(PJ3BUENO, (void*)m3bueno_Sprite, -128, -128);
CargarMascota(PJ3MALO, (void*)m3malo_Sprite, -128, -128);
CargarMascota(PJ4BEBE, (void*)m4bebe_Sprite, -128, -128);
CargarMascota(PJ4BUENO, (void*)m4bueno_Sprite, -128, -128);
CargarMascota(PJ4MALO, (void*)m4malo_Sprite, -128, -128);
CargarBoton(BOTON_AMARILLO,(void*)boton_amarillo_Sprite,-128,-128);
CargarBoton(BOTON_ROJO, (void*)boton_rojo_Sprite, -128, -128);
CargarBoton(BOTON_AZUL, (void*)boton_azul_Sprite, -128, -128);
CargarBoton(BOTON_VERDE,(void*)boton_verde_Sprite, -128, -128);
CargarBoton(SALUD, (void*)salud_Sprite, -128, -128);
CargarBoton(HAMBRE, (void*)hambre_Sprite, -128, -128);
CargarBoton(FELICIDAD,(void*)felicidad_Sprite, -128, -128);
CargarEvolucion(EVOLUCION, (void*) evolucion_Sprite, -128, -128);
37
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
CargarComida(PIZZA, (void*) pizza_Sprite, -128, -128);
CargarComida(HAMBURGUESA, (void*) hamburguesa_Sprite, -128, -128);
CargarComida(HOTDOG, (void*) hotdog_Sprite, -128, -128);
CargarComida(ENSALADA, (void*) ensalada_Sprite, -128, -128);
CargarComida(SOPA, (void*) sopa_Sprite, -128, -128);
CargarComida(HELADO, (void*) helado_Sprite, -128, -128);
CargarComida(PUDDING, (void*) pudding_Sprite, -128, -128);
CargarComida(SUSHI, (void*) sushi_Sprite, -128, -128);
CargarComida(PASTEL, (void*) pastel_Sprite, -128, -128);
}
38
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
4.1.5 – Clase de idiomas
En esta clase gestionaremos los textos de los diferentes idiomas que tiene el juego: Inglés,
Castellano y Catalán.
class lang{
public:
lang();
void InstruccionesSimon(int,char*);
void Ronda(int,int);
void NoPartida(int,int);
void NomUserShort(int);
void NomMascotaShort(int);
void NomUser(int);
void NomMascota(int);
void Comida(int, int);
void Estado(int,char*,int,int,int);
~lang();
};
En esta clase tendremos funciones como la siguiente, con la que podríamos modificar el texto en
cada uno de los idiomas:
void lang::NomUserShort(int idioma){
PA_Init16cBg(PANTALLA_INFERIOR, 2);
switch(idioma){
case SPANISH:
PA_16cText(0,45, 30, 230,250,"El nombre de usuario es muy
corto. Debe tener al menos 3 letras.",10, 2,1000);
break;
case ENGLISH:
PA_16cText(0,45, 30, 230,250,"User name is too short. It
should have 3 letters or more.",10, 2,1000);
break;
case CATALAN:
PA_16cText(0,45, 30, 230,250,"El nom d'usuari és massa curt.
Ha de tenir 3 lletres o més.",10, 2,1000);
break;
}
}
39
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
5 – EVALUACIÓN
A lo largo del desarrollo del proyecto ha surgido algún que otro problema.
El primer problema que surgió fue la falta de memoria para las paletas de los sprites, ya que
en un primer diseño se creaba una paleta por cada sprite y PALib sólo ofrece 16 paletas diferentes
por pantalla. La solución fue fácil: compartir paletas entre diferentes sprites con ayuda del programa
PAGfx. De esta manera, tendremos una sola paleta donde almacenar hasta 256 colores, que serán
los que se utilizarán en los sprites asociados a esa paleta.
Se han hecho varios test del juego para asegurarnos de que todo funcionase correctamente,
como crear varias partidas para comprobar que no se podían crear más de tres (que es el número
máximo de partidas que se puede guardar).
También se verifica que el jugador no pueda introducir su nombre de usuario o el de su
mascota vacío, ha de contener como mínimo tres letras.
5.1 – Posibles ampliaciones
Ha habido alguna decisión de diseño que no se ha podido llevar a cabo debido, a la falta de
tiempo, como mostrar a la mascota durmiendo a ciertas horas. Para implementar a la mascota
durmiendo, se debería de haber creado un sprite más por cada mascota. Contamos con 12 mascotas
diferentes: cuatro mascotas infantiles, cuatro evolucionadas en adultos buenos y cuatro
evolucionadas en adultos malos.
En un futuro podrían añadirse algunas mejoras, que para este proyecto no se han podido
incluír, como por ejemplo: interacción del usuario con la mascota a través del micrófono, o
conexión de dos juegos en diferentes consolas a través de Wi-Fi para comunicar ambas mascotas.
40
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
6 – CONCLUSIONES
La programación en dispositivos de memoria limitada, como es la Nintendo DS y otras
consolas portátiles, ha de ser más óptima que si estubiéramos programando para un ordenador,
donde disponemos de memoria prácticamente ilimitada.
Si en Nintendo DS queremos cargar muchas imágenes o sonidos, deberemos hacer uso de
librerías adicionales como EFS, en la que se pueden añadir recursos para utilizarlos posteriormente.
Es importante también, saber que no se ha de utilizar MP3 para reproducir música durante un juego,
ya que consume mucha memoria y podría ralentizar el juego en si.
Es importante optimizar el uso de variables y objetos de clase. Por ejemplo, no sería muy
óptimo crear muchas instancias de una misma clase. Lo mejor es tener el mínimo de objetos
posibles. En este proyecto se ha tenido en cuenta la optimización de la memoria y se ha procurado
crear una sola instancia de cada clase.
Una vez finalizado el proyecto, creo que se ha logrado el objetivo de éste, que era crear un
videojuego para Nintendo DS, jugable y divertido. Se ha intentado conseguir que su apariencia
fuera lo más parecida a un juego comercial.
41
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
7 – RECURSOS UTILIZADOS
- Página web oficial de documentación de PALib
http://palib.info/wiki/doku.php
- Página web oficial de DevKitPro
http://www.devkitpro.org/
- Página web oficial del emulador NDesMuMe
http://www.desmume.com/
- Página web oficial del conversor de sonidos Switch
http://www.nch.com.au/switch/
- Página web: foro dedicado al desarrollo de scene en Nintendo DS
http://www.elotrolado.net/foro_nds-scene_130
- Página web dedicada al desarrollo de scene en Nintendo DS
http://nds.scenebeta.com/
- Página web oficial de Visual C++ Express Edition
http://www.microsoft.com/spanish/msdn/vstudio/express/VC/default.mspx
- Página web oficial de Flash
http://www.adobe.com/es/products/flash/
- Página web oficial de Photoshop CS5
http://www.adobe.com/es/products/photoshop/photoshop/
42
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
- Página web oficial de la librería Libnds
http://www.libnds.devkitpro.org/
- Ejemplos de PALib incluídos con la librería
- Página web de referencia de C++
http://www.cplusplus.com/
- Página web oficial de Audacity
http://audacity.es/
- API de PALib
http://www.palib.info/Doc/PAlibDoc%20Eng/modules.html
- Página web oficial de descarga de .NET Framework
http://www.microsoft.com/downloads/details.aspx?displaylang=es&familyid=0856eacb4362-4b0d-8edd-aab15c5e04f5
43
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
8 – ANEXOS
Imágenes utilizadas:
Mascotas:
Botones:
Comida:
44
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Fondos de pantalla:
45
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
46
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
47
Noemí Ferrer Ortiz
____..............................................PFC: Videojuego para Nintendo DS
Evolución de la mascota:
48

Documentos relacionados