Mostrando entradas con la etiqueta file manager. Mostrar todas las entradas
Mostrando entradas con la etiqueta file manager. Mostrar todas las entradas

lunes, 6 de junio de 2011

GameEngine: Capitulo 5. File Manager

Hola a todos,

Bienvenidos a una nueva entrega de como crear nuestro propio game engine y no perder (demasiado) nuestro atractivo hacia el sexo opuesto....

Este entrega se centra en eliminar los hardcodeos del módulo del audiomanager. La eliminación de estos hardcodeos solo puede realizarse mediante un fichero de configuración que contenga las rutas de carga de los sonidos y los tags que usaremos para hacer sonar los sonidos.

Esta funcionalidad la hemos encapsulado dentro del Filemanager (la implemenación que os paso está a medias, realmente seria y será mucho más extensa). Dicha clase se encargará de leer el archivo de configuración en cuestión e ir cargando los diferentes archivos de recursos que tenga nuestro juego. Todo esto hará que el sound manager (o cualquier otro modulo que use recursos) sea independiente del código para poder cargar sus archivos.

Se han creado los dos archivos (.h y .cpp ) del FileManager y se ha modificado el soundmanager para que use las nuevas funcionalidades. El core.cpp se ha modificado para usar las nuevas funciones a modo de muestra de funcionamiento.

FileManager.h
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/

/**************************************************************************************************/
// FileManager.h : Código del gestor de archivos del game engine
/**************************************************************************************************/

#ifndef __FileManager__
#define __FileManager__

#define MAX_ELEMENTS_LOADED 256 //por ahora hardcodeado, lo arreglaremos en algún momento.

#include <stdio.h> //por ahora usamos esto... en el futuro lo cambiaremos por los streams de cpp

class FileManager
{
public:
FileManager();
~FileManager();

public:
//Funcion para inicializar el motor de sonido
void Init(char file[]);

//Funcion para desinicializar el motor de sonido
void DeInit();
//Lee una linea del archivo. Retorna true si existe la linea y false si no existe.
bool GetLine(char cad[]);

//SIN IMPLEMENTAR TODAVIA.
//Esta función se encarga de usar la función fptr para cargar un archivo con un cierto formato.
//La función de carga devolverá con que indice se ha cargado un cierto recurso que se le especificará mediante la cadena que se le pasará.
void Load( int (*fptr)(char *) );

//SIN IMPLEMENTAR TODAVIA.
//Esta función nos devuelve que número tiene asociado el recurso con el tag identificativo que le pasamos por parametro.
//El rendimiento de esta función es pésimo, pero por ahora no tiene más valor que el didáctico. En un futuro no demasiado lejano se implementará
//esta funcionalidad mediante un árbol.
int GetID(char cad[]);
private:
FILE *fp; //Fichero al cual encapsulamos
//char loaded[MAX_ELEMENTS_LOADED][256]; //Por ahora hardcodeado... tenemos un vector de strings (en el futuro se hará mediante un árbol de búsqueda)
};

#endif // __FileManager__

FileManager.cpp
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/

/**************************************************************************************************/
// FileManager.h : Código del gestor de archivos del game engine
/**************************************************************************************************/
#include "FileManager.h"

#include <iostream> //Usada para imprimir por consola.

using namespace std;


FileManager::FileManager()
{
}

FileManager::~FileManager()
{
}

//Inicialización del file manager
void FileManager::Init( char file[] )
{
cout << "Inicializamos el file manager del archivo " << file << "\n";
fp = fopen(file,"r");
}

void FileManager::DeInit()
{
cout << "Desinicializamos el file manager\n";
fclose(fp);
}

//Lee una linea del archivo. Retorna true si existe la linea y false si no existe.
bool FileManager::GetLine(char cad[])
{
//Si hemos llegado al final del archivo nos vamos
if( feof(fp) )
return false;

fscanf(fp,"%s\n",cad); //leemos la cadena y la devolvemos

cout << cad << "\n"; //Metemos la linea en el log

return true;
}

//Esta función se encarga de usar la función fptr para cargar un archivo con un cierto formato.
//La función de carga devolverá con que indice se ha cargado un cierto recurso que se le especificará mediante la cadena que se le pasará.
//Se presupone que los archivos de loading están formados por dos cadenas separadas por 1 igual (=, sin espacios), la primera que es un identificador y la segunda que es la ruta del recurso.
void FileManager::Load( int (*fptr)(char *) )
{
/* POR IMPLEMENTAR
char cad[256]; //Cadena donde guardaremos cada linea que leamos
char id[256]; //Cadena donde guardaremos el identificador de cada recurso
char ruta[256]; //Cadena donde guardaremos la ruta de cada recurso
int num_id; //número que nos asigna la función de carga del recurso.... un -1 significa que no lo ha podido cargar

//Leemos cada linea del archivo
while( GetLine(cad) )
{
sscanf(cad,"%s=%s",id,ruta); //Separamos las cadenas
num_id = fptr(ruta); //Cargamos el recurso

if (num_id == -1) //Si el recurso no se ha podido cargar, vamos a cargar el siguiente recurso
continue;

sprintf( loaded[ num_id ] ,"%s" , id ); //Nos guardamos la referencia al recurso
}
*/
}

//Esta función nos devuelve que número tiene asociado el recurso con el tag identificativo que le pasamos por parametro.
//El rendimiento de esta función es pésimo, pero por ahora no tiene más valor que el didáctico. En un futuro no demasiado lejano se implementará
//esta funcionalidad mediante un árbol.
int FileManager::GetID(char cad[])
{
/* POR IMPLEMENTAR
int i; //Iterador

for ( i = 0 ; i < MAX_ELEMENTS_LOADED ; ++i ) //Para cada elemento cargado
{
if( !strcmp(loaded[i],cad) ) //Hemos encontrado la cadena que nos interesa
{
return i; //Nos vamos devolviendo el valor que nos pedian
}
}
*/
return -1; //Si no encontramos lo que buscamos es que no está.
}

SoundManager.cpp
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un game engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/

/**************************************************************************************************/
// SoundManager.h : Código de la parte de audio del game engine
// Caracteristicas especiales: Esta clase implementa un singleton, es decir, solo podrá existir un objeto de esta clase en todo el proyecto
/**************************************************************************************************/
#include "SoundManager.h"
#include "MyGL.h"

#include <iostream> //Usada para imprimir por consola

using namespace std;

//Instancia única del sound manager
SoundManager SoundManager::instance;

SoundManager::SoundManager()
{
}

SoundManager::~SoundManager()
{
}

//Devolvemos el puntero al singleton
SoundManager& SoundManager::singleton()
{
return instance;
}

//Sounds functions
void SoundManager::Init(int* argc, char* argv[])
{
char cad[256]; //Cadena donde guardaremos cada linea que leamos
char id[256]; //Cadena donde guardaremos el identificador de cada recurso
char ruta[256]; //Cadena donde guardaremos la ruta de cada recurso
int num_id; //número que nos asigna la función de carga del recurso.... un -1 significa que no lo ha podido cargar

cout << "Inicializamos el sound manager\n";

alutInit(argc, argv) ;

filemanager.Init("Data\\LoadSound.txt");


alGenBuffers(MAX_SOUNDS,buffer);

//Todo este código tendrá que ir al filemanager, pero por el momento lo dejamos aquí
//Leemos cada linea del archivo
while( filemanager.GetLine(cad) )
{
for( int i = 0 ; i < strlen(cad); ++i)
{
if ( cad[i] == '=' )
{
cad[i]='\0';
sprintf(id,"%s",cad);
sprintf(ruta,"%s",&cad[i+1]);
i = 257;
}
}

num_id = LoadSound(ruta); //Cargamos el recurso
cout << "Intentamos cargar sonido con ruta:" << ruta << "\n";

if (num_id == -1) //Si el recurso no se ha podido cargar, vamos a cargar el siguiente recurso
continue;

cout << "Sonido cargado con identificadores:" << id << " " << num_id << "\n";

sprintf( loaded[ num_id ] ,"%s" , id ); //Nos guardamos la referencia al recurso
}
alGenSources(MAX_SOUNDS, source);
}

void SoundManager::DeInit()
{
cout << "Desinicializamos el sound manager\n";
filemanager.DeInit();
alutExit();
}


//Carga el sonido cad y devuelve su posición en la que se ha guardado
int SoundManager::LoadSound( char cad[] )
{
//TODO : Evaluar los casos en los que el archivo no se puede cargar y devolver un -1 en consecuencia
static int s = 0;

SoundManager::buffer[s++] = alutCreateBufferFromFile (cad);
return (s-1);
}

void SoundManager::Play(int id)
{
static unsigned int s = 0;
alSourcei (source[s], AL_BUFFER, buffer[id]);
alSourcePlay (source[s]);

if(++s == MAX_SOUNDS)
s = 0;
}

void SoundManager::Play(char id[])
{
/*
int sound;
sound = filemanager.GetID(id);

if (sound == -1)
return;

Play( sound );
*/
int i; //Iterador

for ( i = 0 ; i < MAX_ELEMENTS_LOADED ; ++i ) //Para cada elemento cargado
{
if( !strcmp(loaded[i],id) ) //Hemos encontrado la cadena que nos interesa
{
Play( i ); //Hacemos el play del sonido en concreto
return;
}
}
}



Core.cpp

void Core::glut_idle()
{
//Nos sacamos de la manga que de vez en cuando haga sonidos aleatorios
if(!(rand()%100))
{
switch(rand()%5)
{
case 0 :
SoundManager::singleton().Play("SOUND_BOOST");
break;

case 1 :
SoundManager::singleton().Play("SOUND_PASOS");
break;

case 2 :
SoundManager::singleton().Play("SOUND_SALTO");
break;

case 3 :
SoundManager::singleton().Play("SOUND_COIN");
break;

case 4 :
SoundManager::singleton().Play("SOUND_DIE");
break;
}
}

//Repintamos la escena
glutPostRedisplay();
}

En cuanto a la entrega ejecutable es la misma que la del último dia, solamente que incluyendo el archivo Data\\LoadSounds.txt con la información necesaria para cargar el sonido.

Aunque el código no es ni mucho menos definitivo y es extremadamente mejorable, os ha de quedar claro el concepto que todo lo que se pueda sacar del código, mejor. Llegará el punto en el que recompilar el gamengine sea un par de minutos y en ese momento tal vez será demasiado tarde extraer la carga de recursos.

LordPakusBlog
Espero que os haya gustado, si teneis dudas, propuestas de mejores implementaciones o ampliaciones del módulo no dudeis en postearlas.. nos vemoss!!

Entradas populares