1.说明:
这个例子展示:
1.wasd手动操控(某个物体)移动;
2.让场景节点独立移动(也就是某个物体).
3.场景节点动画器(SceneNodeAnimators)能让我们移动的时候保持自己的独立移动.
2.MyEventReceiver
为了接收鼠标键盘以及GUI事件,需要继承接口:irr::IEventReceiver来获取和处理消息.
IEventReceiver就一个方法需要重写,
OnEvent(),此方法在引擎获得用户输入消息时会被调用.
MyEventReceiver继承字IEventReceiver,
含有一个数组成员(记录当前每一个按键的状态):
bool KeyIsDown[KEY_KEY_CODES_COUNT];//0xff
重写OnEvent:
virtual bool OnEvent(const SEvent& event)
{
if(event.EventType = irr::EET_KEY_INPUT_EVENT)
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
return false;
}
事件类型是由枚举类型:EEVENT_TYPE记录,比如EET_GUI_EVENT =0;
SEvent类包含一下类:
SGUIEvent:GUI事件
SMouseInput://鼠标事件
SkeyInput://键盘输入事件
SJoystickEvent:游戏手柄事件
SLogEvent://log事件
SUserEvent://任何种类的用户事件
SKeyInput:
struct SKeyInput
{
wchar_t Char;
EKEY_CODE key;
bool PressedDown:1;//false:起
bool Shift:1;//用于组合键
bool Control:1;
};
为了获取wasd按键的状态,写一个函数:
virtual bool IsKeyDown(EKEY_CODE keyCode)const
{
return KeyIsDown[keyCode];
}
3.
1)创建一个
需要移动的球
体节点
在ISceneManager有相应方法创建简单几何体.
scene::ISceneNode* node1 = smgr->addSphereSceneNode();
然后设置属性:位置,纹理,关闭灯光.
2)创建一个做参照的立方体节点
scene::ISceneNode* node2 = smgr->addCubeSceneNode();
初始化它的纹理,关闭光照,
至于位置,给node2绑定一个动画,让它一直旋转.
scene::ISeneNodeAnimator* anim = smgr->createFlyCircleAnimator(
core::vector3df(0,0,30),20);
node2->addAnimator(anim);
anim->drop();
4.额外展示:
1)添加一个带奔跑动画的b3d模型,让他在两个点间来回奔跑,模型:ninja.b3d
内部包含一套动作,跑,死,攻击,跳跃等.
模型默认朝向是+z,run整数是:0-13,
scene::IAnimatedMeshSceneNode* anims =
smgr->addAnimatedMeshSceneNode(smgr->getMesh("../media/ninja.b3d");
设置模型属性:
添加移动动画(这个动画是指物体移动),为了更有意义,设置它为+x->-x
关闭光照,
设置模型循环帧数(因为只需要跑的动作):setFrameLoop(0,13)
旋转-90度:移动方向为-x,与模型的跑步动作朝向
(+z)
不一致:setRotation(core::vector3df(0,0,0))
设置动画速度:setAnimationSpeed(15)
scene::ISceneNodeAnimator* anim = smgr->createFlyStraightAnimator(
core::vector3df(100,0,0),//开始位置
core::vector3df(-100,0,0),//结束位置
3500,//每秒节点要移动的距离
true);
anims->addAnimator(anim);
anim->drop();
2)添加一个log和静态文本框
guie->addImage(driver->getTextrue("../media/irrlichtlogoalph2.tga"),
core::position2d<s32>(10,20));
//静态文本框,写"Movement"
gui::IGUIStaticText* stext = guie->addStaticText(
L"Movement",core::rect<s32>(10,10,400,20),true);
将字体颜色设置为黄色:
stext->setOverrideColor(video::SColor(255,255,255,0);
5.实现wasd控制球移动
基于时间的物体移动,需要在while循环内基于时间改变球位置
位置参数设置:node1->setPositoin(nodePostion);
需要获得当前的nodePostion: = node1->getPostion()+改变量
获得改变量:
比如Y方向,需要根据当前W,S按键状态决定
if(receiver.IsKeyDown(irr::KEY_KEY_W)
nodePosition.Y+=MOVEMENT_SPEED*frameDeltaTime;
frameDeltaTime是时间改变量.
const u32 now =
device->getTimer()->getTime()
;
frameDeltaTime = (f32)(now - then)/1000.0f;
then = now;
6.完整代码:
#ifdef _MSC_VER
#pragma comment(lib,"Irrlicht.lib")
#endif
#include <irrlicht.h>
using namespace irr;
class MyEventReceiver :public IEventReceiver
{
bool KeyIsDown[KEY_KEY_CODES_COUNT];
public:
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == irr::EET_KEY_INPUT_EVENT)
KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
return false;
}
virtual bool IsKeyDown(EKEY_CODE keyCode) const
{
return KeyIsDown[keyCode];
}
MyEventReceiver()
{
for (u32 i = 0; i < KEY_KEY_CODES_COUNT; i++)
KeyIsDown[i] = false;
}
};
int main(int argc, char** argv)
{
MyEventReceiver receiver;
IrrlichtDevice* device = createDevice(video::EDT_OPENGL,
core::dimension2d<u32>(720, 455), 16, false, false, false, &receiver);
if (!device)
return 1;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* guie = device->getGUIEnvironment();
//分别添加一个球体和一个立方体
scene::ISceneNode* node1 = smgr->addSphereSceneNode();
//设置球体的属性:位置,纹理,关闭材质灯光(没设置灯源)
if (node1)
{
node1->setPosition(core::vector3df(0, 0, 40));
node1->setMaterialTexture(0, driver->getTexture("../media/wall.bmp"));
node1->setMaterialFlag(video::EMF_LIGHTING, false);
}
scene::ISceneNode* node2 = smgr->addCubeSceneNode();
//
if (node2)
{
node2->setMaterialTexture(0, driver->getTexture("../media/wall.bmp"));
node2->setMaterialFlag(video::EMF_LIGHTING, false);
//为cube创建和添加一个动画
scene::ISceneNodeAnimator* anim = smgr->createFlyCircleAnimator(core::vector3df(0, 0, 30),20);
node2->addAnimator(anim);
anim->drop();
}
//添加一个在两个点间奔跑的b3d模型
scene::IAnimatedMeshSceneNode* anims = smgr->addAnimatedMeshSceneNode(smgr->getMesh("../media/ninja.b3d"));
//设置属性:添加动画
if (anims)
{
scene::ISceneNodeAnimator* anim = smgr->createFlyStraightAnimator(core::vector3df(100, 0, 0), core::vector3df(-100, 0, 0), 3500, true);
//添加
if (anim)
{
anims->addAnimator(anim);
anim->drop();
}
//为了跟合理的显示动画,需要设置:关闭灯光,添加纹理,设置动作帧范围(只需要run动作),动作时间,因为动作帧包含了所有动作,
//对应MD2格式的动画,只需要调用:anims->setMD2Animation(scene::EMAT_RUN);
anims->setFrameLoop(0, 13);
anims->setAnimationSpeed(15);
anims->setScale(core::vector3df(2.0, 2.0, 2.0));
anims->setRotation(core::vector3df(0, 0, 0));//如果没有这一行,模型是倒着走的
//anims->setMaterialTexture(0, driver->getTexture("../media/sydney.bmp"));
anims->setMaterialFlag(video::EMF_LIGHTING, false);
}
//添加一个log
//gui::IGUIEnvironment* guie =
device->getGUIEnvironment()->addImage(
driver->getTexture("../media/irrlichtlogoalpha2.tga"),
core::position2d<s32>(10, 20));
gui::IGUIStaticText* diagnostics = device->getGUIEnvironment()->addStaticText(
L"hello", core::rect<s32>(10, 10, 400, 20),true);
diagnostics->setOverrideColor(video::SColor(255, 255, 255, 0));
//设置摄像机
smgr->addCameraSceneNodeFPS();
u32 lastFPS = -1;
u32 then = device->getTimer()->getTime();
const f32 MOVEMENT_SPEED = 5.f;
while (device->run())
{
const u32 now = device->getTimer()->getTime();
const f32 frameDeltaTime = (f32)(now - then) / 1000.0f;
then = now;
//wasd
core::vector3df nodePosition = node1->getPosition();
if (receiver.IsKeyDown(irr::KEY_KEY_W))
nodePosition.Y += MOVEMENT_SPEED*frameDeltaTime;
else if (receiver.IsKeyDown(irr::KEY_KEY_S))
nodePosition.Y -= MOVEMENT_SPEED*frameDeltaTime;
if (receiver.IsKeyDown(irr::KEY_KEY_A))
nodePosition.X -= MOVEMENT_SPEED*frameDeltaTime;
else if(receiver.IsKeyDown(irr::KEY_KEY_D))
nodePosition.X += MOVEMENT_SPEED*frameDeltaTime;
node1->setPosition(nodePosition);
driver->beginScene(true, true, video::SColor(255, 0, 100, 100));
smgr->drawAll();
// guie->drawAll();
device->getGUIEnvironment()->drawAll();
driver->endScene();
u32 fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw tmp(L"Movement [");
tmp += driver->getName();
tmp += L"] fps:";
tmp += fps;
device->setWindowCaption(tmp.c_str());
lastFPS = fps;
}
}
device->drop();
return 0;
}