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两个方法,分别是按下键盘和释放键盘,略作修改就能实现长按事件。

原文地址:https://www.cnblogs.com/fks143/p/4337533.html