Ogre 3D 1.7 Beginner's Guide
上QQ阅读APP看书,第一时间看更新

Time for action — adding movement to the scene

Up until now, we only had one class, namely, ExampleApplication. This time we need another one:

  1. Create a new class, name it Example25FrameListener, and let it inherit publicly from Ogre::FrameListener:
    class Example25FrameListener : public Ogre::FrameListener
    {
    };
    
  2. Add a private member variable, which is an Ogre::SceneNode pointer, and name it _node:
    private:
    Ogre::SceneNode* _node;
    
  3. Add a public constructor that takes an Ogre::SceneNode pointer as a parameter and assigns it to the member node pointer:
    public:
    Example25FrameListener(Ogre::SceneNode* node)
    {
    _node = node;
    }
    
  4. Add a new function called frameStarted(FrameEvent & evt), which translates the member node with (0,0,0.1) and then returns true:
    bool frameStarted(const Ogre::FrameEvent &evt)
    {
    _node->translate(Ogre::Vector3(0.1,0,0));
    return true;
    }
    
  5. Add a new member variable to hold the pointer to the FrameListener, which we will create later:
    Ogre::FrameListener* FrameListener;
    
  6. Add a constructor which inits the pointer with NULL and a destructor which destroys the FrameListener when the application is closed:
    Example25()
    {
    FrameListener = NULL;
    }
    ~Example25()
    {
    if(FrameListener)
    {
    delete FrameListener;
    }
    }
    
  7. Now create a new function in ExampleApplication called createFrameListener. In this function, create an instance of the FrameListener we defined and add it using mRoot:
    void createFrameListener()
    {
    FrameListener = new Example25FrameListener(_SinbadNode);
    mRoot->addFrameListener(FrameListener);
    }
    
  8. Compile and run the application. You should see the same scene as seen earlier, but this time, the instance of Sinbad moves right and you can't move the camera or close the application with the Escape key. To close the application, click the X button on the console windows, or if you started the application from a console, you can use CTRL+C.
    Time for action — adding movement to the scene

What just happened?

We added a new class to our code which moves our scene node.

FrameListener

The new concept we have encountered here is the concept of FrameListeners. As the name suggests, a FrameListener is based on the observer pattern. We can add a class instance which inherits from the Ogre::FrameListener interface to our Ogre 3D root instance using the addFrameListener() method of Ogre::Root. When this class instance is added, our class gets notified when certain events happen. In this example, we overrode the frameStarted() method. Before a frame (by frame, we mean a single picture of the scene) is rendered, Ogre::Root iterates over all added FrameListeners and calls the frameStarted() method of each one. In our implementation (see step 4) of this function, we translated the node 0.1 units on the x-axis. This node was passed to the Framelistener in its constructor. Therefore, each time the scene is rendered, the node is translated a bit, and as a result, the model moves.

As we have seen during the running of the application, we can't move our camera or exit our application using the Escape key. This is because these things were done by the FrameListener, which comes with the ExampleApplication framework. The ExampleApplication framework comes with the SDK. Now that we have replaced it with our own implementation, we can't use the functions the FrameListener offers any longer. But we will reimplement most of them in this chapter, so no worries. If needed, we could still call the functions of the base class to get our default behavior back.

In step 4, our function returns true. If it returned false, Ogre 3D would interpret this as a signal to drop out of the render loop, and with this, the application would be closed. We will use this fact to reimplement the "press Escape to exit the application" function.

Pop quiz — design pattern of FrameListener

  1. On which design pattern is the FrameListener concept based?

    a. Decorator

    b. Bridge

    c. Observer