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. .

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Entradas recientes

Categorías

Enlaces

Archivos

Páginas

Meta