Ogre: 建立一个简单的框架——响应键盘事件

[转载请保证内容的完整性和正确性]

建立一个简单的框架——响应键盘事件

上一节我们在场景中添加了一个机器人,这一节我们将建立一个FrameListener类(顾名思义,这是一个侦听类),来控制模型进行移动。

创建FrameListener类

FrameListener类主要负责事件的侦听,如帧结束、键盘输入等事件。它继承自ExampleFrameListener类,如果需要的话还可以继承KeyListener(键盘事件)、MouseListener(鼠标事件)和JoyStickListener(游戏杆事件)。这里只有键盘事件。

1 //DemoFrameListener.h
2  class DemoFrameListener : public ExampleFrameListener, public OIS::KeyListener {
3  public:
4      DemoFrameListener(RenderWindow* _win, Camera* _cam, bool bufferKeys,
5          bool bufferMouse, bool bufferJoy);
6      bool keyPressed(const OIS::KeyEvent& arg);
7      bool keyReleased(const OIS::KeyEvent& arg);
8      bool frameEnded(const FrameEvent& evt);
9  }; 
 1 //DemoFrameListener.cpp
 2  DemoFrameListener::DemoFrameListener(RenderWindow* _win, Camera* _cam, bool bufferKeys,
 3          bool bufferMouse, bool bufferJoy)
 4          : ExampleFrameListener(_win, _cam, bufferKeys, bufferMouse, bufferJoy) {
 5
 6  }
 7
 8  bool DemoFrameListener::keyPressed(const OIS::KeyEvent& arg) {
 9      return true;
10  }
11
12  bool DemoFrameListener::keyReleased(const OIS::KeyEvent& arg) {
13      return true;
14  }
15
16  bool DemoFrameListener::frameEnded(const FrameEvent& evt) {
17      return true;
18  } 

在Application类中添加新的方法。

1 //DemoApplication.cpp
2  void DemoApplication::createFrameListener(void) {
3      mFrameListener = new DemoFrameListener(mWindow, mCamera, true, true, true);
4      mRoot->addFrameListener(mFrameListener);
5  } 

这时运行代码,还是能看到和上一节一样的机器人,但是鼠标、键盘都不能移动摄像机了。接下来我们将添加自己的控制方法。

创建Manager类

在添加控制方法之前,我们要先优化一下代码结构。上一节中我们把添加模型的代码写到了Application类中,这次我们要创建一个Manager类,来统一管理这些模型资源。

 1 //DemoManager.h
 2  class DemoManager
 3  {
 4  public:
 5      DemoManager(Ogre::SceneManager* _sm);
 6      ~DemoManager(void);
 7      void Update();
 8      void SetDeltaT(float _dt);
 9  private:
10      Ogre::SceneManager* sm;
11      float deltaT;
12      Ogre::SceneNode* rootsn;
13      Ogre::SceneNode* node;
14  }; 

添加构造函数中的代码

1 //DemoManager.cpp
2  DemoManager::DemoManager(Ogre::SceneManager* _sm) : sm(_sm) {
3      Ogre::Entity* ent = sm->createEntity("Robot", "robot.mesh");
4      rootsn = sm->getRootSceneNode();
5      node = rootsn->createChildSceneNode("RobotNode");
6      node->attachObject(ent);
7  } 

其他函数中也略作修改。

1 //DemoApplication.h
2  //添加变量
3  private:
4      DemoManager* demoManager;
 1 //DemoApplication.cpp
 2  //修改两个函数
 3  void DemoApplication::createScene(void) {
 4      mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
 5      Light* l = mSceneMgr->createLight("MainLight");
 6      l->setPosition(20, 80, 50);
 7
 8      demoManager = new DemoManager(mSceneMgr);
 9  }
10
11  void DemoApplication::createFrameListener(void) {
12      mFrameListener = new DemoFrameListener(mWindow, mCamera, true, true, true, demoManager);
13      mRoot->addFrameListener(mFrameListener);
14  }
1 //DemoFrameListener.h
2  //修改构造函数声明
3 DemoFrameListener(RenderWindow* _win, Camera* _cam, bool bufferKeys,
4      bool bufferMouse, bool bufferJoy, DemoManager* _dm);
1 //DemoFrameListener.cpp
2  //修改构造函数
3 DemoFrameListener::DemoFrameListener(RenderWindow* _win, Camera* _cam, bool bufferKeys,
4      bool bufferMouse, bool bufferJoy, DemoManager* _dm)
5      : ExampleFrameListener(_win, _cam, bufferKeys, bufferMouse, bufferJoy), demoManager(_dm) {
6
7  } 

这是运行代码可以看到和之前一样的界面,但是我们的代码结构已经得到了优化,分为了三部分:Application(管理结构)、FrameListener(处理事件)和Manager(管理资源)。

添加键盘事件

我们将添加6个按键,WASD进行平移,QE进行水平旋转。

首先,为了能够让移动不受帧率的影响,我们让移动随时间变化。我们要传给Manager类每一帧间隔的时间。

1 //DemoManager.cpp
2  void DemoManager::SetDeltaT(float _dt) {
3      deltaT = _dt;
4  } 

然后定义键盘事件:

 1 //DemoFrameListener.cpp
 2  bool DemoFrameListener::keyPressed(const OIS::KeyEvent& arg) {
 3      Ogre::Vector3 movement(0, 0, 0);
 4      float yaw(0);
 5
 6      switch (arg.key) {
 7      case OIS::KC_W:
 8          movement.z -= 1000;
 9          break;
10      case OIS::KC_S:
11          movement.z += 1000;
12          break;
13      case OIS::KC_A:
14          movement.x -= 1000;
15          break;
16      case OIS::KC_D:
17          movement.x += 1000;
18          break;
19      case OIS::KC_Q:
20          yaw += 5;
21          break;
22      case OIS::KC_E:
23          yaw -= 5;
24          break;
25      }
26
27      demoManager->SetMovement(movement);
28      demoManager->SetRotation(yaw);
29      return true;
30  } 

为了方便,我们再定义一个退出程序的按键。

 1 //DemoFrameListener.cpp
 2  bool DemoFrameListener::keyReleased(const OIS::KeyEvent& arg) {
 3      if (arg.key == OIS::KC_ESCAPE) {
 4      _exit = true;
 5      }
 6      return true;
 7  }
 8
 9  bool DemoFrameListener::frameEnded(const FrameEvent& evt) {
10      ExampleFrameListener::frameEnded(evt);
11      if (demoManager) {
12          demoManager->SetDeltaT(evt.timeSinceLastFrame);
13          demoManager->Update();
14      }
15
16      return (!_exit);
17  } 

然后在Manager中接收按键事件:

 1 //DemoManager.cpp
 2  void DemoManager::Update() {
 3      node->translate(movement * deltaT);
 4      node->yaw(Ogre::Radian(yaw * deltaT));
 5
 6      movement = Ogre::Vector3(0, 0, 0);
 7      yaw = 0;
 8  }
 9
10  void DemoManager::SetMovement(Ogre::Vector3 _movement) {
11      movement = Ogre::Vector3(_movement);
12  }
13
14  void DemoManager::SetRotation(float _yaw) {
15      yaw = _yaw;
16  } 

这里可以看出,我们对3D模型做的变换其实就是对场景节点做的变换。

运行这段代码,我们虽然可以控制模型机器人,但是需要一下一下地按键。要改善这个问题就要修改FrameListener类,其中有keyPressed和keyReleased两个方法,分别是按下键盘和释放键盘,略作修改就能实现长按事件。

时间: 2024-10-26 11:52:22

Ogre: 建立一个简单的框架——响应键盘事件的相关文章

Ogre: 建立一个简单的框架——关于场景节点

[转载请保证内容的完整性和正确性] 建立一个简单的框架——关于场景节点 如果我们要做一个类似于<跑跑卡丁车>的游戏,人物模型是需要随着卡丁车模型一起进行各种变换的(平移.旋转等),我们需要分别计算两个关联的模型的位置吗?这样能解决问题,但是太麻烦了,利用Ogre的场景节点可以很方便地解决这种问题. 添加一个新的模型 之前添加的模型都是由3DMAX等软件导出的模型,接下来我们利用Ogre生成一个Cube模型. 1 //DemoManager.cpp 2 Ogre::ManualObject* c

Hibernate学习——建立一个简单的Hibernate项目

最近老师让做个web小应用,大三的时候学习过一点J2EE的东西,也做过一些web相关的XXX管理系统,都是用servlet,jsp这些完成的,虽然勉强能够完成任务,但其中各种代码掺杂在一起,不好看而且维护起来也很麻烦,出了一点问题要调试好久才能解决.这次打算让自己多学一点东西,在项目的架构上我使用了struts2实现了多层代码的分离,在数据库方面,因为以往的经历都需要对连接数据库进行一个封装,里面包含有数据库的连接,记录的添加,查询,修改和删除等操作,每次使用的过程中都需要先实现一个连接对象然后

【Java编程】建立一个简单的JDBC连接-Drivers, Connection, Statement and PreparedStatement

本blog提供了一个简单的通过JDBC驱动建立JDBC连接例程,并分别通过Statement和PreparedStatement实现对数据库的查询.在下一篇blog中将重点比较Statement与PreparedStatement的差异. 1.为项目添加JDBC驱动 1)JDBC驱动下载 官方下载地址:mysql-connector-java-5.0.8.zip CSDN资料下载地址:mysql-connector-java-5.0.8.zip 2)为项目添加JDBC驱动 建立项目Java项目J

TCP学习之建立一个简单的客户/服务器系统--回射系统

TCP学习之建立一个简单的客户/服务器系统--回射系统 相关的资料可以参考Unix网络编程,这个只是修改版,不需要依赖任何文件,可以独立编译通过,而且是在两台不同的主机上进行的. fggets和fputs这两个函数来自标准I/O函数库,writen和readline见my_unp.h头文件 //my_unp.h #include<stdarg.h> #include<syslog.h> #include<stdio.h> #include<netinet/in.h

WebADI_建立一个简单的WebADI实现日记账上传(案例)

2014-06-01 BaoXinjian 一.摘要 WebADI原本固定资产导入和日记账导入的一些工具发展而来,因为财务部门人员大多非常熟悉Excel,希望竟可能尽量多的使用Excel工具去进行财务操作 而WebADI提供了这样一种可能性通过excel,将资料建立客制化的API或Interface处理,导入至EBS中 在11i中,WebADI可能还不够完善,还需要很多代码操作和注册 在R12中,WebADI的功能有进一步的加强 个人觉得,如果资料导入API或Interface不是太过频繁,数据

学习用node.js建立一个简单的web服务器

一.建立简单的Web服务器涉及到Node.js的一些基本知识点: 1.请求模块 在Node.js中,系统提供了许多有用的模块(当然你也可以用JavaScript编写自己的模块,以后的章节我们将详细讲解),如http.url等.模块封装特定的功能,提供相应的方法或属性,要使用这些模块,需要先请求模块获得其操作对象. 例如要使用系统的http模块,可以这样写: var libHttp = require('http'); //请求HTTP协议模块 这样,以后的程序将可以通过变量libHttp访问ht

Hyperledger Fabric 建立一个简单网络

p { margin-bottom: 0.25cm; line-height: 120% } Building you first network 网络结构: 2个Orgnizations(每个Org包含2个peer节点)+1个solo ordering service 打开fabric-sample下的示例first-network p { margin-bottom: 0.25cm; line-height: 120% } 其中byfn.sh为启动这个网络的启动脚本,启动脚本中除建立一个包含

搭建一个简单struts2框架的登陆

第一步:下载struts2对应的jar包,可以到struts官网下载:http://struts.apache.org/download.cgi#struts252 出于学习的目的,可以把整个完整的压缩文件都下载下来. 里面包括:1 apps:示例应用,对学习很有帮助 : 2 docs:相关学习文档.API文档等: 3 lib:核心类库,依赖包: 4:src:源代码 第二步:在eclipse新建一个Dynamic Web Project类型工程,一直点next,记得勾选generate web.

SCSI miniport 驾驶一个简单的框架

前段时间,只需用一台新电脑,由于资金有限没有匹配了心仪已久的SSD.我没感觉到飞翔的感觉,总不甘心,仔细想想.我死了相当大的存储,我们可以假设部分内存作为硬盘驱动器把它弄出来.不会比固态硬盘的速度快,我们開始吧. 首先.我们要做的就是写一个硬盘控制器的驱动,我们知道.存储类型的驱动一般都遵守 class/port/miniport driver 这种结构.微软已经完毕了磁盘类的驱动,以及 SCSI 总线的 Port 驱动,我们仅仅须要完毕 SCSI 总线上硬盘控制器的 Miniport 驱动就能