使用Irrlicht构建游戏主角
2015-07-07 15:50
169 查看
所谓游戏主角就是第三视角看到的在屏幕中间附近跑来跑去,然后周围景物随之变换的节点。
实现的思路很简单,分为以下三步
1. 获取键盘输入
2. 移动主角,并且在需要的时候更改动画
3. 移动摄像机
这里的前提是周围环境相对世界坐标系不变。
那么使用Irrlicht怎么实现呢?一步一步来。
1. 获取键盘输入
自然就是重载我们的 IEventReceiver 类了,这部分大体思路可以参考教程 04.Movement 里面的实现:维护一个键位表,每个键值有两个状态(按下和没有按下),在键盘有信号时修改本表对应键值的状态,以便主渲染程序读取。
接下来第二步
2.移动角色并更改动画
本身这几个动作是比较简单的,但坑就坑在节点类 IAnimatedMeshSceneNode 居然是个抽象类,并且我没有找到合适的去继承它成为实体类的方法(如果有请告知)。那只能对这个类的系列操作封装在一个代理类 MyRoleDelegate 里面了。这个类里面有个 render() 函数用于从事件***中读取当前键盘状态并操作主节点。
有WASD操作的人物一共有八个方向,此时对应八种模型旋转变换(二维),也比较简单。附上代码
另外,setAnimationType涉及更改动画的API,仅仅适用于MD2格式模型,如有其它需要请重载
第三步就最简单了,只需要在主渲染函数里面更改相机位置即可。
当然,你还需要一个主Game类来初始化所有变量,载入模型,建立三角碎片选择器,加入碰撞检测与重力等等,就不在这里解释了。
最终的效果就是开头的那张动画。
实现的思路很简单,分为以下三步
1. 获取键盘输入
2. 移动主角,并且在需要的时候更改动画
3. 移动摄像机
这里的前提是周围环境相对世界坐标系不变。
那么使用Irrlicht怎么实现呢?一步一步来。
1. 获取键盘输入
自然就是重载我们的 IEventReceiver 类了,这部分大体思路可以参考教程 04.Movement 里面的实现:维护一个键位表,每个键值有两个状态(按下和没有按下),在键盘有信号时修改本表对应键值的状态,以便主渲染程序读取。
[code] class MyEventReceiver : public IEventReceiver { public: MyEventReceiver() { for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i) KeyIsDown[i] = false; runContrlCounter = 0; pressKeyCounter = 0; } 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]; } private: bool KeyIsDown[KEY_KEY_CODES_COUNT]; };
接下来第二步
2.移动角色并更改动画
本身这几个动作是比较简单的,但坑就坑在节点类 IAnimatedMeshSceneNode 居然是个抽象类,并且我没有找到合适的去继承它成为实体类的方法(如果有请告知)。那只能对这个类的系列操作封装在一个代理类 MyRoleDelegate 里面了。这个类里面有个 render() 函数用于从事件***中读取当前键盘状态并操作主节点。
有WASD操作的人物一共有八个方向,此时对应八种模型旋转变换(二维),也比较简单。附上代码
[code]class MyRoleDelegate { public: MyRoleDelegate(IAnimatedMeshSceneNode* node_p, MyEventReceiver* receiver_p, IrrlichtDevice* device_p) :role(node_p), receiver(receiver_p), device(device_p) { init(); } void init() { MOVEMENT_SPEED = 25.f; available = true; currentPosition = role->getPosition(); setAnimationType(EMAT_STAND); //初始为站立动画 } void setAnimationType(EMD2_ANIMATION_TYPE atype) { //避免重复设置同一个动作而造成卡顿 if(currentAnimationType!=atype) { role->setMD2Animation(atype); currentAnimationType=atype; } } void render() { if(false) { // setAnimationType(EMAT_STAND); } else { setAnimationType(EMAT_RUN); f32 frameDeltaTime = 0.1; currentPosition = role->getPosition(); float move_distance = MOVEMENT_SPEED * frameDeltaTime; vector3df dir(0.0,-90,0); //角色的方向 if(receiver->IsKeyDown(KEY_KEY_W)) { dir.Y = -90; currentPosition.Z += move_distance*0.7; if(receiver->IsKeyDown(KEY_KEY_A)) { //WA 方向 dir.Y = -135; currentPosition.X -= move_distance*0.7; } else if(receiver->IsKeyDown(KEY_KEY_D)) { //WD 方向 dir.Y = -45; currentPosition.X += move_distance*0.7; } else {//W方向,以下类似 currentPosition.Z += move_distance*0.3; } } else if(receiver->IsKeyDown(KEY_KEY_S)) { dir.Y = 90; currentPosition.Z -= move_distance*0.7; if(receiver->IsKeyDown(KEY_KEY_A)) { dir.Y = 135; currentPosition.X -= move_distance*0.7; } else if(receiver->IsKeyDown(KEY_KEY_D)) { dir.Y = 45; currentPosition.X += move_distance*0.7; } else { currentPosition.Z -= move_distance*0.3; } } else if(receiver->IsKeyDown(KEY_KEY_A)) { dir.Y = 180; currentPosition.X -= move_distance; } else if(receiver->IsKeyDown(KEY_KEY_D)){ dir.Y = 360; currentPosition.X += move_distance; } else{ dir = currentRotation; setAnimationType(EMAT_STAND); } if(dir != currentRotation){ role->setRotation(dir); currentRotation = dir; } role->setPosition(currentPosition); } } vector3df getCameraPosition(){ //设置此时相机应该处于的位置 vector3df pos = currentPosition; pos.Y += 50; pos.Z -= 50; return pos; } private: IrrlichtDevice* device; //主设备指针 MyEventReceiver* receiver;//主类事件*** IAnimatedMeshSceneNode* role;//所代理的节点指针 bool available; EMD2_ANIMATION_TYPE currentAnimationType; vector3df currentPosition, currentRotation;; f32 MOVEMENT_SPEED; };
另外,setAnimationType涉及更改动画的API,仅仅适用于MD2格式模型,如有其它需要请重载
第三步就最简单了,只需要在主渲染函数里面更改相机位置即可。
[code]while(device->run()) { rDele->render(); //rDele 为主节点代理 camera->setPosition(rDele->getCameraPosition()); //其他渲染操作 }
当然,你还需要一个主Game类来初始化所有变量,载入模型,建立三角碎片选择器,加入碰撞检测与重力等等,就不在这里解释了。
最终的效果就是开头的那张动画。
相关文章推荐
- linux日志系统
- PHP下获取上个月、下个月、本月的日期(strtotime,date)
- resin servlets和jsp的引擎
- Android V4 包下的ViewDragHelper学习.
- 多编程还是多编程
- linux相关线程函数
- strtok()函数
- 【C语言】数字在排序数组中出现的次数(修改)
- 第5章 埃洛体系(Facebook的前世)
- 每天一道算法题目(20)——复杂链表的拷贝
- 每天一道算法题目(20)——复杂链表的拷贝
- Eclipse常用快捷键
- MySQL基于SSL的主从复制、半同步复制
- Dubbo入门
- 一套设计模式教程
- git(创建,提交,回退)
- Murano中的角色
- div设置半透明效果
- 机器学习 之 Adaboost
- 模拟p-坚持CSMA算法