第056章-第四章-获取用户输入和使用帧监听课件_第1页
第056章-第四章-获取用户输入和使用帧监听课件_第2页
第056章-第四章-获取用户输入和使用帧监听课件_第3页
第056章-第四章-获取用户输入和使用帧监听课件_第4页
第056章-第四章-获取用户输入和使用帧监听课件_第5页
已阅读5页,还剩22页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

游戏设计概论任课教师:张洪江游戏设计概论(第二版)第四章获取用户输入和使用帧监听认识什么是帧监听认识如何处理用户输入结合两种概念创建我们自己的摄像机控制游戏设计概论(第二版)实践时刻——准备一个场景我们将使用和之前章节中略微不同的创建场景的版本。1.删除createScene()和createCamera()函数中的所有代码:2.删除createViewports()函数。3.添加一个新的成员变量到类中。这个成员变量是一个场景结点的指针:private:Ogre::SceneNode*_SinbadNode;4.使用createScene()函数创建一个平面并添加它到场景之中:Ogre::Planeplane(Vector3::UNIT_Y,-10);Ogre::MeshManager::getSingleton().createPlane("plane",ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,plane,1500,1500,200,200,true,1,5,5,Vector3::UNIT_Z);Ogre::Entity*ent=mSceneMgr->createEntity("LightPlaneEntity","plane");mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(ent);ent->setMaterialName("Examples/BeachStones");游戏设计概论(第二版)实践时刻——准备一个场景5.然后添加一个光源到场景中:Ogre::Light*light=mSceneMgr->createLight("Light1");light->setType(Ogre::Light::LT_DIRECTIONAL);light->setDirection(Ogre::Vector3(1,-1,0));6.我们也需要一个Sinbad的实例,创建一个结点并关联实例。Ogre::SceneNode*node=mSceneMgr->createSceneNode("Node1");mSceneMgr->getRootSceneNode()->addChild(node);Ogre::Entity*Sinbad=mSceneMgr->createEntity("Sinbad","Sinbad.mesh");_SinbadNode=node->createChildSceneNode("SinbadNode");_SinbadNode->setScale(3.0f,3.0f,3.0f);_SinbadNode->setPosition(Ogre::Vector3(0.0f,4.0f,0.0f));_SinbadNode->attachObject(Sinbad);游戏设计概论(第二版)实践时刻——准备一个场景7.我们也想在场景中增加阴影;所以添加它们:mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE);8.创建一个摄像机并放置它在(0,100,200)并把镜头朝向(0,0,0);记住添加代码到createCamera()函数中。mCamera=mSceneMgr->createCamera("MyCamera1");mCamera->setPosition(0,100,200);mCamera->lookAt(0,0,0);mCamera->setNearClipDistance(5);9.编译运行,你将会看到下面图中的效果游戏设计概论(第二版)实践时刻——添加运动到场景中目前为止,我们只有一个类,即是,ExampleApplication。这次我们需要另一个类:1.创建一个新类,命名为Example25FrameListener,并使它公有继承Ogre::FrameListener】classExample25FrameListener:publicOgre::FrameListener{};2.添加一个私有的成员变量,一个Ogre::SceneNode的指针,并把它命名为_node】private:Ogre::SceneNode*_node;3.添加接收一个Ogre::SceneNode指针为参数的公有构造函数,并把这个指针赋值操作给成员变量node指针。public:Example25FrameListener(Ogre::SceneNode*node){_node=node;}游戏设计概论(第二版)实践时刻——添加运动到场景中8.编译运行程序。你应看到和之前相同的场景。但是这次,Sinbad的实例向右边移动了并且你不能移动摄像机或用Escape键关闭程序。你可以使用控制台窗口的X按钮关闭窗口。如果你从控制台启动程序,你可以使用CTRL+C来结束程序。游戏设计概论(第二版)刚刚发生了什么?我们添加了一个可以移动我们场景结点的类到我们的代码中。游戏设计概论(第二版)帧监听帧监听是基于一个观察者的模式。我们可以添加一个类的实例。你可以使用Ogre::Root的addFrameListener()方法,通过继承自Ogre::FrameListener的接口,添加一个对象到我们的Ogre3D根对象中。当对象被添加时,在确定的事件发生时我们的类就会得到通知。在这个例子中,我们重写了frameStarted()方法。在帧(帧,意思是指场景中的单个图像)被渲染之前,Ogre::Root遍历所有被添加的Framelistener并调用其frameStarted()方法。我们第四步中的函数定义中,我们沿X轴每帧0.1单位的速率变换结点。这个结点通过Framelistener的构造函数的传入。因此,场景每次被渲染的时候,结点就变换一点位置。结果,模型就移动了。正如我们在程序运行时看到的,我们不能移动摄像机或使用Escape键退出。这是因为这些是由Framelistener来操作的,而这个FrameListener是ExampleApplication框架自带的。ExampleApplication是SDK自带的。现在我们代替其原有的FrameListener,使用我们自己定义的实现过程。这样我们就不能使用自带的Framelistener,但是这章我们将会重新实现他们中的大部分,所以不用担心。如果需要,我们可能仍然调用基类的成员函数来获得默认的行为。在第四步中,我们函数返回true。如果返回false,Ogre3D将会解释false为退出渲染循环的标志,而与此同时,程序就会结束。我们将会重新实现“按Escape键退出”的函数。游戏设计概论(第二版)简单测试——FrameListener的设计模式

1.Framelistener概念的模式是基于?a.Decorator【装饰者】b.Bridge 【桥】c.Observer 【观察者】游戏设计概论(第二版)英雄动起来——添加第二个模型添加第二个模型到场景并使它沿场景中Sinbad模型的相反方向运动。游戏设计概论(第二版)添加输入支持我们现在已经有含移动物体的场景,但是我们想要程序可以像原来一样退出。因此,我们将会添加输入支持,并当Escape键按下的时候,我们可以退出程序。目前为止,我们只使用了Ogre3D;现在,我们将会使用OIS(ObjectOrientedInputSystem[面向对象的输入系统]),OIS是Ogre3DSDK自带的,因为它被ExampleFrameListener所使用,但是在其他方面它是从Ogre3D中完全独立出来的。

游戏设计概论(第二版)实践时刻——添加输入支持同样的,我们使用之前的代码并添加必要的代码以获得输入支持:】【1.我们需要添加一个新的参数到Listener的构造函数。】Example27FrameListener(Ogre::SceneNode*node,RenderWindow*win)【2.当改变构造函数时,我们也需要改变实例化的地方:】Ogre::FrameListener*FrameListener=newExample27FrameListener(_SinbadNode,mWindow);【3.在这之后,我们需要添加代码到listener的构造函数。首先,我们需要两个辅助变量:】size_twindowHnd=0;std::stringstreamwindowHndStr;【3.现在请求Ogre3D获取渲染的窗口句柄:】win->getCustomAttribute("WINDOW",&windowHnd);

【4.转换handle为一个string:】windowHndStr<<windowHnd;游戏设计概论(第二版)实践时刻——添加输入支持【6.创建一个OIS参数表并添加窗口句柄:】(注:这章中参数表代表ParamList,而ParamList是OISPrereqs.h中std::multimap<std::string,std::string>的别名,而multimap请参考STL的容器。)OIS::ParamListpl;pl.insert(std::make_pair(std::string("WINDOW"),windowHndStr.str()));【7.使用参数表创建输入系统:】_man=OIS::InputManager::createInputSystem(pl);【8.然后创建一个keyboard,这样我们就可以检查用户的输入了:】_key=static_cast<OIS::Keyboard*>(_man->createInputObject(OIS::OISKeyboard,false));【9.我们创建的对象,必须在最后回收。添加一个析构函数到帧监听类中,这将会析构我们的OIS对象:】~Example27FrameListener(){_man->destroyInputObject(_key);OIS::InputManager::destroyInputSystem(_man);}游戏设计概论(第二版)实践时刻——添加输入支持【10.在我们完成初始化之后,添加下面的代码到frameStarted()函数中的node变换之后,return之前:】_key->capture();if(_key->isKeyDown(OIS::KC_ESCAPE)){returnfalse;}【11.添加用户输入对象作为成员变量到帧监听类中:】OIS::InputManager*_man;OIS::Keyboard*_key;【12.编译运行程序。你现在应该可以看到程序可以通过按Escape键退出。】游戏设计概论(第二版)刚刚发生了什么?我们创建了一个输入系统的实例并使用实例来获取用户的键盘输入。因为我们需要窗口的句柄来创建输入系统,我们改变帧监听类的构造函数,这样它就可以接受传递过来的一个渲染窗口的指针。这已经在第一步中完成了。我们然后从数值到字符串转换句柄并添加字符串到OIS的参数表。通过参数表,我们可以创建我们输入系统的实例。游戏设计概论(第二版)窗口句柄一个窗口句柄仅仅是一个识别窗口的数值。这个数值是由操作系统创建并且每个窗口都有自己独一无二的句柄。输入系统需要这个句柄,因为没有它,输入系统就不能获取输入事件。Ogre3D为我们创建了一个窗口。所以为了获得窗口句柄,我们需要请求Ogre3D执行下面一行代码:win->getCustomAttribute("WINDOW",&windowHnd);游戏设计概论(第二版)窗口句柄渲染的窗口有多种属性,Ogre3D实现了一个通用getter函数。Ogre3D也需要平台独立,因为每个平台都有自己的窗口句柄的变量类型,所以通用的函数是跨平台的唯一方法。这段代码中,WINDOW是窗口句柄的标识符。我们需要传递传递一个指针来存贮句柄的值;在函数中这个指针将会被覆写。在我们接受句柄之后,我们使用stringstream来转换它为一个string类型,因为这是OIS所需要的。OIS有同样的问题并使用同样的解决办法。在创建时,我们给OIS一个对组的参数表,这个对组是由一个标识字符串和一个字符串的值组成。在第六步中,我们创建了这个参数表并添加字符串类型的句柄。在第七步使用这个参数表创建了输入系统。通过运用输入系统,我们可以在第八步中创建我们键盘接口。这个接口将会用于查询系统——用户按下的是哪个键?这一步将会在第九步中完成(译者:原作者应该指的是第十步)。每次在我们渲染帧之前,我们使用capture()函数来获取键盘的新状态。如果不调用这个函数,我们将不会得到键盘的新状态,并此因我们将永远得不到键盘事件了。在更新完状态之后,我们查询键盘是否现在按下Escape键。当按下的时候,我们了解到用户想要退出用户程序。这意味着我们必须返回false让Ogre3D知道我们关闭程序。否则,如用户想要程序持续运行,我们可以返回true来使程序持续运行。游戏设计概论(第二版)给模型添加动作现在我们已经有能力获取用户的输入,现在让我们使用它来控制Sinbad的在平面上的运动吧。游戏设计概论(第二版)实践时刻——控制Sinbad我们使用以前的代码并添加代码到我们需要的地方,正如之前所做的一样。我们将会使用以下代码,使用WASD键来控制Sinbad。if(_key->isKeyDown(OIS::KC_W)){translate+=Ogre::Vector3(0,0,-10);}if(_key->isKeyDown(OIS::KC_S)){translate+=Ogre::Vector3(0,0,10);}if(_key->isKeyDown(OIS::KC_A)){translate+=Ogre::Vector3(-10,0,0);}if(_key->isKeyDown(OIS::KC_D)){translate+=Ogre::Vector3(10,0,0);}游戏设计概论(第二版)实践时刻——控制Sinbad现在使用向量来变换模型,并记住使用基于时间的运动而非基于帧的运动:Ogre::Vector3translate(0,0,0);//translate先要定义成一个向量_node->translate(translate*evt.timeSinceLastFrame);//必须移到这个位置returntrue前面;编译运行程序,然后你就可以用WASD键来控制Sinbad了。游戏设计概论(第二版)实践时刻——让我们的摄像机再次工作创建摄像机。让它和用户输入结合起来。

1.扩展帧监听的构造函数,让它接受一个camera指针:Example30FrameListener(Ogre::SceneNode*node,RenderWindow*win,Ogre::Camera*cam)2.同样添加一个成员变量来储存camera指针:Ogre::Camera*_Cam;3.然后添加参数到成员变量:_Cam=cam;游戏设计概论(第二版)实践时刻——让我们的摄像机再次工作【4.修改帧监听的初始化并添加camera指针:】Ogre::FrameListener*FrameListener=newExample30FrameListener(_SinbadNode,mWindow,mCamera);【5.我们需要获得鼠标的输入以移动摄像机。所以创建一个新的成员变量来存贮鼠标:】OIS::Mouse*_mouse;【6在构造函数中,在键盘操作后初始化鼠标:】_mouse=static_cast<OIS::Mouse*>(_man->createInputObject(OIS::OISMouse,false));游戏

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论