Irrlicht学习笔记(4)--Movement

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;
}


你可能感兴趣的:(Irrlicht)