History: Go on
Source of version: 3 (current)
Copy to clipboard
__im_tutorial1.cpp__
{CODE(wrap="1", colors="c++")}/* **************************************************************
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;
}
{CODE}