现在的位置: 首页 > 综合 > 正文

ExampleFrameListener类详解

2013年09月11日 ⁄ 综合 ⁄ 共 3183字 ⁄ 字号 评论关闭

1. OGRE的事件模型。 OGRE事件处理采用的是public subscribe mode, 即发布式订阅模型。通常的场景如下: 对象A试图在对象B产生C类型事件的时候 执行指定的动作,于是,对象A告知对象B当产生C类型事件的时候给自己发出一个通知。整个过程涉及到以下元素,

    *事件源 (Event Source)。通常是GUI对象或者用户输入, 或者某个对象内部产生的事件。例如现在Root对象 就是一个事件源,它从内部产生 FrameEvent事件。
*事件处理对象(Event Handler)。用户定义的事件处理器(函数)。这里就是我们的 ExampleFrameListener对象了。
*注册或订阅(registration or subscription)。将一个 事件处理对象实例向事件源实例注册的过程,这样当 事件处理器对象感兴趣的事件发生的时候可以立即收到通知。例如在ExampleApplication 的createFrameListener里,
// 事件处理对象实例 
mFrameListener= new ExampleFrameListener(mWindow, mCamera);
...
// 向 事件源实例注册 
mRoot->addFrameListener(mFrameListener);      
* 通知函数。通常会强制要求事件处理对象实现一个名称和参数已定的特殊方法。例如ExampleFrameListener的frameStarted和 frameEnd实现。

现在我们应该知道为什么会有ExampleFrameListener的存在了!当Root产生 FrameEvent时ExampleFrameListener就会得到通知,即调用ExampleFrameListener的 frameStarted和frameEnd方法,给了我们一个基于帧的触发事件接口。这也应该是和OGRE引擎其他部分交互的主要方式,选择自己感兴趣 的事件并实现对应的EventListener。

2. OGRE的InputReader对象。OGRE用InputReader对象封装 了键盘、鼠标等输入设备。它主要有两种工作模式,缓存和非缓存,在这两种工作方式下ExampleFrameListener获得响应的方式有很大不同。

非 缓存方式比较简单,我们只需要直接创建一个InputReader对象就可以了,

       // 直接调用 PlaftformManager创建输入设备 
mInputDevice = PlatformManager::getSingleton().createInputReader();

       // 初 始化,与当前渲染窗口关联 
mInputDevice->initialise(win,true, true);

获 得输入设备引用后,我们就可以主动轮询当前的设备状态,注意我们得到的只是当前这一刻设备的状态,

       // 获得设备当前快照
mInputDevice->capture(); 

之 后就可以检测设备的按键状态,

       // 检测键盘按键,KC_XXX是预定义的键盘扫描码
if (mInputDevice->isKeyDown(KC_A)) ...

       // 检 测鼠标按键,参数1表示查询第2个鼠标按键,(0-左键,1-右键, 2-中键..)
if( mInputDevice->getMouseButton( 1 ) )

剩 下的就是根据按键状态做对应的动作了。

缓存方式的工作方式则大大的不同。在缓存方式下,键盘和鼠标的输入不会丢失,而是会被转换成对应的事 件存储到队列里面去。看代码,

      // 创建一个EventProcessor,EventProcessor会自动在内部创建一 个InputReader
// (输入设备)和一个EventQueue(事件队列)。 输入设备按键按下的时候会产生对
// 应 的事件送入事件队列,这就是缓存的过程。
mEventProcessor = new EventProcessor();     

      // 在 这里创建了InputReader和EventQueue并将两者关联。
mEventProcessor->initialise(win);

      // 创 建鼠标光标
OverlayManager::getSingleton().createCursorOverlay();

      // EventProcessor 自身也是一个FrameListener对象,在这里它把自己注册到了Root
// 对象上面去,在frameStarted里面获 取设备快照,InputReader就会将按键动作
// 转换成事件提交到EventQueue里面去。
mEventProcessor->startProcessingEvents();

      // 事 件提交到EventQueue里面后,会按照FIFO的原则依次通知注册到EventProcessor
// 的Listener。 ExampleFrameListener继承了KeyListener,所以我们可以将
// ExampleFrameListener 注册到EventProcessor上面去,按键事件到来的时候
// ExampleFrameListener的 keyClicked,keyPressed和keyReleased方法将会被调用()。
mEventProcessor->addKeyListener(this);

      // 获 得输入设备的引用
mInputDevice = mEventProcessor->getInputReader();

所 以在缓存方式下我们并不是主动调用InputReader的capture方法来轮讯设备状态,而是交给EventProcessor来缓存按键事件队 列,然后再通知ExampleFrameListener处理。在缓冲方式下还有一个不同的地方就是按键不再是简单的被检测是否按下,而是有了 Pressed和Released等不同的状态。

3. OGRE Overlay, Overlay是一个容器对象,用来容纳其他的2D和 3D元素。OGRE保证在最后才渲染Overlay对象,这样Overlay总是出现在镜头的最前面,用来显示诸如FPS和LOGO这些2D元素最合适 了。Overlay可以直接创建或者从脚本文件读入属性来创建。在OGRE把zip打包文件作为一个目录来等同看待,下面创建Overlay的代码,
mDebugOverlay = (Overlay*)OverlayManager::getSingleton().getByName("Core/DebugOverlay");
就 是从ogrenew/Samples/Media/packs目录下的OgreCore.zip资源包中创建了我们看到的统计信息面板和 OGRE Logo。

了解了以上几点后ExampleFrameListener的代码就没什么秘密了,基本上就是在立即模式下根据键盘和 鼠标按键更新镜头的位置来在3D场景中漫游。可以注意到主要的代码都是在虚函数processUnbufferedKeyInput里面处理的,如果我们 在后面的demo里面想覆盖某些按键设置,只需要重载这个函数即可。下面是默认已实现的按键功能,

   Mouse: 漫游
W or Up: 向 前移动
S or Down: 向后移动
A: 向左移动
D: 向右移动
PgUp: 向上移动
PgDown: 向 下移动
F: 切换FPS显示
R: 切换渲染模式(绘制点/绘制虚线框/绘制实体多边形)
T: 切换纹理过滤模 式(双线过滤/三线过滤/各向异性)
P: 切换显示镜头位置

抱歉!评论已关闭.