这几天熟悉了一下Entity,SceneManager,SceneNode。自己可以简单的实现了站立的robot和ninja,总感觉静态的场景不好玩,想做一下动态的场景,由于本人目前是初学者,所以也就只能做做关键帧动画,骨骼动画就留在后面实现吧,hoho~
定义一个10秒种的动画,这个动画包含一个动画轨迹(上下翻转)。让这个动画应用到当前摄像机上去,程序运行时,我(第一人称摄像机)应该在上下翻转。
在createScene函数里做初始化工作。
首先我们考虑怎样可以把动画应用到当前摄像机上。因为一个动画可以应用到一个节点上,所以可以创 建一个节点并将当前摄像机attach到这个节点上去,代码如下:
SceneNode* camNode = mSceneMgr->getRootSceneNode()->createChild();
camNode->attachObject(mCamera);
下面定义动画、动画轨迹以及关键帧:
// 定义动画,指定动画的名称及长度(这里为10秒)
Animation* anim = mSceneMgr->createAnimation("CameraTrack", 10);
// 指定动画关键帧之间的插值方式(包括线性插值和样条插值)
anim->setInterpolationMode(Animation::IM_SPLINE);
// 定义动画的一个动画轨迹,并指定这个轨迹是作用到camNode节点上的
AnimationTrack* track = anim->createTrack(0, camNode);
// 定义动画轨迹包含的关键帧,下面定义了四个关键帧,加上起始帧
// 五个关健帧形成了一个翻转的动画。
KeyFrame* key = track->createKeyFrame(0); // startposition
key = track->createKeyFrame(2.5);
key->setTranslate(Vector3(500,500,-1000));
key = track->createKeyFrame(5);
key->setTranslate(Vector3(-1500,1000,-600));
key = track->createKeyFrame(7.5);
key->setTranslate(Vector3(0,-100,0));
key = track->createKeyFrame(10);
key->setTranslate(Vector3(0,0,0));
然后定义AnimationState类的对象,它和刚才定义的动画类相对应。设置动画的状态为启用:
mAnimState = mSceneMgr->createAnimationState("CameraTrack");
mAnimState->setEnabled(true); // 启用该动画
到此,初始化工作就做完了.
最后,要想使动画动起来,我们需要重载ExampleFrameLisener类的frameStarted函数,并调用下面的函数,根据传入的时间来设置动画的状态: mAnimState->addTime(evt.timeSinceLastFrame);
以下是进行重载ExampleFrameLisener类的frameStarted函数的操作。
#include "ExampleFrameListener.h"
AnimationState *mAnimState;
class ProjectiveDecalListener : public ExampleFrameListener
{
public:
ProjectiveDecalListener(RenderWindow* win, Camera* cam)
: ExampleFrameListener(win, cam)
{
}
~ProjectiveDecalListener()
{
}
bool frameStarted(const FrameEvent& evt)
{
mAnimState->addTime(evt.timeSinceLastFrame);
return ExampleFrameListener::frameStarted(evt); //没有这句的话,鼠标和键盘将无法控制
}
};
重载ExampleApplication类中的createFrameListener函数,可以放在CreateScene()的后面。
void createFrameListener(void)
{
mFrameListener= new ProjectiveDecalListener(mWindow, ExampleApplication::mCamera);
mRoot->addFrameListener(mFrameListener);
}
这里需要对上面这个函数进行详细的讲解:
因为Root类是要每帧更新的,他也了解FrameListeners。我们首先要创建ProjectiveDecalListener的实例,然后把他注册到Root对象中。
mRoot和mFrameListener变量是在ExampleApplication类中定义的。addFrameListener方法添加一个帧监听者,removeFrameListener方法移除帧监听者(也就是说FrameListener就不用在更新了)。注意add|removeFrameListener方法仅仅是得到一个指向FrameListener的指针(也就是说FrameListener并没有一个名字你可以移除她)。这就意味着你需要对每一个FrameListener持有一个指针,让你随后可以移除他们。
这样我们就可以看到旋转摄像头里所看到的场景图像了。