Go on         Continuation of Intermediate Tutorial (Complete)

im_tutorial1.cpp

/* **************************************************************

file: im_tutorial1.cpp
description: Intermediate tutorial, modified to manage an
             arbitrary number of points and robots, and a
             collision avoidance algorithm

****************************************************************/

#include "ExampleApplication.h"
#include "singleton.h"
#include "im_tutorial1.h"
#include <deque>

using namespace std;

// RobotAnimator ////////////////////////////////////////////////////

// programmer: Andres Vogel
// description: controller for single robot being
// animated

// /////////////////////////////////////
// class for animation of robots      //
// /////////////////////////////////////

// namepsace IntermediateTutorial1
//      programmer: Andres Vogel
//      description: this is the intermediate tutorial
//------------------------------------------------------------------------

namespace IntermediateTutorial1
{

//--------------------------------------------------------------------------
// class RobotRayDataManager
//      Based on the Singleton class
//
    class RobotRayDataManager : 
        public IntermediateTutorial1::Singleton<RobotRayDataManager>
    {
        friend class Singleton<RobotRayDataManager>;
        friend class std::auto_ptr<RobotRayDataManager>;
    private:
        
        Ogre::SceneManager* mSceneMgr;
        Ogre::RaySceneQuery* mRaySceneQuery;
    
        RobotRayDataManager() : mRaySceneQuery(0), mSceneMgr(0) {  }
        ~RobotRayDataManager() {  }
        
    public:
        Vector3 getRayIntersection(Ogre::Ray ray)
        {
            mRaySceneQuery->setRay( ray );
            // Execute query
            RaySceneQueryResult &result = mRaySceneQuery->execute();
            RaySceneQueryResult::iterator itr = result.begin( );
                
            // Get results, create a node/entity on the position
            if ( itr != result.end() && itr->worldFragment )
            {
                return itr->worldFragment->singleIntersection;
            }
            return Vector3::ZERO;
        }
        
        Vector3 getViewportRayIntersection(Camera* cam, Real x, Real y)
        {
           Ogre::Ray ray = cam->getCameraToViewportRay(x, y);
           return getRayIntersection(ray);
        }
            
        void clearResults(void)
        {
            mRaySceneQuery->clearResults();
        }
        
        void setSceneMgr(Ogre::SceneManager* sceneMgr)
        {
            mSceneMgr = sceneMgr;
            mRaySceneQuery = mSceneMgr->createRayQuery( Ogre::Ray() );
        }
        
        Ogre::SceneManager* getSceneMgr()
        {
            return mSceneMgr;
        }
        
    };

//
// end RobotRayDataManager
//--------------------------------------------------------------------------

//--------------------------------------------------------------------------

// ----------------------------------------------------------------------
//  class RobotAnimator
//      class for animating robots across the screen.  Do not
//      use new on this class, simply use the createRobot
//      factory method on the RobotAnimatorManager class

//      programmer: Andres Vogel
    
    class RobotAnimator : public Ogre::UserDefinedObject
    {
        // creator defines the creator object for this
        // class
        CREATOR_CLASS(RobotAnimatorManager);
        CREATOR_CLASS(RobotAnimatorManagerMulti);
    public:  // enums, types, etc.
        enum RobotTypes { RBT_TYPE_NORMAL, RBT_TYPE_USER };
        typedef std::list<RobotAnimator*> RobotAnimatorList;
        typedef std::list<RobotAnimator*>::iterator RobotAnimatorIterator;
        
    private: // class instance variables
        // the entity that represents the robot
        Ogre::Entity* mEntity;
        // the state of the robot at a given moment
        enum RobotState { RBT_BEGIN_WALK, RBT_WALKING, RBT_IDLE } mRobotState;
        Ogre::SceneNode* mNode; // robots node
        std::deque<Vector3> mWalkList;   // The list of points we are walking to
        bool mWalking;   // whether the robot is walking
        Ogre::Real mDistance;   // the distance to a destination point
        Ogre::Vector3 mDirection;  // the movement direction
        Ogre::Vector3 mDestination; // the destination vector
        Ogre::AnimationState* mAnimationState; // the state of the robot animation
        RobotTypes mRobotType;  // sets the type of robot (not used really)
        Ogre::RaySceneQuery* mRaySceneQuery; // current scene query data
        Real mWalkSpeed; // the walking speed of the robot
        
        // /////////////////////
        // constants          //
        // /////////////////////
        static const Real DEFAULT_WALK_SPEED; // the walking speed for the robot
        static const Real AVOIDANCE_FACTOR; // avoidance factor for robots
        
        
    protected:
        //
        // private constructor since we don't want just anyone
        // creating random RobotAnimators!
        //
        RobotAnimator(Entity* ent, SceneNode* node) :
         // initialize instance variables
            mEntity(ent),
            mNode(node),
            mWalkSpeed(DEFAULT_WALK_SPEED),
            mWalking(false),
            mRobotType(RBT_TYPE_NORMAL)
            
        {
            
            if ( nextLocation() )
            {
                // Set walking animation
                setAnimationState(true, true, "Walk");
                mWalking = true;
            } // if
            else
            {
                setAnimationState(true, true, "Idle");
                mWalking = false;
                   
            } // else

        }
        
    public: // methods
    
        
        ~RobotAnimator() {  }
        
        Ogre::String getName(void)
        {
            return mEntity->getName();
        }
        
        inline long getTypeID(void)
        {
            return mRobotType; 
        }
        
        //-----------------------------------------------------
        // testGround(): make sure robots feet are on the
        // the ground
        void testGround(void)
        {
            // get current node position
            
            Vector3 nodePos = this->getPosition( );
            Ray nodeRay( Vector3(nodePos.x, 5000.0f, nodePos.z), 
                Vector3::NEGATIVE_UNIT_Y );
            Vector3 vIntersect = RobotRayDataManager::getSingleton().
                getRayIntersection(nodeRay);
            vIntersect.y += 3.0f;
            mNode->setPosition( vIntersect );
                
            // clear results of the query
            RobotRayDataManager::getSingleton().clearResults();
        }
        
        //-------------------------------------------------
        // testCollide(): test for a local collide between
        // robots
        void testCollide(RobotAnimator* rbt)
        {
            if(rbt == this)
                return;
            Ogre::Vector3 vRbtPos = rbt->getPosition();
            Ogre::Vector3 vMyPos = mNode->getPosition();
            Ogre::Vector3 totalMovement = Vector3::ZERO;
            
            // get the distance, better to be squared (easier to calc)
            Real tr = (vRbtPos - vMyPos).squaredLength();
            
            // this is kinda a magic number ;)  I multiply the inverse
            // of the distance by an avoidance factor to create a stronger
            // avoidance vector as things get close enough to collide

            Real trFactor = (1.0 / tr) * AVOIDANCE_FACTOR;

            // if we are closer than about 44-45 units ( sqrt[2000] )            
            if(tr < 2000)
            {
                if(vRbtPos.x < vMyPos.x)
                    totalMovement.x = trFactor;
                if(vRbtPos.x > vMyPos.x)
                    totalMovement.x = -trFactor;
                if(vRbtPos.z < vMyPos.z)
                    totalMovement.z = trFactor;
                if(vRbtPos.z > vMyPos.z)
                    totalMovement.z = -trFactor;
                    
                // add random noise (makes them wiggle a little)
                totalMovement.x += Ogre::Math::RangeRandom(-0.1, 0.1);
                totalMovement.z += Ogre::Math::RangeRandom(-0.1, 0.1);
                
                mNode->translate(totalMovement);
            }
        }
        
        //-------------------------------------------------------
        // testCollide(RobotAnimatorList): test for multiple
        // robot collisions with this robot
        void testCollide(RobotAnimatorList robots)
        {

            RobotAnimatorIterator rbIterator;
            // go through each item in the robot list
            for ( rbIterator = robots.begin( ); rbIterator != robots.end( );
            rbIterator++ )
            {
                ( *rbIterator )->testCollide( this );
            }
        }
        
        Ogre::Vector3 getPosition(void)
        {
            return mNode->getPosition();
        }
        
        //-----------------------------------------------------
        // doFrame(): performs the translation actions on the
        // robot animation
        void doFrame(const FrameEvent &evt)
        {
                        
            if ( mWalking )
            {
                Real move = mWalkSpeed * evt.timeSinceLastFrame;
                mDistance -= move;
                // if we reach a waypoint, check for the next location
                if (mDistance <= 0.0f)
                {
                    mNode->setPosition( mDestination );
                    mDirection = Vector3::ZERO;
                    
                    if (! nextLocation( ) )
                    {
                        // no other locations found, Idle
                        setAnimationState(true, true, "Idle");
                        mWalking = false;
                        
                    } // if
                } // if
                else // if we are inbetween waypoints, move toward the next one
                {
                    mNode->translate( mDirection * move );
                } // else
                
                // make sure we are walking on the ground
                //testGround();
                
            }
            
           
            // play out animation
            mAnimationState->addTime(evt.timeSinceLastFrame);
            
        }
        
        void setAnimationState(bool enable, bool loop, Ogre::String state)
        {
            mAnimationState = mEntity->getAnimationState( state );
            mAnimationState->setLoop( true );
            mAnimationState->setEnabled( true );        
        }
        
        void setWalkSpeed(Ogre::Real walk)
        {
            mWalkSpeed = walk;
        }
        
        Real getWalkSpeed(void)
        {
            return mWalkSpeed;
        }
        
        
        bool nextLocation( )
        {
            if ( mWalkList.empty() )
                return false;
                
            mDestination = mWalkList.front( );  // this gets the front of the deque
            mWalkList.pop_front( );             // this removes the front of the deque
    
            mDirection = mDestination - mNode->getPosition( );
            mDistance = mDirection.normalise( );
    
            Vector3 src = mNode->getOrientation( ) * Vector3::UNIT_X;
            
            // we must zero out all y components to ensure that
            // the object stays oriented towards a given point
            src.y = 0;
            mDirection.y = 0;
            
            if ( (1.0f + src.dotProduct( mDirection )) < 0.0001f )
                mNode->yaw( Degree(180) );
            else
            {
                Ogre::Quaternion quat = src.getRotationTo( mDirection );
                mNode->rotate( quat );
            } // else
    
            return true;
        } // nextLocation

        // add a location to the robot walk list
        void addLocation( Ogre::Vector3 loc )
        {
            mWalkList.push_back(loc);
            if( !mWalking )
            {
                setAnimationState(true, true, "Walk");
                mWalking = true;
                nextLocation();
            }
        } // addLocation
    
    };
    
    
/* TODO (dreprog#1#): setup avoidance factor to be controlled by accessor functions */
    
    const Real RobotAnimator::DEFAULT_WALK_SPEED = 35.0f;
    const Real RobotAnimator::AVOIDANCE_FACTOR = 1500.0f;
    
// end class RobotAnimator 
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// RobotAnimatorManager 
//
// Maintains a list of robots that are being managed
// programmer: Andres Vogel
// description:     This class manages all the robots
//                  in the class, I chose not to implement
//                  as a seperate factory and manager
//                  because the manager doesn't have
//                  much responsiblity, and I placed
//                  the responsiblity of animating
//                  in the hands of the RobotAnimator
//                  objects themselves, and the manager
//                  simply brokers the call to the
//                  doFrame() methods of the RobotAnimators
//

    class RobotAnimatorManager : 
        public IntermediateTutorial1::Singleton<RobotAnimatorManager>
    {
        friend class Singleton<RobotAnimatorManager>;
        friend class std::auto_ptr<RobotAnimatorManager>;
    private:
        // this is the list of robots being managed
        RobotAnimator::RobotAnimatorList mRobots;
        // the scene manager managing the current scene
        Ogre::SceneManager* mSceneMgr;
        int mRobotCount;
        static bool sDestroyed;
        
        RobotAnimatorManager() : mRobotCount(0) {  }
       // ~RobotAnimatorManager() {  }    
        
    public:
        ~RobotAnimatorManager()
        {
            // clean up all the robots
            RobotAnimator::RobotAnimatorIterator rbIterator;
            // go through each item in the robot list
            for ( rbIterator = mRobots.begin( ); rbIterator != mRobots.end( );
            rbIterator++ )
            {
                // update frame information for each robot
                delete ( *rbIterator );
                // test for a collision between robots
            //    ( *rbIterator )->testCollide(mRobots);
            }
        }
        
        // attempting to call getSingleton after a destroySingleton
        // will leave you with a null pointer!
        
        RobotAnimator* createRobot(Ogre::Entity* ent, Ogre::SceneNode* sn)
        {
            RobotAnimator* rbt = new RobotAnimator(ent, sn);
//            mRob = rbt;
            mRobots.push_back( rbt );
            mRobotCount++;
            return rbt;
        }

        // doFrame(const FrameEvent &evt)
        // does a frame event for each 
        void doFrame(const FrameEvent& evt)
        {
            RobotAnimator::RobotAnimatorIterator rbIterator;
            // go through each item in the robot list
            for ( rbIterator = mRobots.begin( ); rbIterator != mRobots.end( );
            rbIterator++ )
            {
                // update frame information for each robot
                ( *rbIterator )->doFrame(evt);
                // test for a collision between robots
                ( *rbIterator )->testCollide(mRobots);
            }
        }
    };
    
// end RobotAnimationManager 
//-------------------------------------------------------------------
    
    
    

//---------------------------------------------------------------------------
// RobotAnimatorManagerMulti (Non-singleton version)
//
// Maintains a list of robots that are being managed
// programmer: Andres Vogel
// description:     This class manages all the robots
//                  in the class, I chose not to implement
//                  as a seperate factory and manager
//                  because the manager doesn't have
//                  much responsiblity, and I placed
//                  the responsiblity of animating
//                  in the hands of the RobotAnimator
//                  objects themselves, and the manager
//                  simply brokers the call to the
//                  doFrame() methods of the RobotAnimators
//

    class RobotAnimatorManagerMulti 
    {
    private:
        // this is the list of robots being managed
        RobotAnimator::RobotAnimatorList mRobots;
        // the scene manager managing the current scene
        Ogre::SceneManager* mSceneMgr;
        int mRobotCount;
        static bool sDestroyed;
        
    public:
        RobotAnimatorManagerMulti() : mRobotCount(0) {  }
       // ~RobotAnimatorManager() {  }    
        ~RobotAnimatorManagerMulti()
        {
            // clean up all the robots
            RobotAnimator::RobotAnimatorIterator rbIterator;
            // go through each item in the robot list
            for ( rbIterator = mRobots.begin( ); rbIterator != mRobots.end( );
            rbIterator++ )
            {
                // update frame information for each robot
                delete ( *rbIterator );
                // test for a collision between robots
            //    ( *rbIterator )->testCollide(mRobots);
            }
        }
        
        // attempting to call getSingleton after a destroySingleton
        // will leave you with a null pointer!
        
        RobotAnimator* createRobot(Ogre::Entity* ent, Ogre::SceneNode* sn)
        {
            RobotAnimator* rbt = new RobotAnimator(ent, sn);
//            mRob = rbt;
            mRobots.push_back( rbt );
            mRobotCount++;
            return rbt;
        }

        // doFrame(const FrameEvent &evt)
        // does a frame event for each 
        void doFrame(const FrameEvent& evt)
        {
            RobotAnimator::RobotAnimatorIterator rbIterator;
            // go through each item in the robot list
            for ( rbIterator = mRobots.begin( ); rbIterator != mRobots.end( );
            rbIterator++ )
            {
                // update frame information for each robot
                ( *rbIterator )->doFrame(evt);
                // test for a collision between robots
                ( *rbIterator )->testCollide(mRobots);
            }
        }
    };
    
//
// end RobotAnimatorManagerMulti 
//-------------------------------------------------------------------
    
    
    
    
//---------------------------------------------------------------
// RobotAnimationListener 
//
    class RobotAnimatorListener : public ExampleFrameListener
    {
    public:  // enums, typedefs, etc
//        typedef std::list<Ogre::Entity*> EntityList;
//        typedef std::list<Ogre::Entity*>::iterator EntityListIterator;
//        typedef std::list<Ogre::Entity*> EntityList;
//        typedef std::list<Ogre::Entity*>::iterator EntityListIterator;
//        typedef Ogre::MapIterator<EntityNodeMap> EntityNodeMapIterator
    public: // methods
        RobotAnimatorListener(RenderWindow* win, Camera* cam, 
            Ogre::SceneManager* sceneMgr)
        : ExampleFrameListener(win, cam, false, false)
                
        {
//            EntityListIterator elIterator;
//            for ( elIterator = entlist.begin( ); elIterator != entlist.end( );
//            elIterator++ )
//            {
//                mRobots.push_back(
//                    static_cast<RobotAnimator*>
//                        (( *elIterator )->getUserObject()) );
//            }
            mRobotManager = RobotAnimatorManager::getSingletonPtr();
            RobotRayDataManager::getSingleton().setSceneMgr(sceneMgr);
            
            
        }
        
        ~RobotAnimatorListener()
        {
        //    delete mRobotManager;
        }
        
        bool frameStarted(const FrameEvent &evt)
        {
            mRobotManager->doFrame(evt);
            
            return ExampleFrameListener::frameStarted(evt);
        }
        
        RobotAnimator::RobotAnimatorList mRobots;
        RobotAnimatorManager* mRobotManager;
    };
    
// end RobotAnimatorListener
//--------------------------------------------------------------------------

}

// 
// end namespace IntermediateTutorial1
//------------------------------------------------------------------------

using namespace IntermediateTutorial1;

class MoveDemoApplication : public ExampleApplication
{
protected:
public:
    MoveDemoApplication()
    {
    }

    ~MoveDemoApplication() 
    {
    }
protected:
    Entity *mEntity;                // The entity of the object we are animating
    SceneNode *mNode;               // The SceneNode of the object we are moving
    std::deque<Vector3> mWalkList;  // A deque containing the waypoints

    void createScene(void)
    {
        // Set the default lighting.
        mSceneMgr->setAmbientLight( ColourValue( 1.0f, 1.0f, 1.0f ) );
         // Create the entity
        mEntity = mSceneMgr->createEntity( "Robot", "robot.mesh" );
          // Create the scene node
        mNode = mSceneMgr->getRootSceneNode( )->
            createChildSceneNode( "RobotNode", Vector3( 0.0f, 0.0f, 25.0f ) );
        mNode->attachObject( mEntity );
        
// add another robot ////////////////////////////////////////

        Entity* ent2 = mSceneMgr->createEntity( "Robot2", "robot.mesh" );
          // Create the scene node
        SceneNode* nd2 = mSceneMgr->getRootSceneNode( )->
            createChildSceneNode( "RobotNode2", Vector3( 0.0f, 0.0f, 25.0f ) );
        nd2->attachObject( ent2 );
        nd2->translate(10,0,100);
        
        Entity* ent3 = mSceneMgr->createEntity( "Robot3", "robot.mesh" );
          // Create the scene node
        SceneNode* nd3 = mSceneMgr->getRootSceneNode( )->
            createChildSceneNode( "RobotNode3", Vector3( 0.0f, 0.0f, 25.0f ) );
        nd3->attachObject( ent3 );
        nd3->translate(-20,0,-15);
        
         Entity* ent4 = mSceneMgr->createEntity( "Robot4", "robot.mesh" );
          // Create the scene node
        SceneNode* nd4 = mSceneMgr->getRootSceneNode( )->
            createChildSceneNode( "RobotNode4", Vector3( 0.0f, 0.0f, 25.0f ) );
        nd4->attachObject( ent4 );
        nd4->translate(200,0,40);
        
         Entity* ent5 = mSceneMgr->createEntity( "Robot5", "robot.mesh" );
          // Create the scene node
        SceneNode* nd5 = mSceneMgr->getRootSceneNode( )->
            createChildSceneNode( "RobotNode5", Vector3( 0.0f, 0.0f, 25.0f ) );
        nd5->attachObject( ent5 );
        nd5->translate(-100,0,-30);
        
         Entity* ent6 = mSceneMgr->createEntity( "Robot6", "robot.mesh" );
          // Create the scene node
        SceneNode* nd6 = mSceneMgr->getRootSceneNode( )->
            createChildSceneNode( "RobotNode6", Vector3( 0.0f, 0.0f, 25.0f ) );
        nd6->attachObject( ent6 );
        nd6->translate(-200,0,-40);
        
         Entity* ent7 = mSceneMgr->createEntity( "Robot7", "robot.mesh" );
          // Create the scene node
        SceneNode* nd7 = mSceneMgr->getRootSceneNode( )->
            createChildSceneNode( "RobotNode7", Vector3( 0.0f, 0.0f, 25.0f ) );
        nd7->attachObject( ent7 );
        nd7->translate(92,0,12);
        
// add another robot ////////////////////////////////////////

        
// ////////////////////////////////////// robot animator code
        RobotAnimatorManager* rbtMgr = RobotAnimatorManager::getSingletonPtr();
        RobotAnimator* rbtAnimator = rbtMgr->createRobot(mEntity, mNode);
        rbtAnimator->addLocation( Vector3( 550.0f,  0.0f,  50.0f  ) );
        rbtAnimator->addLocation( Vector3(-100.0f,  0.0f, -200.0f ) );
        mEntity->setUserObject( rbtAnimator );
        
        rbtAnimator = rbtMgr->createRobot(ent2, nd2);
        rbtAnimator->addLocation( Vector3( 600.0,  0.0f,  20.0f  ) );
        rbtAnimator->addLocation( Vector3(50.0f,  0.0f, -400.0f ) );
        rbtAnimator->setWalkSpeed(35.0f);
        ent2->setUserObject( rbtAnimator );
        
        rbtAnimator = rbtMgr->createRobot(ent3, nd3);
        rbtAnimator->addLocation( Vector3( -100.0f,  0.0f,  4.0f  ) );
        rbtAnimator->addLocation( Vector3(200.0f,  0.0f, 500.0f ) );
        rbtAnimator->setWalkSpeed(13.0f);
        ent3->setUserObject( rbtAnimator );
        
        rbtAnimator = rbtMgr->createRobot(ent4, nd4);
        rbtAnimator->addLocation( Vector3(1000.0f,  0.0f,  -300.0f  ) );
        rbtAnimator->addLocation( Vector3(-304.0f,  0.0f, 200.0f ) );
        rbtAnimator->setWalkSpeed(45.0f);
        ent4->setUserObject( rbtAnimator );
        
         rbtAnimator = rbtMgr->createRobot(ent5, nd5);
        rbtAnimator->addLocation( Vector3(90.0f,  0.0f,  -12.0f  ) );
        rbtAnimator->addLocation( Vector3(-491.0f,  0.0f, 392.0f ) );
        rbtAnimator->setWalkSpeed(120.0f);
        ent5->setUserObject( rbtAnimator );
        
         rbtAnimator = rbtMgr->createRobot(ent6, nd6);
        rbtAnimator->addLocation( Vector3(399.0f,  0.0f,  -300.0f  ) );
        rbtAnimator->addLocation( Vector3(192.0f,  0.0f, 600.0f ) );
        rbtAnimator->setWalkSpeed(30.0f);
        ent6->setUserObject( rbtAnimator );
        
         rbtAnimator = rbtMgr->createRobot(ent7, nd7);
        rbtAnimator->addLocation( Vector3(522.0f,  0.0f,  100.0f  ) );
        rbtAnimator->addLocation( Vector3(-900.0f,  0.0f, -200.0f ) );
        rbtAnimator->setWalkSpeed(90.0f);
        ent7->setUserObject( rbtAnimator );
        
// ////////////////////////////////////// end robot animator code

        
        // Create the walking list
// ////////////////////////////////////// code commented for animator

//        mWalkList.push_back( Vector3( 550.0f,  0.0f,  50.0f  ) );

// ////////////////////////////////////// robot animator code

//        mWalkList.push_back( Vector3(-100.0f,  0.0f, -200.0f ) );
//        mWalkList.push_back( Vector3(-400.0f,  0.0f, -100.0f ) );
         // Create objects so we can see movement
        Entity *ent;
        SceneNode *node;

        ent = mSceneMgr->createEntity( "Knot1", "knot.mesh" );
        node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot1Node",
            Vector3(  0.0f, -10.0f,  25.0f ) );
        node->attachObject( ent );
        node->setScale( 0.1f, 0.1f, 0.1f );

        ent = mSceneMgr->createEntity( "Knot2", "knot.mesh" );
        node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot2Node",
            Vector3( 550.0f, -10.0f,  50.0f ) );
        node->attachObject( ent );
        node->setScale( 0.1f, 0.1f, 0.1f );

        ent = mSceneMgr->createEntity( "Knot3", "knot.mesh" );
        node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot3Node",
            Vector3(-100.0f, -10.0f,-200.0f ) );
        node->attachObject( ent );
        node->setScale( 0.1f, 0.1f, 0.1f );
//        
//        ent = mSceneMgr->createEntity( "Knot4", "knot.mesh" );
//        node = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "Knot4Node",
//            Vector3(-400.0f, -10.0f,-100.0f ) );
//        node->attachObject( ent );
//        node->setScale( 0.1f, 0.1f, 0.1f );

         // Set the camera to look at our handywork
        mCamera->setPosition( 90.0f, 280.0f, 535.0f );
        mCamera->pitch( Degree(-30.0f) );
        mCamera->yaw( Degree(-15.0f) );
    }

    void createFrameListener(void)
    {
        
// ////////////////////////////////////// code commented for animator
//
//        mFrameListener= new MoveDemoListener(mWindow, mCamera, mNode, 
//          mEntity, mWalkList);

// ////////////////////////////////////// end code commented for animator

// ////////////////////////////////////// code added for animator

        
        mFrameListener = new RobotAnimatorListener(mWindow,
            mCamera, mSceneMgr);
        
// ////////////////////////////////////// end code added for animator

            
        mFrameListener->showDebugOverlay(true);
        mRoot->addFrameListener(mFrameListener);

    }

};

#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(int argc, char **argv)
#endif
{
    // Create application object
    MoveDemoApplication app;

    try {
        app.go();
    } catch( Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
        MessageBox( NULL, e.getFullDescription().c_str(), 
            "An exception has occured!",
            MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
        fprintf(stderr, "An exception has occured: %s\n",
                e.getFullDescription().c_str());
#endif
    }

    return 0;
}