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

你可能感兴趣的:(框架)