ogre3D学习基础10 -- 键盘控制与鼠标控制(直接控制)

要实现键盘,鼠标对场景的控制,首先要帧监听,就是在每一帧的渲染前后对它进行操作。这里的操作没有用到缓冲区,只是简单的直接获取。

  1、这些步骤和前面的一样,直接上代码,操作还是在createScene函数里。代码如下:

 1     void createScene()

 2     {

 3         //载入实体

 4         mSceneMgr->setAmbientLight(ColourValue(0.25,0.25,0.25));//设置环境色

 5         Entity *ent1 = mSceneMgr->createEntity("ninja","ninja.mesh");

 6         SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("ninjaNode");

 7         node1->attachObject(ent1);

 8 

 9         //点光源

10         Light *light = mSceneMgr->createLight("light1");

11         light->setType(Light::LT_POINT);//点光源

12         light->setPosition(Vector3(250,150,250));

13         light->setDiffuseColour(ColourValue::White);//漫射光

14         light->setSpecularColour(ColourValue::White);//反射光

15 

16         //第一个摄像机节点

17         node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode1",Vector3(-400,200,400));

18         node1->yaw(Degree(-45));//绕y轴顺时针旋转45度

19         node1->attachObject(mCamera);

20         //第二个摄像机节点

21         node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode2",Vector3(0,200,400));

22     }

  这些代码就不解释了,如果不懂,请往前看。

  2、绑定摄像机到节点

1 void createCamera()

2     {

3         //其他参数选择默认

4         mCamera = mSceneMgr->createCamera("PlayerCam");

5         mCamera->setNearClipDistance(5);

6     }

  3、新建一个类ExampleTestFrameListener,父类为ExampleFrameListener,对鼠标和键盘的控制主要在这里面进行。其中是定义在ExampleApplication.h中的一个类,负责帧监听。构造函数如下:ExampleTestFrameListener(RenderWindow *win,Camera *cam,SceneManager *sceneMgr);

  现在开始逐渐对他进行完善:

  首先添加成员变量

1 bool mMouseDown; // 鼠标左键是否在上一帧被按下

2 Real mToggle; // 直到下一次触发的时间

3 Real mRotate; // 滚动常量

4 Real mMove; // 移动常量

5 SceneManager *mSceneMgr; // 当前场景管理器

6 SceneNode *mCamNode; // 当前摄像机所附在的场景节点

  在构造函数里对他们进行初始化

 1 ExampleTestFrameListener(RenderWindow *win,Camera *cam,SceneManager *sceneMgr)

 2         :ExampleFrameListener(win,cam,false,false)//第三个参数指明是否使用带缓冲的键盘输入,第四个参数指明是否使用带缓冲的鼠标输入

 3     {

 4         mMouseDown = false;//键盘状态记录

 5         mToggle = 0;//鼠标状态记录

 6         mCamNode = cam->getParentSceneNode();//始终指向父节点

 7         mSceneMgr = sceneMgr;

 8         mRotate = 0.13;

 9         mMove = 250;

10     }

  然后我们在每一帧里执行动作,方法就是在frameStarted()写入我们的操作。这个函数会在每一帧渲染前执行。

  第一,按下鼠标左键打开关闭灯光。

    首先获取鼠标的控制权,代码:mMouse->capture();//俘获鼠标

    然后读取鼠标按键的当前状态,代码不难理解。

      bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left);//获取鼠标当前的状态

    最后判断是否更改灯的状态

    1 if(currMouse && !mMouseDown)

    2         {

    3             Light *light = mSceneMgr->getLight("light1");//获取光源指针

    4             light->setVisible(!light->isVisible());//根据上一次的状态改变,相当于取反,由开到关,由关到开。

    5         }

    6 

    7         mMouseDown = currMouse;//更新鼠标的状态

    关于鼠标:

    通常 0 是鼠标左键,1 是右键,2 是中键。在某些系统里 1 是 中键、2 是右键。所以我们读取鼠标状态没有使用数字,而是使用了更加健壮的代码

    mMouse->getMouseState().buttonDown(OIS::MB_Left);这样能避免由于系统差别造成的问题。

  第二步,用键盘实现上下左右前后的移动。

    首先,也是捕获键盘 mKeyboard->capture();//俘获键盘

    其次,实现按下数字键1,2时切换不同的摄像机

   1      mToggle -= evt.timeSinceLastFrame;//减去从上一帧到现在所经历的时间,保证正在渲染时不切换摄像机

   2         if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_1))//按下数字键1时选择摄像机1

   3         {

   4             mToggle = 0.5f;//

   5             mCamera->getParentSceneNode()->detachObject(mCamera);//将当前摄像机从场景节点上卸载下来
   6 mCamNode = mSceneMgr->getSceneNode("CamNode1");//获取摄像机1的指针    7 mCamNode->attachObject(mCamera);//重新绑定新的摄像机    8 }    9 else if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_2))//按下数字键1时选择摄像机1   10 {   11 mToggle = 0.5f;//   12 mCamera->getParentSceneNode()->detachObject(mCamera);//将当前摄像机从场景节点上卸载下来   13 mCamNode = mSceneMgr->getSceneNode("CamNode2");//获取摄像机2的指针   14 mCamNode->attachObject(mCamera);//重新绑定新的摄像机   15 }

    其中的变量mToggle很关键,可以保证每一帧的渲染操作都是原子操作,不被中途打断,避免产生不可预测问题。 

    再次,实现按键W,A,S,D的平移,这里需要一个三元组transVector3用来保存当前摄像机的位置。

      实现前后的移动,其实就是让坐标z增大或者减小,代码如下

  1      Vector3 transVector = Vector3::ZERO;//保存平移方位

  2         if (mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W))//

  3         {

  4             transVector.z -= mMove;//z轴负方向移动

  5         }

  6         if (mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S))//

  7         {

  8             transVector.z += mMove;//z轴正方向移动

  9         }

      其他的移动操作,基本一样,只需改变z为x或y。具体代码在最后面。

    OIS:  

    开放输入系统(OIS)提供了三个主要的类来获得输入:Keyboard, Mouse, 和Joystick(摇杆) 。

  第三,实现按下鼠标右键时以一定倾斜角度拖动摄像机

    按下鼠标右键时拖动,摄像机以一定的倾斜角度改变

       //根据从上一帧开始鼠标移动的距离来控制摄像机的俯仰偏斜。

        if (mMouse->getMouseState().buttonDown(OIS::MB_Right))

        {

            mCamNode->yaw(Degree(-mRotate * mMouse->getMouseState().X.rel),Node::TS_WORLD);//以y为基础旋转

            mCamNode->pitch(Degree(-mRotate * mMouse->getMouseState().Y.rel),Node::TS_LOCAL);//以x为基础旋转

        }

  第四,在ExampleTestApplication中注册帧监听器

    具体操作时在createFrameListener()函数中,添加以下几行代码

  1      mFrameListener = new ExampleTestFrameListener(mWindow,mCamera,mSceneMgr);//创建一个帧监听器

  2         mRoot->addFrameListener(mFrameListener);//注册到Root类中

  3         mFrameListener->showDebugOverlay(true);//在层上显示帧状态

  好了,完整代码:

  

  1 #include "ExampleApplication.h"

  2 using namespace Ogre;

  3 

  4 class ExampleTestFrameListener:public ExampleFrameListener

  5 {

  6 public:

  7     ExampleTestFrameListener(RenderWindow *win,Camera *cam,SceneManager *sceneMgr)

  8         :ExampleFrameListener(win,cam,false,false)//第三个参数指明是否使用

  9         //带缓冲的键盘输入,第四个参数指明是否使用带缓冲的鼠标输入(

 10     {

 11         mMouseDown = false;// 键盘和鼠标状态追踪

 12         mToggle = 0;

 13 

 14         mCamNode = cam->getParentSceneNode();

 15         mSceneMgr = sceneMgr;

 16         //设置旋转和移动速度

 17         mRotate = 0.13;

 18         mMove = 250;

 19     }

 20     bool frameStarted(const FrameEvent& evt)

 21     {

 22         mMouse->capture();//俘获鼠标

 23         mKeyboard->capture();//俘获键盘

 24 

 25         if (mKeyboard->isKeyDown(OIS::KC_ESCAPE))//按下esc键

 26         {

 27             return false;

 28         }

 29 

 30         bool currMouse = mMouse->getMouseState().buttonDown(OIS::MB_Left);//获取鼠标当前的状态

 31         if(currMouse && !mMouseDown)

 32         {

 33             Light *light = mSceneMgr->getLight("light1");//获取灯光指针

 34             light->setVisible(!light->isVisible());//根据上一次的状态改变

 35         }

 36 

 37         mMouseDown = currMouse;//更新鼠标状态

 38 

 39         mToggle -= evt.timeSinceLastFrame;//减去从上一帧到现在所经历的时间,保证正在渲染时不切换摄像机

 40         if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_1))//按下数字键1时选择摄像机1

 41         {

 42             mToggle = 0.5f;

 43             mCamera->getParentSceneNode()->detachObject(mCamera);

 44             mCamNode = mSceneMgr->getSceneNode("CamNode1");

 45             mCamNode->attachObject(mCamera);

 46         }

 47         else if ((mToggle <0.0f) && mKeyboard->isKeyDown(OIS::KC_2))//按下数字键1时选择摄像机1

 48         {

 49             mToggle = 0.5f;

 50             mCamera->getParentSceneNode()->detachObject(mCamera);

 51             mCamNode = mSceneMgr->getSceneNode("CamNode2");

 52             mCamNode->attachObject(mCamera);

 53         }

 54 

 55         Vector3 transVector = Vector3::ZERO;//保存平移方位

 56         if (mKeyboard->isKeyDown(OIS::KC_UP) || mKeyboard->isKeyDown(OIS::KC_W))//

 57         {

 58             transVector.z -= mMove;//z轴负方向移动

 59         }

 60         if (mKeyboard->isKeyDown(OIS::KC_DOWN) || mKeyboard->isKeyDown(OIS::KC_S))//

 61         {

 62             transVector.z += mMove;//z轴正方向移动

 63         }

 64         if (mKeyboard->isKeyDown(OIS::KC_LEFT) || mKeyboard->isKeyDown(OIS::KC_A))//

 65         {

 66             transVector.x -= mMove;//x轴负方向移动

 67         }

 68         if (mKeyboard->isKeyDown(OIS::KC_RIGHT) || mKeyboard->isKeyDown(OIS::KC_D))//

 69         {

 70             transVector.x += mMove;//x轴正方向移动

 71         }

 72         if (mKeyboard->isKeyDown(OIS::KC_PGUP) || mKeyboard->isKeyDown(OIS::KC_Q))//

 73         {

 74             transVector.y -= mMove;//Y轴负方向移动

 75         }

 76         if (mKeyboard->isKeyDown(OIS::KC_PGDOWN) || mKeyboard->isKeyDown(OIS::KC_E))//

 77         {

 78             transVector.y += mMove;//Y轴正方向移动

 79         }

 80 

 81         //根据从上一帧开始鼠标移动的距离来控制摄像机的俯仰偏斜。

 82         if (mMouse->getMouseState().buttonDown(OIS::MB_Right))

 83         {

 84             mCamNode->yaw(Degree(-mRotate * mMouse->getMouseState().X.rel),Node::TS_WORLD);

 85             mCamNode->pitch(Degree(-mRotate * mMouse->getMouseState().Y.rel),Node::TS_LOCAL);

 86         }

 87         return true;

 88         //return ExampleFrameListener::frameStarted(evt);

 89     }

 90     bool frameEnded(const FrameEvent& evt)

 91     {

 92         return ExampleFrameListener::frameEnded(evt);

 93     }

 94 protected:

 95     bool mMouseDown;// 鼠标左键是否在上一帧被按下

 96     Real mToggle;//直到下一次触发的时间间隔

 97     Real mRotate;//滚动常量

 98     Real mMove;//移动常量

 99     SceneManager *mSceneMgr;//当前的场景管理器

100     SceneNode *mCamNode;//当前的摄像机所绑定的场景节点

101 private:

102 };

103 

104 

105 class ExampleTestApplication:public ExampleApplication

106 {

107 public:

108     ExampleTestApplication()

109     {

110 

111     }

112     ~ExampleTestApplication()

113     {

114 

115     }

116 

117 protected:

118     void createCamera()

119     {

120         //其他参数选择默认

121         mCamera = mSceneMgr->createCamera("PlayerCam");

122         mCamera->setNearClipDistance(5);

123     }

124     void createScene()

125     {

126         //载入实体

127         mSceneMgr->setAmbientLight(ColourValue(0.25,0.25,0.25));//设置环境色

128         Entity *ent1 = mSceneMgr->createEntity("ninja","ninja.mesh");

129         SceneNode *node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("ninjaNode");

130         node1->attachObject(ent1);

131 

132         //点光源

133         Light *light = mSceneMgr->createLight("light1");

134         light->setType(Light::LT_POINT);//点光源

135         light->setPosition(Vector3(250,150,250));

136         light->setDiffuseColour(ColourValue::White);//漫射光

137         light->setSpecularColour(ColourValue::White);//反射光

138 

139         //第一个摄像机节点

140         node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode1",Vector3(-400,200,400));

141         node1->yaw(Degree(-45));//绕y轴顺时针旋转45度

142         node1->attachObject(mCamera);

143         //第二个摄像机节点

144         node1 = mSceneMgr->getRootSceneNode()->createChildSceneNode("CamNode2",Vector3(0,200,400));

145     }

146     void createFrameListener()

147     {

148         mFrameListener = new ExampleTestFrameListener(mWindow,mCamera,mSceneMgr);//创建一个帧监听器

149         mRoot->addFrameListener(mFrameListener);//注册到Root类中

150         mFrameListener->showDebugOverlay(true);//在层上显示帧状态

151     }

152 };

153 

154 #include "windows.h"

155 

156 

157 

158 INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )

159 

160 

161 {

162     ExampleTestApplication app;

163         app.go();

164     return 0;

165 }
全部代码

  图片就不上了,本来想截取几个gif格式的动画上来的,可一直没找到好工具。

你可能感兴趣的:(学习)