Nociones Básicas Sobre OGRE. Parte 2.
Julio 28, 2008
2. Cómo reaccionar a eventos dentro de OGRE, la clase FrameListener.
En esta lección veremos cómo podemos reaccionar a eventos en tiempo de ejecución dentro de OGRE, lo que nos permitirá salir de la aplicación o interactuar por medio del teclado / ratón. Para ello utilizaremos dos clases que vienen incorporadas dentro de esta librería: FrameListener y FrameEvent.
Pero, ¿Qué es un FrameListener? A continuación pongo la definición tal cual viene en la API (traducida, claro):
Un “listener” (oyente) es una interfaz diseñada para ser llamada cuando ocurren ciertos eventos. Esta clase (FrameListener) define la interfaz que se relaciona a eventos de cuadros (frame).
Lo anterior significa que si yo defino un FrameListener, mi aplicación sería capaz de realizar acciones entre cuadro y cuadro. Lo más común es utilizarlo para la captura de eventos de teclado y ratón, o para actualizar el movimiento y la posición de los diferentes objetos ya sea manualmente, o también por medio de alguna biblioteca de simulación de físicas, aunque no está limitado a esas tareas. Siempre que tengamos alguna acción que queramos realizar en cada cuadro, entonces debemos utilizar un FrameListener.
La clase FrameListener contiene 2 métodos virtuales, frameStarted() y frameEnded(). El método frameStarted() es llamado al inicio del cuadro, antes de hacer la actualización de la escena, y el método frameEnded() es llamado después de haber hecho la actualización de la escena y antes de actualizar el siguiente cuadro. Ambos métodos regresan un valor boolean, que le indica al motor gráfico si debe seguir actualizando, o salir del ciclo de actualización (render). Si no re-definimos estos métodos, el valor por defecto es true, o sea, seguir actualizando.
Los métodos frameStarted() y frameListener() tienen además un parámetro de tipo FrameEvent. Este FrameEvent no es mas que una estructura que contiene información acerca del evento, básicamente el tiempo transcurrido (en segundos) desde el último evento (timeSinceLastEvent) y el tiempo transcurrido desde el último cuadro (timeSinceLastFrame). La diferencia entre uno y otro valor es que el primero nos cuenta el tiempo que ha pasado de frameStarted() a framEnded() y viceversa, y el otro el tiempo de frame a frame, o sea de frameStarted() a frameStarted() y de frameEnded() a frameEnded().
Una vez que hemos definido una clase para que sea nuestro FrameListener, necesitamos “registrarla” para que OGRE sepa de su existencia, esto lo hacemos mediante el método addFrameListener() de nuestra clase Root. OGRE además nos permite el uso de múltiples FrameListener si así lo deseamos, pero cada uno que definamos siempre debemos recordar utilizar addFrameListener() para registrarlo y poderlo utilizar. Muchos programadores separan la lógica de su programa en varios FrameListener, pero nosotros, por simplicidad de esta lección, utilizaremos solo uno.
Con esta información, ya podemos hacerle una mejora a nuestro programa que nos permita salir pasados 3 segundos.
Para empezar, modificamos la definición de la clase de nuestra lección anterior (OgreTutorial1.h) de forma que nos quede de la siguiente manera:
class OgreApp : Ogre::FrameListener
Después añadimos la siguiente variable a nuestra clase, que nos permitirá contar el tiempo que ha transcurrido
Ogre::Real mTime;
Añadimos además el siguiente método a nuestra clase, que nos permitirá registrar nuestro FrameListener()
void initEventHandlers()
{
mRoot->addFrameListener(this);
}
Utilizamos el puntero this ya que la clase de nuestra aplicación es a su vez nuestro FrameListener, pero como mencionaba antes, es posible hacerlo en una clase separada, en cuyo caso, podríamos hacer algo como lo siguiente:
fl = new MiFrameListener();
mRoot->addFrameListener(fl);
Definimos nuestros métodos frameStarted() y frameEnded(), y vamos a agregar el código para que pasados 3 segundos, salga de la aplicación. Para esto, vamos a cambiar nuestra variable exit a true si es que han pasado mas de 3 segundos, y como mencionamos antes, necesitamos que regrese un valor de false para indicar que no queremos que siga actualizando el despliegue. En este caso haremos la comprobación al inicio del cuadro, pero podríamos hacerlo al final si lo deseáramos, esto ya dependerá de lo que queramos y necesitemos hacer en nuestra aplicación.
bool frameStarted(const Ogre::FrameEvent &evt)
{
// Incrementamos nuestro contador de tiempo
mTime += evt.timeSinceLastFrame;
// Verificamos si han pasado mas de 3 segundos y salimos
if (mTime > 3)
exit = true;
if (exit == true)
return false;
else
return true;
}
bool frameEnded(const Ogre::FrameEvent &evt)
{
return true;
}
Finalmente vamos a añadir 2 líneas nada mas, initEventHandlers(); dentro del método Go(), antes de crear nuestra escena para registrar nuestro FrameListener, y mTime = 0 dentro de createScene(), para que el contador de tiempo comience de cero.
A continuación pongo el código completo.
OgreTutorial2.h
#include "Ogre.h"
class OgreApp : Ogre::FrameListener
{
public:
Ogre::Root* mRoot;
Ogre::RenderWindow* mWindow;
Ogre::SceneManager* mSceneMgr;
Ogre::Camera* mCamera;
Ogre::Viewport* mViewport;
Ogre::Real mTime;
bool exit;
bool bufferedInput;
OgreApp()
{
exit = false;
mRoot = NULL;
mWindow = NULL;
}
~OgreApp()
{
if (mRoot != NULL)
delete mRoot;
}
void go()
{
createRoot();
setupRenderSystem();
if (exit == true)
return;
else
{
createRenderWindow();
initEventHandlers();
createScene();
startRenderLoop();
}
}
void createRoot()
{
// Crea el objeto root, la base de todo el sistema de OGRE
mRoot = new Ogre::Root();
}
void setupRenderSystem()
{
// Mostrar cuadro de dialogo para elegir sistema de render
// y resolucion de la ventana
if (!mRoot->showConfigDialog())
{
exit = true;
}
}
void createRenderWindow()
{
// Crea una ventana por defecto, con un titulo especificado
mWindow = mRoot->initialise(true, "Mi Aplicacion con OGRE");
}
void initEventHandlers()
{
mRoot->addFrameListener(this);
}
void createScene()
{
// Elegir manejador de escenario
mSceneMgr = mRoot->createSceneManager(Ogre::ST_GENERIC);
// Crear camara y posicionarla en el espacio
mCamera = mSceneMgr->createCamera("CamaraPrincipal");
mCamera->setPosition(Ogre::Vector3(0.0f, 0.0f, 500.0f));
mCamera->lookAt(Ogre::Vector3(0.0f, 0.0f, 0.0f));
mCamera->setNearClipDistance(5.0f);
mCamera->setFarClipDistance(5000.0f);
// Agregar camara al viewport
mViewport = mWindow->addViewport(mCamera);
mViewport->setBackgroundColour(Ogre::ColourValue(0.0f, 0.0f, 0.0f));
// Inicializando el contador de tiempo.
mTime = 0;
}
void startRenderLoop()
{
// Comenzar el despliegue
mRoot->startRendering();
}
bool frameStarted(const Ogre::FrameEvent &evt)
{
// Incrementamos nuestro contador de tiempo
mTime += evt.timeSinceLastFrame;
// Verificamos si han pasado mas de 3 segundos y salimos
if (mTime > 3)
exit = true;
if (exit == true)
return false;
else
return true;
}
bool frameEnded(const Ogre::FrameEvent &evt)
{
return true;
}
};
OgreTutorial2.cpp
#include "OgreTutorial2.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main()
#endif
{
OgreApp* app = new OgreApp();
app->go();
delete app;
return 0;
}
Ahora, si ejecutan esta aplicación verán que termina sola pasados 3 segundos, ya no necesitamos matar el proceso.
Por el momento es todo. Dejaremos para la siguiente lección el uso de OIS para la entrada por teclado, ya que es algo extenso y complejo, y no quiero alargar mucho este tema. Espero sus comentarios.
Entry Filed under: OGRE. .
Trackback this post | Subscribe to the comments via RSS Feed