学了那么长时间,才学会跑起来。My Ogre,动起来。
第一,还是要把框架搭起来,这里我们用到双端队列deque,前面已经简单介绍过,头文件如下:
#include "ExampleApplication.h"
#include "deque"
using namespace std;
第二,是我们的监听器,继承至ExampleFrameListener,构造函数我们使用五个参数,分别为渲染窗口,摄像机,场景节点,实体,行走路线上的位置坐标。
MoveDemoListener(RenderWindow *win,Camera *cam,SceneNode *sn,Entity *ent,std::deque <Vector3> &walk) :ExampleFrameListener(win,cam,false,false), mNode(sn),mEntity(ent),mWalkList(walk)
{ // Set default values for variables
mWalkSpeed = 35.0f;//行走 速度设为每秒 35 个单位
mDirection = Vector3::ZERO;//可用来判断机器人是否正在行走,为零时不走 }
第三,我们接着完善监听器,首先成员函数添加了
Real mDistance;//实体要移动的距离
Vector3 mDirection;//方向
Vector3 mDestination;//目的地 AnimationState *mAnimationState;//物体的目前的动画状态 Entity *mEntity;
SceneNode *mNode;
std::deque<Vector3> mWalkList;//要行走的点
Real mWalkSpeed;//物体移动的速度
然后添加一个函数,bool nextLocation();用来判断是否有下一个方位,确定下一步怎么走。如果返回行走的队列为空,返回false
bool nextLocation()
{
if (mWalkList.empty())
return false;
mDestination = mWalkList.front(); // 取得队列的头部
mWalkList.pop_front(); // 删除已走过的点
mDirection = mDestination - mNode->getPosition();//距离由目的地减去当前位置得到
mDistance = mDirection.normalise();//normalise()作用是将方向向量转换成单位向量,返回向量的原始长度
return ture;
}
最后我们添加在每一帧前渲染的函数frameStarted(),这函数我们见了好多次,以后我们还会见面的。移动、转向操作等都在这里。
bool frameStarted(const FrameEvent &evt)
{
if (mDirection == Vector3::ZERO)
{
if (nextLocation())//如果行走列表不为空
{
// 设置行走的动画
mAnimationState = mEntity->getAnimationState("Walk");//设置动画为走动
mAnimationState->setLoop(true);//循环执行
mAnimationState->setEnabled(true);//激活
}
}
else//开始 移动
{
Real move = mWalkSpeed * evt.timeSinceLastFrame;//速度*时间 = 移动距离
mDistance -= move;//更新距离
if (mDistance <= 0.0f)//小于0,说明已经走过目标地点
{
mNode->setPosition(mDestination);//重新设置为目的地
mDirection = Vector3::ZERO;//方向为0,不走
if (! nextLocation())//如果行走列表为空,没有目的地
{// Set Idle animation
mAnimationState = mEntity->getAnimationState("Idle");//从网格动画的动画集(Idle)中获取当前的状态
mAnimationState->setLoop(true);//设置循环
mAnimationState->setEnabled(true);//激活
}
else //继续走
{
Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;//获取实体的当前朝向,这里有向量的乘积,如果俩个向量方向相反,乘积就是-1
if ((1.0f + src.dotProduct(mDirection)) < 0.0001f)//如果要旋转180度
{
mNode->yaw(Degree());
}
else//如果不是要旋转180度
{
Ogre::Quaternion quat = src.getRotationTo(mDirection);//获取方向
mNode->rotate(quat);//旋转
} // else
}
}
else
{
mNode->translate(mDirection * move);//移动一定距离
} // else
} // if mAnimationState->addTime(evt.timeSinceLastFrame);//更新动画状态
return ExampleFrameListener::frameStarted(evt);
}
我已经把注释写的很详细了。这里说一下第29行Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;这里牵涉到向量乘积的问题,两个向量乘积有以下两种情况
向量的积分为数量积和向量积 数量积就是向量的点乘 向量积就是向量的叉乘
设a(x,y,z) b(m,n,p)
则 a点乘b=xm+yn+zp
或 a点乘b=|a||b|*cos<a,b>
设a=xi+yj+zk b=mi+nj+pk
则叉乘 a×b=(yp-zn)i+(zm-xp)j+(xn-ym)k
Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;//这个是点乘,结果是一个数,大小在-1,1之间。两个向量方向相反时,乘积为-1
还有个老熟人createFrameListener(),我就不解释了,不懂,看前一章。
void createFrameListener(void)
{
mFrameListener = new MoveDemoListener(mWindow,mCamera,mNode,mEntity,mWalkList);
mFrameListener->showDebugOverlay(true);
mRoot->addFrameListener(mFrameListener);
}
第四,创建场景,如下,都是一些简单的东西,不解释
void createScene(void)
{
mSceneMgr->setAmbientLight( ColourValue( 1.0f, 1.0f, 1.0f ) );
mEntity = mSceneMgr->createEntity( "Robot", "robot.mesh" );
mNode = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "RobotNode", Vector3( 0.0f, 0.0f, 25.0f ) );
mNode->attachObject( mEntity ); // 创建走动列表
mWalkList.push_back( Vector3( 550.0f, 0.0f, 50.0f ) );
mWalkList.push_back( Vector3(-100.0f, 0.0f, -200.0f ) ); 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 ); mCamera->setPosition( 90.0f, 280.0f, 535.0f );
mCamera->pitch( Degree(-30.0f) );
mCamera->yaw( Degree(-15.0f) );
}
好了,完整代码如下
#include "ExampleApplication.h"
#include "deque"
using namespace std; class MoveDemoListener : public ExampleFrameListener
{
public:
MoveDemoListener(RenderWindow *win,Camera *cam,SceneNode *sn,Entity *ent,std::deque <Vector3> &walk)
:ExampleFrameListener(win,cam,false,false),mNode(sn),mEntity(ent),mWalkList(walk)
{
mWalkSpeed = 35.0f;//行走 速度设为每秒 35 个单位
mDirection = Vector3::ZERO;//可用来判断机器人是否正在行走
} bool nextLocation()
{
if (mWalkList.empty())
return false;
mDestination = mWalkList.front(); //
mWalkList.pop_front(); //
mDirection = mDestination - mNode->getPosition();
mDistance = mDirection.normalise();
return true;
}
bool frameStarted(const FrameEvent &evt)
{
if (mDirection == Vector3::ZERO)
{
if (nextLocation())//如果行走列表不为空
{
// 设置行走的动画
mAnimationState = mEntity->getAnimationState("Walk");//设置动画为走动
mAnimationState->setLoop(true);//循环执行
mAnimationState->setEnabled(true);//激活
}
}
else//开始 移动
{
Real move = mWalkSpeed * evt.timeSinceLastFrame;//速度*时间 = 移动距离
mDistance -= move;//更新距离
if (mDistance <= 0.0f)//小于0,说明已经走过目标地点
{
mNode->setPosition(mDestination);//重新设置为目的地
mDirection = Vector3::ZERO;//方向为0,不走
if (! nextLocation())//如果行走列表为空,没有目的地
{
mAnimationState = mEntity->getAnimationState("Idle");//从网格动画的动画集(Idle)中获取当前的状态
mAnimationState->setLoop(true);//设置循环
mAnimationState->setEnabled(true);//激活
}
else //继续走
{
Vector3 src = mNode->getOrientation() * Vector3::UNIT_X;//获取实体的当前朝向,这里有向量的乘积,如果俩个向量方向相反,乘积就是-1
if ((1.0f + src.dotProduct(mDirection)) < 0.0001f)//如果要旋转180度
{
mNode->yaw(Degree());
}
else//如果不是要旋转180度
{
Ogre::Quaternion quat = src.getRotationTo(mDirection);//获取方向
mNode->rotate(quat);//旋转
} // else
}
}
else
{
mNode->translate(mDirection * move);//移动一定距离
} // else
} // if mAnimationState->addTime(evt.timeSinceLastFrame);//更新动画状态
return ExampleFrameListener::frameStarted(evt);
}
protected:
Real mDistance;//实体要移动的距离
Vector3 mDirection;//方向
Vector3 mDestination;//目的地 AnimationState *mAnimationState;//物体的目前的动画状态 Entity *mEntity;
SceneNode *mNode;
std::deque<Vector3> mWalkList;//要行走的点
Real mWalkSpeed;//物体移动的速度 }; class MoveDemoApplication:public ExampleApplication
{
public:
MoveDemoApplication()
{ }
~MoveDemoApplication()
{ }
protected:
Entity *mEntity;
SceneNode *mNode;
std::deque<Vector3> mWalkList;
void createScene(void)
{
mSceneMgr->setAmbientLight( ColourValue( 1.0f, 1.0f, 1.0f ) );
mEntity = mSceneMgr->createEntity( "Robot", "robot.mesh" );
mNode = mSceneMgr->getRootSceneNode( )->createChildSceneNode( "RobotNode", Vector3( 0.0f, 0.0f, 25.0f ) );
mNode->attachObject( mEntity ); mWalkList.push_back( Vector3( 550.0f, 0.0f, 50.0f ) );
mWalkList.push_back( Vector3(-100.0f, 0.0f, -200.0f ) ); 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 ); mCamera->setPosition( 90.0f, 280.0f, 535.0f );
mCamera->pitch( Degree(-30.0f) );
mCamera->yaw( Degree(-15.0f) );
} void createFrameListener(void)
{
mFrameListener = new MoveDemoListener(mWindow,mCamera,mNode,mEntity,mWalkList);
mFrameListener->showDebugOverlay(true);
mRoot->addFrameListener(mFrameListener);
} }; #include "windows.h" INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT)
{
MoveDemoApplication app;
app.go();
return ;
}