




免费预览已结束,剩余39页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
摘 要随着CPU运算能力提升和独立显卡渲染3D图形的加速,3D游戏已成为游戏开发的主流。游戏公司一般都在Windows下购买商用的或者内部自主研发的游戏引擎作为游戏开发的框架,这对于游戏开发爱好者来说代价过于昂贵。然而免费的游戏引擎文档不齐全,难以搭建起编程平台。本文将介绍如何在Linux下利用Ogre图形渲染引擎、Newton物理引擎和连接这两个引擎的OgreNewt库作为工具,开发出两种不同的3D游戏场景。场景的实现具有良好的移植性,只要有必要的库文件,也可在Windows下运行。本文首先介绍了编写游戏当中需要用到的与Ogre、Newton和OgreNewt的相关技术,然后对这两个游戏场景进行了需求分析和整体框架的建模,接着编写Makefile脚本把这三个源码的头文件和链接库合成一个“完整”的游戏引擎,最后讲解了具体的实现细节。具体的实现中用了多态、继承和模板等技术降低了模块间的耦合性;使用单件模式和工厂模式实现了统一实例化和管理实体,降低了代码的复杂性。关键词:游戏引擎;3D游戏;游戏场景Abstract3D games have become the main stream of game development with the enhancement of the CPU computing and the acceleration of the 3D graphics rendering by discrete display card. It is too expensive for the lovers of game development that most of game engines today are ready-made to be bought or developed within the independent research. However, the documents of the free game engines are not complete that it is hard to set up the programming platform.This paper introduced how to develop two different types of 3D game scenes racing and shooting games using three engines graphics rendering engine Ogre, physics engine Newton and OgreNewt library that connects these two as the development tool under Linux operating system.Firstly, the Paper introduced the related technologies to Ogre, Newton and OgreNewt used in the game development. Then, requirement analysis and the whole framework modeling of the two game scenes are presented. After that, a Makefile script fusion of these three head files and link libraries made a complete game engine. Finally, the Paper introduced the concrete realization details using polymorphism, inheritance template and other technologies to decreases the degree of coupling between different modules and design patterns such as Singleton, Factory to integrate the instantiations and manage entities that reducing unnecessary code.Key words: Game Engine; 3D Game; Game Scene目 录第一章 引言11.1 研究背景11.2 主要研究内容11.3 论文结构2第二章 相关技术32.1 Ogre 图形渲染引擎32.1.1 程序入口32.1.2 资源管理器42.1.3 场景管理器42.1.4 场景节点52.1.5 实体62.2 Newton 物理引擎72.2.1 物理引擎72.2.2 轴72.2.3 作用力回调函数82.2.4 力矩92.2.5 刚体和碰撞体92.3 OgreNewt102.4 设计模式10第三章 游戏场景的需求分析和总体设计123.1 赛车场景123.1.1 项目需求123.1.2 总体设计123.2 射击场景133.2.1 项目需求133.2.2 总体设计13第四章 游戏场景的框架及实现154.1 游戏编程平台的搭建154.1.1 游戏开发环境的搭建154.1.2 自动编译脚本154.2 实体基类设计164.3 赛车场景设计174.4 射击场景设计224.4.1 实体容器类设计224.4.2 队伍类设计234.4.3 特殊单件模式类244.4.4 管理器基类254.4.5 死亡实体管理器与队伍管理器264.4.6 实例化实体的工厂类284.4.7 实体的生命周期284.4.8 策略管理器29第五章 游戏场景的运行结果315.1 赛车场景315.2 射击场景32第六章 总结与展望346.1 论文总结346.2 工作展望34参考文献36致 谢38ContentsChapter 1 Introduction11.1 Study Background11.2 Main Study Content11.3 The Structure of This Paper2Chapter 2 Related Technology32.1 Ogre Graphics Rendering Engine32.1.1 Program Entry32.1.2 Resources Manager42.1.3 Scenes Manager42.1.4 Scene Node52.1.5 Entity62.2 Newton Physics Engine72.2.1 Physics Engine72.2.2 Joint72.2.3 Force Callback Function82.2.4 Torque92.2.5 Rigid Body and Collision Body92.3 OgreNewt102.4 Design Paterns10Chapter 3 Analysis and Design for The Game Scene123.1 Racing Scene123.1.1 Project Requirements123.1.2 Design123.2 Shooting Scene133.2.1 Project Requirements133.2.2 Design13Chapter 4 Framework and Implementation for The Game Scene154.1 Build Game Programming Platform154.1.1 Build Game Development Enviroment154.1.2 Script for Automatically Compile154.2 Design of The Base Class164.3 Racing Scene Design174.4 Shooting Scene Desing224.4.1 Design of The Container Class224.4.2 Design of The Team234.4.3 Special Singleton Pattern244.4.4 Base Manager Class254.4.5 Dead Body Manager and Team Manager264.4.6 Factory Class for Instantiated Entities284.4.7 Entity Life Cycle284.4.8 Strategy Manager29Chapter 5 The Running Results of Game Scenes315.1 Racing Scene315.2 Shooting Scene32Chapter 6 Summary and Future work346.1 Summary of This Paper346.2 Improvements and Future Work34References36Acknowledgements38Linux 下基于OgreNewt的游戏场景构建与实现第一章 引言1.1 研究背景3D游戏就是三维游戏, 三维游戏中的点的位置由三个坐标决定的。客观存在的现实空间就是三维空间,具有长、宽、高三种度量。三维游戏(3D游戏)是相对于二维游戏(2D游戏)而言的,因其采用了立体空间的概念,所以更显真实,而且对空间操作的随意性也较强,也更容易吸引人。3D游戏是使用空间立体计算技术实现操作的游戏。从编程实现角度来说游戏基础模型(游戏的人物,场景,基础地形)是使用三维立体模型实现的,游戏的人物角色控制是使用空间立体编程算法实现的,这种游戏称作3D游戏。3D游戏比2D游戏多了一个维度,开发难度也就提高了许多。如果从底层的API开始开发,代码将不可复用开发效率极低,因此很多游戏公司都直接购买现成的或者内部自主开发的游戏引擎。引擎相当于游戏的框架,框架打好后,关卡设计师、建模师、动画师只要往里填充内容就可以了。因此,在3D游戏的开发过程中,引擎的制作往往会占用非常多的时间,马克思佩恩的MAX-FX引擎从最初的雏形Final Reality到最终的成品共花了四年多时间,LithTech引擎的开发共花了整整五年时间,耗资700万美元。对于游戏开发爱好者来说,购买或者开发游戏引擎代价过于昂贵。因此他们往往选择开放源码1的游戏引擎,开放源码软件是指保证所有人可以得到这些代码,没有一个公司可以完全独占它。但很多开源软件文档不齐全,这提升了游戏开发平台搭建的难度,因此利用免费的源码搭建起编程平台是游戏开发爱好者开发游戏的关键。1.2 主要研究内容赛车游戏实现的难点:获取赛车与当前道路的关系,给赛车添加物理特性给人一种真实感;射击游戏实现的难点:射击类游戏中有大量的实体,如何管理这些实体是游戏开发的难点。本文在Linux下以Ogre2、Newton3和OgreNewt4三个引擎搭建起编程平台并开赛车游戏和射击游戏两个游戏场景,解决这两类游戏的开发难点。1.3 论文结构本文划分为六章,文章的安排结构如下:第一章 简单介绍了3D游戏、游戏引擎和开放源码,针对游戏编程爱好者游戏开发会遇到的难点,提出了毕业设计的目标和研究价值。第二章 介绍本文中用到的与Ogre、Newton和OgreNewt的相关技术。第三章 利用Makefile搭建起游戏开发平台。第四章 介绍如何实现两个游戏场景的框架。第五章 介绍了两个游戏场景的具体实现细节。第六章 总结了毕业设计所作的工作,并指明了下一步改进计划。主要是在界面和平滑度方面的改进计划。37第二章 相关技术2.1 Ogre 图形渲染引擎OGRE,全称Object-Oriented Graphics Rendering Engine(面向对象图形渲染引擎),是一个成熟、稳定、可靠、灵活、跨平台,而且拥有丰富功能实时3D图形库,让程序员可以在应用程序中采用面向对象的方式来表现复杂3D的空间。它3D图形的应用程序提供了“强大的动力”,进而允许更多关注应用程序细节而不是一个3D场景的渲染过程。作为应用程序的中间件,OGRE扮演了一个专注于处理了三维空间场景的角色,用户可以用很少量的代码来构建一个完整的三维场景。Steve Streeting于2001年创建Ogre项目,它是一个开源软件项目,这意味着你“通常”可以免费的随意使用它,只要遵守它所使用的LGPL协议5就可以了。虽然是开源项目,但它几乎拥有了商业3D渲染引擎的全部特性,例如:全面并同等的支持OpenGL和Direct3D、跨平台、自动处理渲染状态和空间剪裁、支持渲染到纹理技术和投影纹理等多种特性,甚至在某些方面超越了它们。在游戏当中主要用到Root对象,资源管理器,场景管理器,场景查询,以下对Ogre的这几部分依次进行详细介绍。2.1.1 程序入口Root对象是一个Ogre应用程序的主入口点。因为它是整个Ogre引擎的外观(Facade)类6,它提供了方便的调用整个Ogre每个子系统的接口。通过Root对象来启动和停止Ogre是最简单的一种方式;当你生成一个Root实例的时候就启动了整个Ogre,当析构的时候(让它停止活动或者执行delete删除它)Ogre也就关闭了。程序中一般不直接使用Root对象,而是用Root对象创建的场景管理器。2.1.2 资源管理器渲染场景需要相应的资源,Ogre使用Singleton类对象ResourceGroupManager作为资源管理器,这个对象的实例用于查找资源的具体位置(应用程序指定的路径)和初始化(不一定载入)已知类型的资源。Ogre引擎中有以下6种资源类型:(1) 材质资源:在.material文件中包含的材质脚本定义(技术、通路、纹理单元等数据的定义);(2) 模型资源:经过优化的二进制网格模型文件,扩展名为.mesh。包含几何信息和一些动画数据;(3) 骨骼资源:经过优化的二进制骨骼文件,扩展名为.skeleton。包含骨骼动的数据以及相应帧动画的信息;(4) 字体资源:字体的配置信息,扩展名为.fontdef的文件,其中包括TrueType字体的引用以及其他字体配置数据;(5) GPU程序资源:在.program中对GPU程序的声明信息,与材质脚本.material文件有类似的结构,但Ogre保证所有.program文件都会在处理材质脚本之前被载入处理;(6) 纹理资源:在纹理中使用的2D图片数据。每种类型都有其自身的扩展名,比如JPG文件的.jpg或者.jpeg,Targa文件的.tga,诸如此类。2.1.3 场景管理器场景管理器完成如下功能:(1) 在场景中创建和放置活动物体、灯光以及摄像机,并维护他们的在场景图中的周游和变换;(2) 载入和布置世界地图(World geometry,与活动实体不同,世界地图是巨大且可以延伸的,通常情况下是不可移动的,比如一个完整的BSP地图);(3) 对场景查询(Scene Queries)的支持,比如回答“在世界的某个原型空间内,都包含了那些物体”;(4) 剔除不可见物体并且将可见物体放入渲染队列;(5) 根据当前和渲染物体的透视图,对无方向的光源(Nondirectional Light)进行组织和排序(按由近到远);(6) 设置并且渲染场景中的阴影;(7) 渲染场景中的其他物体,如背景和天空盒;(8) 发送组织好的内容到渲染系统执行渲染。有一点要注意:不可以直接“删除”任何有场景管理器创建返回给你的指针所指对象,当你需要释放和清空整个场景的时候,必须让相应的场景管理器自己来做。2.1.4 场景节点场景管理器用场景节点来定义场景图的结构。这些场景节点以树形的结构组织在场景管理器中:一个场景节点可以有一个父节点和任意数量的子节点。程序只渲染场景节点树上的节点,不在树上的节点不会被渲染,所以要关闭场景中的某个部分只需要把那部分的跟节点从场景树中摘除下来即可。场景节点必须通过创建它们的场景管理器来销毁。在场景管理器创建的时候,会给整个场景创建一个没有父节点的场景节点:场景的根节点(Root Scene Node),根节点用于挂接场景中需要渲染的其他节点。用户无权销毁这个节点。图2-1展示了经过几次挂接后场景图的树形结构。Ogre引擎里场景内容独立于场景节点,这样可以把场景内容从场景节点中离出来,这样的操作并不会引起场景内容的销毁或者删除。当创建一个场景节点后,场景管理器不会往上面挂接任何内容,Ogre允许没有绑定任何内容的节点存在,要显示时才创建相应的内容并挂接到需要操作的节点。单独的节点没有限制绑定的内容的数量,但不能把场景内容挂接到一个以上的场景节点,节点移动时所有绑定的内容都随着节点移动。空间操作(移动、旋转、缩放)是对场景图中的场景节点进行操作(场景内容只是挂接在它上面),换句话说,用户操作场景节点,场景内容跟随着所挂接节点一同移动、旋转和缩放。要了解与这三个操作的相关内容请参见7 89。深入了解Ogre参见10。图2-1 挂接5个场景节点的过程2.1.5 实体实体(Entity):实体是Ogre中比较神奇和复杂的概念之一。在每个实体中都包含着一些子实体(SubEntity)的实现,这些子实体是真正的可渲染对象,它们维护着具体的材质特性。而每个子实体又和一个子模型(SubMesh)对应(通常来源于3D模型工具建立的模型)。概括的来说,实体和子实体是物体渲染特性的入口,而模型(Mesh)与子模型是物体结构特性(几何体数据)的入口。实体还需要贴上纹理,这样看起来才更真实,实体的纹理贴图序列由材质脚本来制定。模型(Mesh):Ogre可以快速载入的二进制模型格式,同时也是Ogre唯一支持的模型文件格式。可以通过OgreXMLConverter工具通过命令行的方式产生这种文件,也可以在3D模型工具中通过导出插件创建。当把它放入Ogre的档案系统中的时候,要确认扩展名一定是“.mesh”,否则Ogre无法识别其类型。如果你的模型是用了变形动画或者姿态动画,就会再Mesh模型文件中同时包含这些动画的执行数据。材质脚本(Material):材质脚本文件定义了渲染几何物体所需要的状态信息。模型文件中可以直接引用材质脚本,也可以在具体代码中指定所使用的材质。这些脚本一般通过3D模型导出工具一起导出,它的扩展名是“.material”。纹理(Texture):因为Ogre使用了OpenIL图片库来实现纹理的处理,所以基本上可以支持所有目前的2D图片格式作为纹理数据。Ogre可以识别具体图片格式所专用的扩展名(比如,JPG、GIF等等)。2.2 Newton 物理引擎Newton物理引擎借助OgreNewt可以很好的与Ogre相结合以及简单易用,所以在游戏中使用这个物理引擎。Newton每帧都会调用NewtonUpdate进行更新,为完成某项功能用户只需要编写完成此功能的回调函数然后Newton提供的函数进行设置即可。2.2.1 物理引擎物理引擎通过为刚性物体赋予真实的物理属性的方式来计算运动、旋转和碰撞反映。物理引擎使用对象属性(动量、扭矩或者弹性)来模拟刚体行为可以得到更真实的效果。好的物理引擎允许有复杂的机械装置,像球形关节、轮子、气缸或者铰链,有些也支持非刚性体的物理属性,比如流体。游戏中的物体没有物理效果也可以运动,但是不能给人一种真实的感觉,例如:油桶爆炸,如果不加物理效果,只会按照游戏设计者预先设计好的脚本来爆炸,也就是说无论在什么状态下爆炸只有一种效果而且很不真实(因为脚本能产生的效果是有限的);但是加入了物理效果就不同了,爆炸所产生的碎片的运动都要遵守物理定律,不同状态下爆炸效果会不同。2.2.2 轴轴(Joint)用于限制物体的自由度,比如:手腕关节限制手掌的活动一样,在Newton物理引擎里与之对应的为“Ball and Socket”类型的轴。游戏中需要用轴来限制活动物体的自由度,Newton物理引擎提供了多种轴的API。在游戏编写过程中,为旋转Fighter实体笔者曾直接旋转场景节点,但这样作Fighter实体容易摔倒且旋转过程中会一直摇晃,给人感觉很不真是,后来改Hinge类型的轴+对场景节点施加力矩来旋转Fighter实体就很好解决了上面的问题。Hinge类型的轴如图2-2所示。图2-2 Hinge 类型的轴旋转Fighter的代码片段如下:/ 力和作用点的向量积可生成力矩 torque = force.crossProduct(p); / 给相应的 Fighter 施加力矩 fighter-setTorque(torque); / 设置 Fighter 旋转的转轴 addAngularRow (Ogre:Radian (0.0f), pin); / 设置旋转加速度 setRowAcceleration (acceleration);2.2.3 作用力回调函数实体在现实世界中受重力,摩擦力,弹力等力的影响,Newton提供了很多受力回调函数,OgreNewt已经把这些函数封装在OgreNewt:Body类中,只需要简单的调用即可,在程序中设置小车的受力代码如下:/ 设置钢体的受力回调函数 carBody-setCustomForceAndTorqueCallback(Car:forceCallback); / 车的受力回调函数 void Car:forceCallback(OgreNewt:Body *me, float timestep, int threadIndex) . me-addForce( gravity );/ 重力 . me-addForce(pushForce);/ 在车身上添加空气阻力等力 2.2.4 力矩在物理学里,力矩是一个向量,可以被想象为一个旋转力或角力,导致实体旋转运动的改变。力矩定义为(torque):力臂的向量(r)与力的向量(F)的叉积,即(公式2.1)力矩的方向由右手螺旋定则确定:以右手四指沿分力方向(X轴/Y轴),且掌心面向转轴(X轴/Y轴)而握拳,大拇指方向(Z轴)与该轴正向一致时取正号,反之则取负号11。力矩的大小为:(公式2.2)其中为向量与向量的夹角;为垂直于的向量,因为平行于的分力不起作用12。如图2-3所示,要使物体绕着某固定转轴旋转,只需对物体施加一定的力矩即可。图2-3 力矩(torque)2.2.5 刚体和碰撞体刚性实体,简称刚体,是物理引擎中最基本的实体,直觉上为可以与其他实体产生相互作用的固体。刚体具有质量,大小和形状属性。如果想让一个实体具有物理属性,那这个实体就必须是个刚体。刚体需要“碰撞体”(collision object)来定义自身形状(刚体边界不允许穿透)。碰撞体是用于确定刚体形状的假想实体,所以碰撞体可以被重复利用,例如:在游戏中需要100个一样的箱子,只需要创建一个碰撞体,然后把它分别于100个刚体关联起来。Newton提供了3种碰撞体,游戏只使用到了以下两种:(1) 规则碰撞体:包括方体,椭球体,圆柱体,圆锥体等基本形状;(2) 凸壳碰撞体:凸壳是常见的形状,根据它一系列的空间点理可以划分为多个规则的形状,一般情况下根据3D模型提供的网格进行划分。2.3 OgreNewtOgre图形渲染引擎用四元数来描述实体在场景里的方位及旋转的角位移,而Newton物理引擎用矩阵来描述,因此需要借助OgreNewt来进行不同的表示间的转换,OgreNewt在进行转换的同时还把Newton面向过程的大部分的API封装成对象以方便用户调用。2.4 设计模式本文主要用到了Singleton设计模式13。Singleton 是一个奇怪的结合体:描述十分简单,实作却非常复杂。“保证一个 class 只有一个实体 (instance),并为它提供全局访问点 (global access point)。”Singleton是一种经过改进后的全局变量,因为无法产生第二个具有Singleton型别的对象且整个工程都可以访问Singleton提供的“对象”(由getSingleton获得此对象)。这对于某些类型来说非常重要,比如游戏场景管理器,NPC管理器,系统时钟等就应该使用Singleton模式,如果这些型别可以被实例化为两个以上的实体那会造成数据不同步等危险。“提供一个全局访问点”:从客户角度来看,Singleton对象“拥有自己”。要获得Singleton的“实例”只需要条用Singleton的静态公有方法getSingleton即可。Singleton负责自身的“诞生”和“摧毁”。Singleton的优点:(1) 对唯一实例的受控访:因为Singleton类封装它的唯一实例,所以它可以严格的控制客户怎样以及何时访问它;(2) 对唯一实例的受控访:因为Singleton类封装它的唯一实例,所以它可以严格的控制客户怎样以及何时访问它;(3) 缩小名空间:Singleton模式是对全局变量的一种改进。它避免了那些存储唯一实例的全局变量污染名空间;(4) 可被继承:Singleton类可以被继承,而且拓展子类是非常容易的;(5) 允许可变数目的实例:这个模式使得你易于改变你的想法,并允许Singleton类的多个实例。此外,可以用相同的方法来控制应用所使用的实例的数目。只有允许访问Singleton实例的操作需要改变;(6) 比类操作更灵活:另一种封装单件功能的方式是使用类操作(即C+中的静态成员函数或者是Smalltalk中的类方法)。但这两种语言技术都难以改变设计以允许一个类有多个实例。第三章 游戏场景的需求分析和总体设计3.1 赛车场景3.1.1 项目需求(1) 使用3D max 软件构建出跑道和赛车组件模型;(2) 根据素材构建完整赛车,为赛车添加物理属性,并把赛车和跑道模型加载到视图场景里;(3) 程序计算赛车当前位置的跑道的信息;(4) 赛车根据赛车当前位置的跑道的信息自动做出驾驶判断,比如:当遇到左拐弯时候,赛车先判断当前速度能否通过,如果不能通过则边减速边拐弯,如果非常不幸撞到了栏杆那还得倒车然后再继续拐弯。3.1.2 总体设计根据项目需求可得赛车的总体设计图如图3-1所示。图3-1 赛车总体设计3.2 射击场景3.2.1 项目需求(1) 使用3D max 软件构建出射击场景、子弹和战斗者模型;(2) 根据素材构建战斗者,为战斗者和子弹添加物理属性,并加载所有模型到视图场景里;(3) 程序自动生成多个队伍,每个队伍有多个战斗者;(4) 每个队伍中的根据自身情况分为三种队员:血量比较少的、血量比较多的、血量处于中等的;(5) 队伍根据我方和敌方利用特定AI为队员选定攻击目标;(6) 战斗者的行走、射击、死亡等动作;(7) 战斗者死亡和子弹落地过一定时间后消失。3.2.2 总体设计根据需求分析队伍的总体设计如图3-2,战斗者的总体设计如图3-3。图3-2 队伍总体设计图3-3 战斗者的总体设计第四章 游戏场景的框架及实现4.1 游戏编程平台的搭建4.1.1 游戏开发环境的搭建因为程序使用了许多三方库,在应用程序中需要包含相应的头文件和链接库,以下为Makefile14中为应用程序添加相应的头文件和链接库文件。LIBS = OGRE OIS OgreNewt NewtonCXXFLAGS = $(shell pkg-config -cflags $(LIBS)LDFLAGS = $(shell pkg-config -libs $(LIBS) lJointLibraryshell为执行系统命令的函数,把执行操作系统命令后的输出作为返回值;命令pkg-config为执行软件安装的配置文件,-cflags和-libs为pkg-config的命令选项,$(LIBS)为pkg-config命令参数。$(shell pkg-config cflags $(LIBS)返回变量LIBS的安装文件的头文件,$(shell pkg-config libs $(LIBS)返回变量LIBS的安装文件的库文件。LIBS: 值为Ogre、OIS、OgreNewt和Newton,因为程序中用到了这四个库的库函数; CXXFLAGS: 表示LIBS包含的所有库的头文件的路径;LDFLAGS: 表示 LIBS包含的所有库的链接库的路径。4.1.2 自动编译脚本Linux下不像Windows那样有现成的IDE开发工具,一般都是用Makefile进行编译。以下为Makefile的部分代码。sources = OBJ = $(subst .cpp,.o,$(sources)all: $(OBJ)$(CXX) $(INCLUDE) $(CXXFLAGS) $(LDFLAGS) -o App $(OBJ)include $(sources:.cpp=.d)%.d: %.cppset -e; rm -f $; cc -MM -MT$(subst .cpp,$).o $ $.$; sed s,($(F*).o :*,1.o $ : ,g $; rm -f $.$ .PHONY: cleanclean:rm $(OBJ) $(subst .cpp,.d,$(sources)“%.d:%.cpp”表示所有的.d文件依赖于.cpp文件;“”表示不在屏幕上显示执行的指令;“set -e”表示将用环境变量取代Makefile中的所有变量;“$”表示模式%.d 文件,例如:对于文件 main.cpp, % 表示 main,$ 表示 main.d;“$“表示.cpp文件;默认情况下目标文件不能带有前缀,选项“-MT15”表示输入的字符即为目标文件;函数“$(subst .cpp,.o,$)“表示把 .cpp 文件的后缀名改为.o;“”表示输入输出;“$”表示四位随机数;“sed16s,($) ).o :*,1.o $ : ,g $;”表示从文件“$.$”读入文件,并把所有“filename.o:”(filename为不含后缀的文件名)替换为“filename.o filename.d :”,把结果输出到 “$”文件中。每增加一个源文件,只需要在sources里添加相应的.cpp文件即可。C+程序在编译时需要知道源文件的依赖文件,这里使用编译选项“-MM”自动生成源文件的依赖关系。上面那段代码的作用:当执行make命令时,先为每个.cpp文件生成一个.d的依赖文件,然后编译sources中的所有指定的文件生成可执行应用程序APP;当执行make clean命令时清除所有生成的.o和.d文件。4.2 实体基类设计在两个游戏场景中实体都继承自Entity抽象基类,这个类包含了实体共有的属性,具体实体类派生自这个基类并重载抽象函数实现自身需要的功能。类图如图4-1所示。图4-1 Entity类图(1) mType: Entity的派生类型标识符;(2) initAttributes(); 初始化Entity派生类属性;(3) update(Real timeStep); 负责更新Entity派生类的各种属性;timeStep为帧时间;(4) isDisappear(); 返回是否要把实体从场景里移走,即不再渲染此实体;(5) getName(); 返回实体的名字,每个实体在场景中都有唯一的名字。4.3 赛车场景设计赛车类Car继承于Entity类,类图如图4-2所示(属性和方法太多,只画了主要部分)。图4-2 赛车类图图4.2 赛车类图(1) create(CAR_CONFIG *config, Ogre:SceneManager *mgr, OgreNewt:World *world); 创建小车;config为小车的配置信息;mgr为Ogre的场景管理器;world为OgreNewt的世界场景。实现流程如图4-3所示,利用OgreNewt提供的加重力和摩擦系数给赛车添加物理属性。车身和轮胎和完整赛车如图4-4。图4-3 小车的构建(2) 小车调用void calculateCarDriveInfo(const OgreNewt:World* world, const Car* car, DriveInfo& di); 来计算道路信息,其中world为游戏场景里的世界;car为赛车本身;di为回传给赛车的道路信息,di的定义如下:struct DriveInfointbend;/* 左拐or右拐or直线 */introadCross;/* 标记速度方向与道路相交情况*/Ogre:DegreebendDegree;/* 弯道角度 */Ogre:RealbendDist;/* 车与弯道的距离 */Ogre:RealleftSideDist;/* 车与左边的距离 */Ogre:RealrightSideDist;图4-4 车的部分及整体图 4.4 车身与轮胎图4-5 左弯道赛车在180度平面内每个18度发射一条射线,由OgreNewt提供的API可获得这些射线与道路边界的交点,再根据这些交点利用几何原理计算道路信息。图4-5中的O为赛车重心点,为速度方向,为左边射线,为右边射线,为中线射线。由图知当时为左拐,当与射线有交点时赛车需要拐弯。calculateCarDriveInfo函数的工作流程如图4-6所示。(3) 小车根据calculateCarDriveInfo返回的di 调用saveDrive函数进行移动。如果道路为直线则判断当前速度是否达到最大,没有则加速直到最大;如果为弯道则根据需要拐弯的角度和每帧拐弯的度数计算出拐弯时间t,根据运动学可得通过弯道的速度公式4.1和加速度公式4.2。(公式4.1)(公式4.2)如图4-5所示,为拐过弯道时的速度,为当前速度,为车身长度,为加速度。当时小车必定撞到边界,撞到后小车先后退然后再继续拐弯;当时,小车需要减速,加速度为;当时赛车以加速过弯道。调用driveBySpeed函数来完成此功能。图4-6 计算弯道信息判断两条射线是否相交的代码如下:/* 判断平面xy上的两条射线是否相交, 并返回交点 */* 根据公式 x = (c1*b2 c2*b1)/(a1*b2 a2*b1) */* y = -(c1*a2 c2*a1) / (a1*b2 a2*b1) 进行方程求解 */bool isRayCross (const RayLine& ray1, const RayLine& ray2, Ogre:Real& x, Ogre:Real& y)Ogre:Real denominator = ray2.lineDir.y * ray1.lineDir.x - ray2.lineDir.x * ray1.lineDir.y;if (denominator -0.005) /* 两条射线平行*/return true;Ogre:Real rhs1 = ray1.y * ray1.lineDir.x - ray1.x * ray1.lineDir.y;Ogre:Real rhs2 = ray2.y * ray2.lineDir.x - ray2.x * ray2.lineDir.y;Ogre:Real xx0 = rhs1 * ray2.lineDir.x - rhs2 * ray1.lineDir.x;Ogre:Real yy0 = rhs1 * ray2.lineDir.y - rhs2 * ray2.lineDir.y;Ogre:Real xx = xx0 / denominator;Ogre:Real yy = yy0 / denominator;Ogre:Vector2 v1(xx - ray1.x, yy - ray1.y);Ogre:Vector2 v2(xx - ray2.x, yy - ray2.y);/* 判断解是否在有效范围内 */if (v1.dotProduct(ray1.lineDir) = 0 & v2.dotProduct(ray2.lineDir) = 0)x = xx; y = yy;return false;return true;赛车过左弯道的效果图如图4-7所示。图4-7 赛车过左弯道4.4 射击场景设计4.4.1 实体容器类设计设计游戏场景产生很多的实体,程序无法做到单独控制每个实体,需要容器类来容纳大量实体。容器类需要具备以下功能:(1) 没有数量限制(除非内存不足)的容纳实体;(2) 能根据实体名字进行增删改查;(3) 能遍历本身所能容纳的实体;(4) 对所有的实体执行某一动作。STL库中的map和hash_map都是把Key和Value关联起来,然后根据Key可以快速查找到相应的Value,但它们有本质上的区别17:(1) 底层实现不同,hash_map使用hashtable来实现,而map用RB-tree,这导致了它们的插入查找删除的复杂度的不同,其中hash_map为O(maxlen)(maxlen为存贮元素的Key的hash值相同的最大数目),map为O(logn)(n为存贮元素的个数);(2) hash_map根据Key的hash值来确定存贮位置,而map根据Key的大小。因为程序存贮的实体不需要排序功能,所以选择hash_map做为实体容器的底层实现以提高程序效率。图4-8 队伍类图4.4.2 队伍类设计因为队伍需要对队员进行增删改查更新等操作,而它也是一个Entity类,所以Team继承于Entity和EntityHashMap,增删改查等操作调用EntityHashMap实现即可。队伍类设计如图4-8所示。(1) int runByHP(int hp); 遍历所有的队员,把血量 hp 的队员调离战场,返回值为调离战场的队员数;(2) int getMinHPFighters(int count,vector&fighterVec);遍历所有的队员,选出血量最少的count人存入fighterVec返回给程序。返回值为实际选出了多少个队员;(3) int getMaxHPFighters(int count,vector&fighterVec);同getMinHPFighters;(4) int getRandomFighters(int count,vector&fighterVec);随机选择count个队员存入fighterVec返回给程序。返回值为实际选出了多少个队员。4.4.3 特殊单件模式类/ MySingleton.cpp template class MySingleton protected: struct object_creator object_creator() MySingleton:getSingleton(); ; static object_creator create_object; MySingleton() MySingleton(const MySingleton&); public: typedef T object_type; static object_type& getSingleton() static object_type obj; return obj; ; / object_creator 是一个嵌套从属名称,需要使用 typename 告诉编译器这个名称是个类型 template typ
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 福建电商营销方案设计
- 珍珠奶茶的营销方案策划
- 减肥水果营销策划方案
- 钢筋工程质量管理
- 酒店网站建设方案咨询
- 咨询方案的总结
- 钢箱梁施工方案整改
- 建筑方案设计资源包括哪些
- 跑步健身活动方案策划
- 人工智能技术与AIGC应用 课件全套 第1-8章 认识人工智能 - AIGC 的发展与展望
- 《新课程标准解读》课件
- 2025年高校教师资格证考试题库(带答案能力提升)
- 【高分复习笔记】高廷耀《水污染控制工程》(第4版)(上册)笔记和课后习题(含考研真题)详解
- 福建福州地铁集团有限公司招聘笔试冲刺题2025
- 减重代谢护理案例分享
- 给水排水管道工程施工质量评定表
- 高职数学课件 1.1函数
- 自建房屋地基施工合同
- GB/T 5526-2024动植物油脂相对密度的测定
- 北师大版 五年级上册数学 预习单
- 精神科意外事件防-噎食
评论
0/150
提交评论