Irrlicht 游戏引擎开发 cooliris 界面(三)

来源:互联网 发布:下载 windows 10 编辑:程序博客网 时间:2024/05/29 09:20

(三)着重于介绍如何让场景动起来,以及如何获取和处理消息。

源码:example_3.zip

 

1. Irrlicht 的运动机制

 

所谓运动,实际上计算机在不停得绘制场景,每绘制一次称之为一帧。 当各帧中物体的位置或外观有所变化,那么它就动起来了。 在irrlicht中,绘制一帧是在run循环中完成的:

 

Cpp代码 复制代码 收藏代码
  1. while (device->run())   
  2. {   
  3.     if (device->isWindowActive())   
  4.     {   
  5.         driver->beginScene(truetrue, video::SColor(0, 0, 0, 0));   
  6.         scene_mgr->drawAll();  // 绘制一帧   
  7.         driver->endScene();   
  8.     }   
  9. }   
  10. device->drop();  

 

我们所要做的,就是在 drawAll() 函数中,更新物体的位置,那么场景就动起来了。

 

所有的一切,都与 scene::ISecenNodeAnimator 这个接口相关。凡是实现这个接口的类实例,都可以通过 addAnimator() 函数加入到 ISceneNode 的 animators 列表中。

 

SceneManager 的drawAll() 函数在绘制(render)场景前,会调用 OnAnimate() 函数。这个函数是递归的,以保证加入场景中的每个 SceneNode 都被调用。 在OnAnimate() 函数中, SceneNode 的每一个 ISecenNodeAnimator 的 animateNode() 函数都会被调用,以更新 SceneNode 的位置、大小或纹理。

 

整理其调用顺序如下:

 

1. SceneManager           --> drawAll()                                   绘制一帧

2. ISceneNode               --> OnAnimate()                             SceneNode运动  

3. ISceneNodeAnimator --> animateNode(ISceneNode)       实现运动的具体函数

4. SceneManager           --> render()                                    绘制

 

可见,只要实现 ISecenNodeAnimator 接口,并加入到 SceneNode 中,就能够让其动起来。

 

2. Irrlicht 的消息传递

 

Irrlicht消息的传递是从device->run()开始的,在windows中首先调用 WndProc() 收集消息,打包成其内部的SEvent结构,再由 postEventFromUser() 将消息依次传递给 UserReceiver, GUI 和 3D Scene。

 

Irrlicht 中所有处理消息的类都必须实现 IEventReciever 接口。UserReceiver 就是在CreateDevice函数中指定的一个 IEventReceiver。 也就是说,消息处理的优先级为 UserReceiver > GUI > 3D Scene。

 

在我们的程序中,并没有指定UserReceiver,暂时也没有GUI,所以消息直接交给了 SceneManager。

SceneManager 的消息,也由 ISceneManager 的 postEventFromUser() 传递。 这个函数的实现如下:

 

Cpp代码 复制代码 收藏代码
  1. bool CSceneManager::postEventFromUser(const SEvent& event)   
  2. {   
  3.     bool ret = false;   
  4.     ICameraSceneNode* cam = getActiveCamera();   
  5.     if (cam)   
  6.         ret = cam->OnEvent(event);   
  7.   
  8.     _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;   
  9.     return ret;   
  10. }  

 

也就是说,只有当前Active(有效)的 ICameraSceneNode 才会接收到消息。ICameraSceneNode 会检测ISceneNodeAnimator 的isEventReceiverEnabled(), 如果为真则调用其 OnEvent 函数。

 

整理消息传递的机制如下:

 

1. IrrlichtDevice              --> run()                                       搜集消息并打包

2. IrrlichtDevice              --> postEventFromUser()             传递消息到userReceiver GUI 和 Scene

3. ISceneManager          --> postEventFromUser()             传递消息到CameraNode

4. ICameraSceneNode   --> onEvent()                                调用 Animator 的onEvent

5. ISceneNodeAnimator --> onEvent()  // if enabled           响应消息。

 

可见,实现 ISceneNodeAnimator 虽然可以 SceneNode 动起来,但只有在 CameraSceneNode 上,才能够接收和处理消息。

 

3. 实现CameraAnimator

 

如果我们实现一个 CameraAnimator,在其中处理消息,更新 CameraNode 和 CubeNode 的位置,就可以实现交互和动画。该类关键的几个函数如下:

 

Cpp代码 复制代码 收藏代码
  1. class CameraAnimator : public ISceneNodeAnimator   
  2. {   
  3. public:   
  4.     //! Constructor   
  5.     CameraAnimator(...   
  6.   
  7.     //! Destructor   
  8.     virtual ~CameraAnimator(){};   
  9.   
  10.     //! 更新 SceneNode 位置   
  11.     virtual void animateNode(ISceneNode* node, u32 timeMs);   
  12.   
  13.     //! 处理消息   
  14.     virtual bool OnEvent(const SEvent& event);   
  15.   
  16.     //! This animator will receive events when attached to the active camera  
  17.     virtual bool isEventReceiverEnabled() const  
  18.     {   
  19.         return true;  // 必须为true才能接收消息  
  20.     }   
  21.   
  22.         .... // other member functions.   
  23. private:   
  24.      ... // fields   
  25. };  

 

需要实现的关键有三点:

(1) 拖拽时, 场景跟着移动

(2) 单击某个图片时,场景移动到该位置,图片突出显示

(3) 滚轮实现缩放

 

在编程时有以下几个关键点:

(1) 三维场景中Node的选取,还好 irrlicht 替我们实现了这点,只需如下代码,就可以将鼠标点击处的node选取出来:

 

Cpp代码 复制代码 收藏代码
  1. core::position2d<s32> mouse_position(event.MouseInput.X, event.MouseInput.Y);   
  2. ISceneNode* node = scene_manager_->getSceneCollisionManager()   
  3.         ->getSceneNodeFromScreenCoordinatesBB(mouse_position, -1);  

 

(2) 运动的实现

 

    包括三个运动: CameraNode 的位置, CameraNode 的拍摄点,选取的图片的位置

    CameraNode的位置决定了场景的移动;

    CameraNode 的拍摄点决定了拍摄的角度,可以实现场景的倾斜;

    被选取的图片的位置可以使其比其它图片更接近Camera,实现突出的效果。

 

    (二)中描述的图片位置是排布在 z = 0 这个平面上的,Camera 的位置在 z = -700 平面上,初始拍摄点为原点。

 

    camera拍摄点(target)在 X 轴移动的处理如下:

Cpp代码 复制代码 收藏代码
  1. if (is_drag_ && current_node_ == NULL) // 拖拽  
  2. {   
  3.     core::position2di mouse_position = device_->getCursorControl()->getPosition();   
  4.     s32 xdiff = drag_start_point_.X - mouse_position.X;   
  5.     drag_start_point_ = mouse_position;   
  6.   
  7.     x_target += 0.01*xdiff / core::max_(dt, 0.0000001f);   
  8. }   
  9.   
  10. if (current_node_!=NULL) // 选取了某幅图片  
  11. {   
  12.     x_target = current_node_->getPosition().X;   
  13. }   
  14.   
  15. sign = (x_target < x_current) ? -1 : 1;   
  16. x_speed = sign*sqrt(abs(x_target - x_current)) * 50;  // 运动速度  
  17. target_position.X += x_speed * dt;  // 移动位置  

 

    在 Y 轴和 Z 轴方向的移动,包括图片的移动, 均用类似的方式处理。参见(animateNode)函数。

 

(3) 鼠标滚轮实现缩放

    只需要改变 Camera 在Z轴的位置,作简单的限幅即可:

Cpp代码 复制代码 收藏代码
  1. z_target += 100*event.MouseInput.Wheel;    
  2.   
  3. if (z_target > -200)   
  4. {   
  5.     z_target = -200;   
  6. }   
  7. if (z_target < -3000)   
  8. {   
  9.     z_target = -3000;   
  10. }  

 

4.最后

 

最后我们还需要将实现的 animator 附加到 Camera 上:

 

Cpp代码 复制代码 收藏代码
  1. scene::ICameraSceneNode* camera = scene_mgr->addCameraSceneNode(0,    
  2.     core::vector3df(0,0,-700),    
  3.     core::vector3df(0,0,0), 0);   
  4. scene::CameraAnimator* animator = new scene::CameraAnimator(wall_mgr->GetWallItemList(),    
  5.     device, scene_mgr,    
  6.     device->getTimer()->getTime());   
  7. camera->addAnimator(animator);   
  8. animator->drop();  

 

编译运行后,您应该能够用鼠标实现类似 cooliris 的交互。更进一步的完善,还需要支持键盘等……

 

p.s.

 

3d 界面就介绍到这里了,也算告一段落。

还有两个部分:

(1) GUI: 介绍GUI编写,并加入Truetype中文字体支持;

(2) AnimatedGUI:介绍目录浏览控件的编写,实现一个皮肤系统。

 

由于临近毕业,导师催着要论文,过段时间再继续吧。

鉴于本人的学习经历,劝各位千万不要盲目读研,不要盲目崇拜名校,别被糟蹋了。

我是学机械方向的,盲目接受了当年所谓的推研资格。sigh~~学术气氛糟糕啊……

 

From: http://arec.iteye.com/blog/338135

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 投完简历没回复怎么办 工业废气一年总量超标怎么办 安监局行政处罚没能力交怎么办 被社会淘汰的人怎么办 宝宝吐奶的时候怎么办 网友要我发红包怎么办 电脑久了很慢怎么办 影驰显卡花屏怎么办 反恐精英全球攻势加载地图慢怎么办 老滚5视角锁死了怎么办 苹果描述文件没有了怎么办 苹果6s发热严重怎么办 苹果6s发烫严重怎么办 手机型号不适配全军出击怎么办? 苹果5版本过低怎么办 在泰国买到假货怎么办 在泰国旅游遇到危险该怎么办? 拾到小米手环怎么办 苹果充电打游戏触点怎么办 衣服上金属锈了怎么办 光之子门锁住了怎么办 挖到金矿石了该怎么办 邻居是精神病扔石头怎么办 汽车保养手册丢了怎么办 五号电池没电了怎么办 电脑打印时显示脱机怎么办 博新计划两年后怎么办 门帘粘扣老是掉怎么办 魔术粘贴带双面背胶不粘了怎么办 斜挎包包磨衣服怎么办 电脑ip被别人知道了怎么办 西乐葆不止痛了怎么办 家里鸽子多捣蛋的不行怎么办 联璧倒闭了理财钱怎么办 众筹平台雷了怎么办 App理财无法提现怎么办 喝咖啡喝的心慌怎么办 睾丸被用力捏破流血怎么办 足球大师球队声望过高怎么办 fm17买了好多球员怎么办 fm2018电脑适应了战术怎么办