这个例子告诉我们如何使场景节点动起来

/*
这个例子告诉我们如何使场景节点动起来。
SceneNodeAnimators的最基本概念就是能够使用键盘让场景节点移动起来
并且还能够显示。

一如之前,包含头文件,链接库,使用irr命名空间。
*/
#include <irrlicht.h>
#include <iostream>

using namespace irr;

#pragma comment(lib, "Irrlicht.lib")

/*
在这个例子中,我们的一个目标是使用键盘控制场景节点的移动。
当我们按键的时候,场景节点需要有移动,所以我们需要保存一个场景节点的指针。

另一个指针是Irr设备的指针,因为这次我们要为场景节点做个事件接收器,
还需要设置一个灵活摄象机,所以我们需要保存它。
*/

scene::ISceneNode* node = 0;
IrrlichtDevice* device = 0;


/*
为了获取用户鼠标键盘输入事件,以及GUI的各类事件(例如,XX按钮被按下)并
对其进行相应的处理,我们需要创建一个EventReceiver的实体对象,它必须
继承于IEventReciver类。对于这个接口类,我们仅需要重载其一个方法:OnEvent();
在引擎中有上列事件消息时,该方法会被自动调用。
在这个例子里,我们仅写出按下W,S时的场景节点处理。
*/
class MyEventReceiver : public IEventReceiver
{
public:
virtual bool OnEvent(SEvent event)
{
   /*
   当我们松开W或S键时,我们将获取场景节点的位置,并且使其在Y轴上进行略微的偏移。
   所以,如果你按W,节点将向上移动一点,你按S,节点将向下移动一点。
   */

   if (node != 0 && event.EventType == irr::EET_KEY_INPUT_EVENT&&
    !event.KeyInput.PressedDown)
   {
    switch(event.KeyInput.Key)
    {
    case KEY_KEY_W:
    case KEY_KEY_S:
     {
      core::vector3df v = node->getPosition();
      v.Y += event.KeyInput.Key == KEY_KEY_W ? 2.0f : -2.0f;
      node->setPosition(v);
     }
     return true;
    }
   }

   return false;
}
};


/*
事件接收器已经完成。现在我们可以创建Irr设备并且显示场景节点吧。
我们同时再做一些其他的场景节点,用来比较表现场景之间的不同之处

*/
int main()
{
// 让用户选择设备类型

video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;

printf("Please select the driver you want for this example:\n"\
   " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
   " (d) Software Renderer\n (e) Burning's Software Renderer\n"\
   " (f) NullDevice\n (otherKey) exit\n\n");

char i;
std::cin >> i;

switch(i)
{
   case 'a': driverType = video::EDT_DIRECT3D9;break;
   case 'b': driverType = video::EDT_DIRECT3D8;break;
   case 'c': driverType = video::EDT_OPENGL;   break;
   case 'd': driverType = video::EDT_SOFTWARE; break;
   case 'e': driverType = video::EDT_BURNINGSVIDEO;break;
   case 'f': driverType = video::EDT_NULL;     break;
   default: return 0;
}

// 创建设备
MyEventReceiver receiver;

IrrlichtDevice* device = createDevice( driverType, core::dimension2d<s32>(640, 480),
   16, false, false, false, &receiver);

if (device == 0)
   return 1;


video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();


/*
创建一个场景节点,这个场景节点是准备提供给我们去进行事件处理的。
我们创建一个球形的节点,这种简单的几何节点是无需导入模型或自定义顶点属性的。
节点创建完毕后,我们设置节点的位置和纹理。
因为我们的场景中不需要动态光照,所以我们屏蔽掉光照。(否则模型会变黑)
*/
node = smgr->addSphereSceneNode();
node->setPosition(core::vector3df(0,0,30));
node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
node->setMaterialFlag(video::EMF_LIGHTING, false);


/*
现在我们创建一些其他的节点,并为其设置一个场景节点动画器。
场景节点动画器可以依附于各种场景节点,例如Mesh,公告版,灯光,摄象机等都可以。
它的作用是对场景节点的一些属性进行修改调整。
它不仅能够更改场景节点的位置,还可以更改场景节点中的一个对象纹理等操作。
我们创建一个立方体场景节点,并且对其安排一个圆形轨道的场景节点动画器,
这样我们就实现了让立方体场景节点围着我们的球形场景节点旋转的功能。
*/
scene::ISceneNode* n = smgr->addCubeSceneNode();

if (n)
{
   n->setMaterialTexture(0, driver->getTexture("../../media/t351sml.jpg"));
   n->setMaterialFlag(video::EMF_LIGHTING, false);
   scene::ISceneNodeAnimator* anim =
    smgr->createFlyCircleAnimator(core::vector3df(0,0,30), 20.0f);
   n->addAnimator(anim);
   anim->drop();
}

/*
最后我们再增加一个场景节点,用它来显示一个md2格式的模型,
我们用一个场景节点动画器来绑定他,使其在两点间跑动。
*/
scene::IAnimatedMeshSceneNode* anms = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../../media/sydney.md2"));

if (anms)
{
   scene::ISceneNodeAnimator* anim =
    smgr->createFlyStraightAnimator(core::vector3df(100,0,60),
    core::vector3df(-100,0,60), 2500, true);
   anms->addAnimator(anim);
   anim->drop();

   /*
   为了让模型看起来完整,我们设置场景节点动画器让模型在两桢之间进行循环,之后设置了
   模型的骨骼动画速度和纹理,并将模型以及其动作反转了180度(原模型动作是面朝右走,
   旋转后模型动作是面朝左走,符合人物移动路径了)。
   之后我们设置setMD2Animation()函数来替代之前的设置浈循环速率和设置动画速度来进行动画控制。
   但是需要注意的是setMD2Animation()函数仅仅适用于MD2格式文件。
   另外需要说明的是,虽然您知道了如何考试播放动画,但我还是建议您不要尝试将每秒的
   动画桢速率开的过高……请珍惜GPU。
   */
   anms->setMaterialFlag(video::EMF_LIGHTING, false);

   anms->setFrameLoop(160, 183);
   anms->setAnimationSpeed(40);
   anms->setMD2Animation(scene::EMAT_RUN);

   anms->setRotation(core::vector3df(0,180.0f,0));
   anms->setMaterialTexture(0, driver->getTexture("../../media/sydney.bmp"));

}


/*
为了能够看到场景的全貌,我们创建了第一人称射击风格的摄象机
并且关闭了鼠标图标
*/
scene::ICameraSceneNode * cam = smgr->addCameraSceneNodeFPS(0, 100.0f, 100.0f);
device->getCursorControl()->setVisible(false);

/*
用GUIManager增加了一个Irr的Logo图。
*/
device->getGUIEnvironment()->addImage(
   driver->getTexture("../../media/irrlichtlogoalpha2.tga"),
   core::position2d<s32>(10,10));

/*
我们完成了所有的事情,现在我们开始绘制吧。我们同样的,在程序窗口标题上
绘制FPS。
*/
int lastFPS = -1;

while(device->run())
{
   driver->beginScene(true, true, video::SColor(255,113,113,133));

   // 这里绘制的3D场景
   smgr->drawAll();
   // 这里绘制的GUI环境
   device->getGUIEnvironment()->drawAll();

   driver->endScene();

   int fps = driver->getFPS();

   if (lastFPS != fps)
   {
    core::stringw tmp(L"Movement Example - Irrlicht Engine [");
    tmp += driver->getName();
    tmp += L"] fps: ";
    tmp += fps;

    device->setWindowCaption(tmp.c_str());
    lastFPS = fps;
   }
}

/*
最后,释放Irr设备。
*/
device->drop();

return 0;
}