lunes, 26 de septiembre de 2011

LPGameEngine: Capitulo 1 . SoundManager & ResourceManager

Hola a todos,

Este capítulo vuelve parcialmente obsoleto este otro e implementa lo que se dijo en su momento de un filemanager. Se puede aprender igualmente de él pero ya no cumple las condiciones de diseño actuales.

El cambio de este módulo proviene de dos factores:
- La gestión de recursos por un módulo centralizado (resource manager)
- La posibilidad de implementar varios managers de sonido de forma trivial

La forma de implementar estos cambios se ha realizado gracias al aprovechamiento de la herencia y las clases abstractas de C++. A grandes rasgos, para el que no sepa de que va el tema: herencia es que un clase deriva de otra (tiene características en común)  y clase abstracta significa que la clase madre no sirve para nada más que para tener subclases (de por si no tiene implementación).

Gráficamente podemos observar que la clase SoundManager es la madre de las diferentes clases que se encargan de gestionar el sonido:






Este tipo de estructura hace que en el Core.h no se defina un objeto soundmanager sino un puntero:  SoundManager*    pSound;        //Puntero al módulo gestor de sonido.

Dicho puntero podrá ser rellenado con una dirección a un objeto de cualquiera de los hijos de SoundManager... por ejemplo, dentro del resourceManager, se escoge que manager utilizar y se setea el puntero convenientemente:

void ResourceManager::GestSoundManager(void)
{
//Seteamos puntero

cout << "Sound Manager Driver : " << sound << "\n"; 
if( !sound.compare("NONE") )  {      cout << "SOUND:NONE\n"; Core::singleton().SetPointerSoundManager( NULL );      return;  } if( !sound.compare("OpenAL") )  {      cout << "SOUND:OpenAL\n";      Core::singleton().SetPointerSoundManager( (SoundManager *) new            SoundManager_OpenAL() ) ;      return; if( !sound.compare("FMOD") )          cout << "SOUND:FMOD\n";          Core::singleton().SetPointerSoundManager( (SoundManager *) new SoundManager_FMOD() ) ;          return; } if( !sound.compare("BASS") )          cout << "SOUND:BASS\n";         Core::singleton().SetPointerSoundManager( (SoundManager *) new SoundManager_BASS() ) ;          return;  } //AQUI IRÁN NUEVOS MANAGERS DE SONIDO SI HACEN FALTA. }
Posteriormente se podrá acceder al manager de sonido de esta manera sin importarnos que gestor de sónido tenemos por debajo:
psoundmanager = (SoundManager *) Core::singleton().GetPointerSoundManager();

    //Cargamos sonidos
    psoundmanager->PreLoad();

    //if (!LoadFile( soundroute , loadedSound , psoundmanager->Load ) )
    //    return false;

    TiXmlElement *root = doc.RootElement();
    for(TiXmlElement* element = root->FirstChildElement(); element; element = element->NextSiblingElement()) 
    {
        //Leemos el elemento
        id = element->FirstChild("ID")->FirstChild()->Value();            //tomamos el ID
        ruta = element->FirstChild("ROUTE")->FirstChild()->Value();    //tomamos la RUTA   
       
        //Cargamos el recurso
        loadedSound[id] = psoundmanager->Load(ruta);

        cout << "Sonido: " << id << ruta << "\n";
    }

    psoundmanager->PostLoad();

Ya que vemos este ejemplo hemos de comentar tambíen el gran cambio que se ha producido ahora y es que toda la gestión de los ficheros de recursos (configuraciones XML, audio, texturas, etc... ) pasarán por el resourcemanager que se encargará de gestionar dichos recursos.

La forma estandar de gestionar la carga será mediante la estructura
pmanager->PreLoad(); //Acciones a realizar antes de la carga (inicializaciones)
balbalballbal
pmanager->Load();  //Todo manager tendrá que tener una función de load de 1 solo recuros. El resource manager se encargará de cargar uno a uno todos los recursos.
balbalblablalb
pmanager->PostLoad(); //Acciones a realizar despues de la carga (desinicializaciones)

Todos los managers tendrán que utilizar esta estructura para poder interactuar con el resourcemanager.


Ya finalmente, por si os quereis animar a implementar FMOD y BASS os dejo la implementación con OpenAL para que veais que es trivial implementar nuevos módulos (el código completo lo podeis obtener del repositorio)

/**************************************************************************************************/
//        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
/**************************************************************************************************/

/**************************************************************************************************/
// Implementación del SoundManager con OpenAL
/**************************************************************************************************/
#include "SoundManager_OpenAL.h"

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

using namespace std;

SoundManager_OpenAL::SoundManager_OpenAL()
{
}

SoundManager_OpenAL::~SoundManager_OpenAL()
{
}

//Sounds functions
void SoundManager_OpenAL::Init(int* argc, char* argv[])
{
    cout << "Inicializamos el Sound Manager implementado con OpenAL\n";

    alutInit(argc, argv) ;

    num_element = 0;

}

void SoundManager_OpenAL::DeInit()
{
    cout << "Desinicializamos el Sound Manager implementado con OpenAL\n";
    alutExit();
}

//Todo aquello que se ha de hacer antes de cargar los sonidos
void SoundManager_OpenAL::PreLoad()
{
    cout << "Preparamos buffers de sonido\n";
    alGenBuffers(MAX_SOUNDS,buffer);
}

//Todo aquello que se ha de hacer después de cargar los sonidos
void SoundManager_OpenAL::PostLoad()
{
    cout << "Generamos fuentes de sonido\n";
    alGenSources(MAX_SOUNDS, source);
}

//Función para cargar un elemento con la ruta que se le indica
int SoundManager_OpenAL::Load(string route)
{
    buffer[num_element++]  = alutCreateBufferFromFile ((char *)route.c_str());

    if(num_element >= MAX_SOUNDS)
        return -1;

    return (num_element-1);
}

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

  if(++s == MAX_SOUNDS)
    s = 0;
}
Espero que os haya gustado y hayais disfrutado.

Nos vemos

LordPakusBlog

0 comentarios :

Publicar un comentario

Entradas populares