发现cocos2dx chipmunkk物理引擎的一个BUG,请问如何切合BOX2D引擎

作者/ 冯立鹏
毕业于吉林大学计算机学院。早期从事企业级应该开发。曾在华为任系统软件开发工程师,在IBM任高级系统工程师及开发经理。在移动互联网大潮来袭之际,专注于iOS以及Android两大主流移动平台上的2D游戏开发。现就职于安卓越科技(北京)有限公司,已带领团队开发出多款畅销iOS及Android平台移动游戏,在App Store和Google Play 市场均取得不俗成绩。冯立鹏长期使用Cocos2d-x引擎研发跨平台游戏产品,对此引擎的基础知识、高级特性、性能优化,以及底层实现原理都有着深刻的认知和理解。
Cocos2d-x 内置的物理引擎是很多智能手机平台休闲创意游戏的技术来源。最为知名的“愤怒的小鸟”就是建立在2D物理引擎之上的物理模拟游戏,它充分使用了物体的碰撞,破碎,爆破等物理过程,创新了游戏的玩法。我们在学习并掌握了物理引擎的使用、物理世界各种现象的模拟方法之后,也可以利用各种物理模拟算法来丰富我们的游戏玩法,创造出更加逼真、动态丰富的游戏世界。
Cocos2d-x 引擎内置了两种物理引擎,它们分别是 Box2D 和 Chipmunk,都是非常优秀的 2D 物理引擎,而且 x 引擎将它们都内置在 SDK 中。Box2D是基于C++语言的,而Chipmunk 是基于 C 语言的)。在网络上还能找到非常多Box2D的学习内容作为本文的扩展和补充。限于篇幅原因,本文所涉及到的 Box2D物理引擎的知识内容都是最为基本的基础知识,要想做出复杂的物理模拟游戏,你还需要深入研究Box2D引擎, 我推荐你在网上找到《Box2D用户手册》来做深入学习。
Box2D物理引擎简介
在这部分当中我们会简单介绍一下什么是物理引擎,它都包括了哪些具体的物理学内容,然后会重点介绍一下当前最热门最流行的 2D物理引擎——Box2D。
物理引擎的基本概念
在我们生活的环境中,每时每刻都在发生着数不清的物理现象,游戏通常都是对现实世界的抽象和模拟,所以在构建游戏世界时也会涉及一些常见的物理现象。游戏世界中物理现象的多少与游戏的复杂度有关,要想更逼真地模拟现实世界,就要考虑模拟更多的物理现象。但游戏世界始终具有局限性,不能完全地模拟现实世界,否则,人类也将无法分清游戏与现实了。对于移动平台的2D游戏,需要模拟的物理效果并不多,通常需要模拟的内容如下。
重力:在游戏中模拟重力加速度,当游戏中人物跳跃起来后会受到重力影响而向下移动,在没有地面的场景,人物和物体会由于重力而做自由落体运动。
牵引力(动力):在游戏中比如汽车的引擎,人物本身能够提供向前行进的动力,这种牵引力是持续不断地作用在物体上的,物体因此可以向作用力的方向移动。
摩擦力:物体在地面等接触面上移动时,会受到摩擦力的影响,它可以使正在运动的物体由于摩擦力的作用而停下来。
冲击力:比如爆炸会产生一次性的冲击力,会对爆炸范围内的物体产生一瞬间的力的作用,使其运动起来。
碰撞检测:当一个物体与另一个物体碰撞后,两个物体会因为碰撞发生作用力与反作用力,会让其之前的运动受到影响。
还有浮力、关节链接等等物理概念。
在计算机业内很早就诞生了物理引擎这项技术,早期物理引擎普遍都是用于工业设计和生产,比如汽车制造业、桥梁和建筑业等等。后来随着游戏业的兴起,渐渐被适用于游戏当中,用来模拟各种物理现象,让游戏显得更加逼真。发展到现在,已经有多款专业级的 3D物理引擎被广泛应用于大型 3D游戏当中,而小巧灵活的 2D游戏,通常都使用轻量级的 2D物理引擎。2D 物理引擎只工作在二维平面范围内,根据物理世界中的内容,模拟这些物理现象作用后的结果。
在游戏开发过程来看,物理引擎可以被看做是游戏物体的动画系统。游戏中的物体在物理引擎中被称为刚体——“Rigid Bodies”。之所以称之为刚体是因为物理引擎在驱动这些物体生成动画时,是把它们当做是硬的,不会发生形变的物体。将物体这样抽象简化以后,物理引擎就可以同时计算大量的刚体了。通过对物理世界中的大量刚体做重力、牵引力、摩擦力、冲击力、碰撞检测等物理模拟运算,就可以得出在各种力的作用下物体不断变化的位置、方向,进而可以模拟出游戏物体的动态效果。
物理引擎在使用时也有一些局限性。它们必须在模拟效果时使用一些捷径,也就是说简化物体的复杂性,因为真实世界过于复杂,放到物理引擎中模拟计算将耗费大量的硬件资源。在某些极端的情况下,物理引擎可能会捕捉不到发生的碰撞:例如,一个物体在超高速移动,由于计算移动位移需要使用更新时间作为参数,在物理引擎中它就可能会穿过另一个物体,这在现实中是不合理的。我们在使用物理引擎时,会介绍一些注意事项,避免此类情况的发生。
Box2D是由C++开发的,它是一款轻量级的二维刚体仿真库,主要用于编写 2D游戏。
程序员可以使用它,让游戏中的物体运动起来更真实,让游戏世界更具交互性。就像上面所说的,以游戏的角度来看, Box2D物理引擎是一个程序性动画系统。做动画常有两种方法,一种是预先准备好动画所需的图像数据,比如某种格式的 2D图片,再一帧一帧地播放。另一种是以一定方法,动态计算出动画所需的数据,比如移动后的新位置、旋转的角度等等,根据这些数据再进行绘图。从这种角度看,预先准备的,可称为数据性动画,动态计算的可称为程序性动画。Box2D就是用物理学的方法,推导出游戏世界物体的位置、角度等数据。
而 Box2D 也仅仅是推导出数据,至于得到数据之后怎么处理就是程序员自己的事情了。比如在台球游戏中,每个球都是一个圆形的刚体,当两个球发生碰撞后会有各自的运动轨迹,此时物理引擎可以给出球碰撞后每一帧的坐标位置,这时程序员就必须要根据物理引擎给出的坐标,更新台球精灵的位置,这样游戏中玩家就会看到台球碰撞后的运动轨迹。
Cocos2d-x 将 Box2D 作为内置的物理引擎集成在自身当中,在 Box2D 引擎强大的物理模拟功能支持下,使用 Cocos2d-x 可以轻松地开发出物理模拟游戏。这里我们再说一下所谓的物理模拟游戏,在各式各样的游戏类型当中,都多多少少会对真实的世界进行模拟。比如大多数平台跳跃游戏都要对重力进行模拟,做自由落体运算;射击游戏出现爆炸效果时会模拟冲击力,让敌人飞出去;而有一类游戏,它们会对游戏的内容进行大量的物理特性模拟,尽量向真实世界靠拢。比如休闲游戏《蜡笔物理学》就属于此类游戏,在这款游戏中构建的物体都会受到重力、碰撞、作用力与反作用力、摩擦力等物理现象的影响。还有本文开头我们提到的《愤怒的小鸟》,它也是支持大量的物理模拟效果才使得游戏性得以提升,吸引了大量的玩家用户。
下面我们来介绍一下 Box2D 涉及的核心概念,Box2D 中有一些基本对象,都是使用物理引擎时要经常用到的,这里我们先做一个简要的介绍。
物理世界 world:一个物理世界就是各种刚体 bodies、夹具 fixtures、约束 constraints等物理引擎中基本对象相互作用的集合。所有的物理对象都是在物理世界已经建立好的基础上,在物理世界中生成的。物理世界具有一个范围,在2D坐标系中,物理世界的范围就是一个矩形区域,区域内的物理对象可以相互作用,发生物理碰撞等影响,一旦物理对象到了区域之外,将不再进行物理运算,不再产生任何物理作用。Box2D 支持创建多个世界,但这通常没有必要。物理世界是 Box2D 引擎最为重要的对象,游戏必须要持有物理世界对象,这样才能访问物理世界中的各种对象知道它们的状态,然后将这些状态更新到游戏界面中,反应出各种模拟的物理现象。
刚体 rigid body:大多数游戏对象在物理世界中都被抽象成为刚体对象,它是物理世界中十分坚硬的物质,物理引擎假定刚体都是不会发生形变的,它上面任意两点之间的距离都保持不变。在 Box2D物理引擎中,b2Body类就是代表刚体的类型。在设计实现物理游戏时,刚体通常都对应着游戏中的一个具有具体外形的角色,比如台球游戏中的一颗台球,它在物理世界中就会使用一个圆形的刚体来代表。刚体在 Box2D 中主要分为两大类,一类是可以移动位置或者旋转的动态刚体,这种刚体通常用于表示游戏中的活动物体;另一类是位置无法移动和旋转的静态刚体,这种刚体通常用于表示游戏中的地面平台等静物。
夹具 fixture:每个刚体都需要定义一个或者多个夹具,夹具是一个属性容器,它具有形状属性 shape、密度属性 density、摩擦属性 friction 和恢复属性 restitution。当一个刚体具有了夹具之后,它就可以参与物理世界的碰撞检测、摩擦力运算和弹力运算了。一个外形简单的刚体,例如台球定义一个具有圆形外形的夹具就足够了,因为夹具中的形状属性可以定义为圆形,这与台球的圆形外形非常符合。而在要求高度仿真的情况下,一个外形复杂的物体比如一辆汽车如果看做是一个刚体,它就需要拥有多个夹具,比如有一个多边形夹具代表汽车的身体,前轮和后轮各自都是圆形的夹具。如下图,蓝色框代表夹具的形状,大家可以充分理解一个刚体具有多个夹具的情况(也可以说一个刚体由一个或者多个夹具组成):
形状 shape:2D 几何外形对象,比如圆形 circle 或多边形 polygon。形状定义好之后会被附加到某个夹具之上,作为夹具的外形属性存在,它是夹具的重要组成部分,夹具在刚体碰撞运算时会通过形状来进行检测。形状类中保存的主要是形状的几何数据信息,比如一个圆形 circle 主要是保存它的半径信息,只要知道了半径就能知道圆形的具体大小;另一个比较常用的形状是四边形 rect,它主要记录的是四边形的宽度和高度信息。
关节 joint:关节就是种约束,用于将两个或多个刚体固定到一起。Box2D 支持不同的关节类型——转动 revolute、棱柱 prismatic、距离 distance 等。比如卡通人物的手臂运动,就可以定义一个和人类一样的肘关节,关节两端是上臂和前臂两个刚体。一些关节可以有限制 limits 和马达 motors。
关节限制 joint limit:关节限制限定了一个关节的运动范围。例如人类的胳膊肘只能在某一角度范围内运动。
关节马达 joint motor:根据关节的自由度,关节马达可以驱动关节所连接的物体。例如,你可以使用一个马达来驱动一个肘的旋转。
这些物理引擎中的概念在第一次看时可能会让人感觉非常抽象,仅仅从字面上来看是比较难于理解和掌握的。所以本文会以实例和代码的形式,向大家介绍 Box2D 物理引擎在游戏中的引入、使用和清理工作,使用 Box2D 实现各种物理对象,模拟出丰富的物理世界,让大家掌握各种物理对象的使用方法。
在游戏中引入Box2D物理世界
我们先来简要地介绍一下使用 x 引擎建立物理世界,并在物理世界中建立一个刚体(最基本的物体)的过程,这部分知识是将 Box2D 物理引擎引入游戏当中最为基本的步骤,充分理解这部分代码及功能之后,您就能够掌握 Box2D 物理引擎的入门知识了,在引入了最基本的物理世界之后,我们还会陆续介绍重力的实现以及碰撞检测在 x 引擎中的处理方法。
首先是物理世界的建立,因为 x 引擎内置了 Box2D 物理引擎,所以需要使用物理引擎的地方只要引入“Box2D/Box2D.h”头文件即可,以下代码就是建立物理世界,也就是初始化 Box2D 物理引擎的过程,这个过程通常都是放在游戏场景初始化阶段,把物理世界对象作为游戏世界的一部分完成初始化过程:
// 定义重力加速
// 设定垂直方向的加速度,这里采用真实的物理数据
gravity.Set(0.0f, -9.8f);
// 使用刚刚定义好的加速度生成物理世界对象,这样世界中的所有对象都会受到重力加速度的影响
b2World* phyWorld = new b2World(gravity);
// 物理世界的对象都参与碰撞检测,无休眠对象
phyWorld-&SetAllowSleeping(false);
//连续碰撞检测,避免发生物体穿过另一个物体的事件
phyWorld-&SetContinuousPhysics(true);
// 设置碰撞监听器
phyWorld-&SetContactListener(listener);
通过以上代码,我们就在 x 引擎当中建立了一个物理世界,以上代码的最后一步用于设置物理世界中各种物体碰撞的监听器对象——listener,它是b2ContactListener类型。这里我们能够发现,所有 Box2D 的类定义都是以 b2 开头,这表示它是 Box2D 引擎中的类。在物理引擎捕捉到世界中的物体对象发生碰撞后,会使用碰撞监听器 b2ContactListener的回调方法,来实现碰撞的发现和响应功能,我们在 x引擎中要做的,就是定义好一个碰撞检测器,实现它的碰撞回调函数,有以下函数需要实现。
virtual void BeginContact(b2Contact* contact):碰撞发生开始时的回调函数,一般简单的碰撞检测使用;
virtual void EndContact(b2Contact* contact):碰撞发生后的回调函数,一般简单的碰撞检测使用;
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold):碰撞求解前的回调函数,求解就是指计算碰撞产生的冲击力,需要计算碰撞冲击力造成的破坏等效果时,需要使用此回调函数;
virtual void PostSolve(const b2Contact* contact, const b2ContactImpulse* impulse):碰撞求解后的回调函数,需要计算碰撞冲击力造成的破坏等效果时,需要使用此回调函数。
这四个回调方法中,前两个功能有限但使用起来简单,后两个提供的信息量大,但使用起来比较复杂,这个要根据游戏的具体要求而定,如果我们的游戏过程对物理模拟要求不高,仅仅是实现碰撞检测功能,那么我们主要使用 BeginContact(b2Contact* contact)这个回调函数就足够了,如果我们要处理碰撞之前和碰撞之后的效果,根据碰撞中产生的相互作用力来计算物体碰撞后的移动,则我们必须好好利用全部这四个函数,它们联合作用起来,可以模拟出比较真实而复杂的物理碰撞效果。
在游戏初始化时引入 Box2D 物理世界,然后实现碰撞回调函数之后,我们的物理世界初始化工作就完成了,剩下的工作是根据游戏的要求,预先生成或者在游戏过程中动态生成各种物理对象,比如刚体对象。在下面我们就会生成一个刚体对象,为刚体对象定义各种属性,用它来模拟游戏中的某个有形状的物体,并且让这个物体在物理世界中受重力的影响,能够做自由落体运动。
定义物体对象,实现重力效果
为了展示 Box2D引擎中的物理效果,接下来我们需要在物理世界中定义刚体 Body了。在物理模拟游戏当中,一般都会有大量的刚体存在于这个物理世界内。有时候这些刚体是在游戏初始化时建立的,它们有位置、密度、体积等预制好的属性;而另一种情况是根据游戏过程实时动态地生成刚体,并为刚体设置位置等属性。Box2D 是一个高效的物理引擎,所以实时动态生成刚体的速度非常快,只要数量不是非常巨大,就不会影响到游戏的运行速度。刚体通常都会对应这个游戏中的某个角色或者是角色的一部分,比如在飞行射击游戏中,飞机的身体就可以用一个刚体或者多个刚体的组合来代表,刚体就是游戏角色在物理世界的抽象,刚体碰撞的物理变化最终还要反馈到游戏中的角色身上。
下面我们就使用代码来定义一个刚体:
// 首先生成b2BodyDef这个结构体的实例
b2BodyDef spriteBodyD
// 指定刚体定义的类型是动态刚体,表明刚体是可以在物理世界中移动的
spriteBodyDef.type = b2_dynamicB
// 设置刚体定义的初始位置
spriteBodyDef.position.Set(5.0f,5.0f);
// 接下来使用spriteBodyDef对象来生成真正的刚体Body
b2Body* spriteBody = phyWorld-&CreateBody(&spriteBodyDef);
// 生成一个矩形形状,定义大小范围
b2PolygonShape spriteS
spriteShape.SetAsBox( 10.0f, 10.0f);
// 接下来生成刚体Body将要使用的夹具对象
b2FixtureDef spriteShapeD
// 指定夹具的外形就是刚刚生成的矩形
spriteShapeDef.shape = &spriteS
// 设定其物理密度
spriteShapeDef.density = 10.0f;
// 指定自己所属的碰撞组
spriteShapeDef.filter.categoryBits = 0x0010;// 第2组
// 指定自己会与那个组发生碰撞
spriteShapeDef.filter.maskBits = 0x0001;// 与第1组碰撞
// 使用定义好的夹具生成刚体Body
spriteBody-&CreateFixture(&spriteShapeDef);
此时,物理世界中就已经具有了一个刚体对象。这里我们要强调的是刚体的夹具定义时的碰撞分组信息,其中filter.categoryBits把刚体的夹具定义在第2组, 接下来的filter.maskBits定义为第1组;这样此刚体的夹具就会与处于第 1 组的刚体夹具发生碰撞,而其他组或者位于同一组的刚体夹具,即使有了接触也不会发生碰撞事件,这是 Box2D 物理引擎的碰撞分组筛选功能。这在游戏当中非常有用,比如大家都熟悉的坦克大战,敌人和敌人之间,敌人的子弹与敌人的身体,都是没有碰撞检测的,而大家看到的现象就是敌人 A 的子弹可以穿过敌人 B 的身体,敌人 A本身也可以穿过敌人 B 的身体。
定义好这个刚体之后,在没有设置它的位置时,它会默认出现在物理世界的原点,也就是坐标(0,0)的点。还记得初始化物理世界的代码吗,其中前两行对重力加速度进行了设置,并且在 Y 轴方向设置为-9.8,这就是符合我们现实世界的物理特性,物体的重力加速度为 9.8,方向为向下。这样刚体就会在物理世界中受重力影响,做自由落体运动。以上代码段的效果可以参考 Testcpp 例子项目中的 Box2DtestBed 子项目,如图2,屏幕中心不断地生成新的物体(刚体),每个物体就像现实中的重物一样,垂直向下做自由落体运动:
在上面的例子当中,大量的刚体之间,以及刚体与正方形边框之间都可以发生碰撞,下面我们将重点讲述一下刚体之间的碰撞,以及如何利用碰撞检测来实现游戏角色之间碰撞的判定和响应处理。
Box2D引擎的一些注意事项
在使用 Cocos2d-x 引擎制作基于 Box2D 的物理游戏时,除了基本的 Box2D 物理引擎使用知识以外,我们还需要强调一些注意事项,这些注意事项都将有助于你充分使用 Box2D,大大提高调试和开发的工作效率。
Box2D调试渲染
开发基于 Box2D 的物理模拟游戏,有很多模拟过程和结果都是我们无法预料的,比如愤怒的小鸟,每个关卡的平台搭建都需要经过大量的物理模拟测试,才能构建出合理的关卡。如果这种测试过程不可见,那对于程序调试人员来说,测试工作无疑是个噩梦。
在整个测试过程中,所有的刚体外形都应该是可见的,这样我们才能观测出各种物理碰撞等现象的详细过程和结果,这就需要我们引入 GLESDebugDraw类。它是使用 OpenGLES底层绘图方法,将刚体的外形准确绘制到屏幕上的功能类。GLESDebugDraw 类位于Cocos2d-x SDK 的 GLES-Render.cpp 和 GLES-Render.h 文件中,所以如果游戏需要使用到Box2D物理引擎并且需要调试,就要将这两个类也拷贝到游戏的类文件目录下并引用这两个文件。在这两个文件中还定义了 b2Draw 类,它提供了大多数关于绘制几何图形的抽象方法。
怎样才能在显示游戏图层时也绘制物理世界的内容呢。首先要将 GLESDebugDraw类型的对象设置到物理世界对象上,然后确认有哪些内容需要被绘制,可以绘制的内容包括刚体的外形、质心、关节、AABB 包围盒(也就是能够包围刚体的矩形包围盒)等内容:
debugDraw = new GLESDebugDraw(PTM_RATIO);
// 这里新建一个 debug 渲染模块
world-&SetDebugDraw(debugDraw);
uint32 flags = 0;
flags += b2Draw::e_shapeB
flags += b2Draw::e_aabbB //AABB块
flags += b2Draw::e_centerOfMassB //物体质心
flags += b2Draw::e_jointB //关节
flags += b2Draw::e_shapeB
debugDraw-&SetFlags(flags);
//需要显示那些东西
在设置之后,调用 Cocos2d-x 图层的 draw 函数,将其绘制出来。随后在每一帧中,图层的 draw 函数都会被自动调用,我们在此设置 OpenGL 的绘制设定,并将物理世界中的对象绘制到屏幕上:
void BoxLayer::draw()
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
world-&DrawDebugData();
//这个一定要写
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
这样我们就能够在游戏屏幕上看到物理世界中的对象以简单的线条形式绘制到屏幕中。Cocos2d-x TestCpp项目中的Box2DtestBed子项目,就是使用了GLESDebugDraw类将Box2D物理引擎中的内容都变为可见形式的。
Box2D速度与性能注意事项
物理引擎实际上是比较占用硬件资源的,因为引擎中大量的刚体碰撞检测,各种作用力的效果计算都非常耗费 CPU 运算时间。尤其是当刚体数量大量增长时,Box2D 的计算量将成几何级的增长。所以使用 Box2D 物理引擎时,一定要注意性能优化以及提高仿真度的几个技巧。
区分静态刚体和动态刚体:如果有个物体可以使用静态刚体来定义,那就一定不要使用动态刚体来定义它。因为静态刚体仅仅进行碰撞检测,不会考虑作用力对它的影响,相对于动态刚体来说,静态刚体的计算量会小很多,可以减少 CPU 的负担。
启动动态刚体休眠属性:在物理引擎初始化时,可以通过设置是否允许动态刚体休眠来改善性能。如果设置允许动态刚体休眠,一些受到很小作用力或者没有受到作用力的刚体,它们会保持静止不动的状态,此时它们会进入休眠 Sleep状态,进入Sleep 状态的刚体,将不会进行物理运算,这样就可以减少运算时间,直到它们再次受到作用力处于运动状态后,才会从休眠状态被唤醒,继续参与物理计算。
设置单位转换参数:游戏屏幕是以像素为单位长度的,而物理引擎是以米为单位长度的,这里就存在一个米与像素的单位换算关系。物理引擎有一个合理的单位工作范围,在 Box2D 中,物体的大小最好在 0.1 米到 10 米之间,如果超过这个范围,物体的表现可能会变得不真实。所以设计游戏中的物体大小时,其像素单位也需要有一个合理的范围。我们通常将换算值设置为 32,这样在游戏中 32 像素大小的物体,在物理引擎中它就是 1 米大小,在这样一个合理的大小范围内, Box2D引擎的模拟效果会比较真实。
设置子弹属性:动态刚体有时会高速移动,如果刚体在两帧之间移动的距离超过了碰撞物体的身长,那碰撞检测就失去了检测功能,出现刚体直接穿过障碍物的现象。所以如果某个刚体的运动速度很快时,需要设置此刚体为子弹类型,也就是高速移动的动态刚体类型,使用 SetBullet(ture)函数。这样的刚体在移动时会计算每一个单位的移动是否发生碰撞,不会发生直接穿过障碍物的现象。
注意这些使用技巧以后,我们的 Box2D 引擎将会更快速更真实更准确地模拟各种物理效果。
复杂多边形的代码生成工具
之前我们讲解的 Box2D 中的刚体,都是比较简单的形状(都是使用的最基本的矩形外形),所以在使用代码来定义时也比较简单。当游戏物体的形状变得丰富而复杂时,手动书写代码来定义物体外形是不现实的,这时我们就要借助于一些有效的工具来定义物体的外形,也就是多边形的顶点信息。这里我们推荐一款叫做 vertexhelper 的软件,这是一款开源免费的顶点绘制工具,其界面如下,通过可视化的界面可以绘制出任意一种你想要的多边形。而组成这些多边形的顶点数据,将会以 C++代码的形式给出,经过拷贝粘贴,就可以将复杂的多边形生成代码放到你自己的类中。可以说 vertexhelper是一款强大的代码自动生成工具。
如上图中定义好了两个多边形之后,我们可以在文本区直接得到 C++代码,使用这些顶点信息,我们就可以在 Box2D中生成相应的多边形。以下是 vertexhelper 自动生成的顶点信息代码:
[cpp] view plaincopyprint?
//row 1, col 1
int num = 6;
b2Vec2 verts[] = {
b2Vec2(-30.4f / PTM_RATIO, 14.6f / PTM_RATIO),
b2Vec2(-30.6f / PTM_RATIO, -3.6f / PTM_RATIO),
b2Vec2(-23.7f / PTM_RATIO, -14.6f / PTM_RATIO),
b2Vec2(-14.7f / PTM_RATIO, -14.6f / PTM_RATIO),
b2Vec2(-6.5f / PTM_RATIO, -3.8f / PTM_RATIO),
b2Vec2(-6.5f / PTM_RATIO, 14.4f / PTM_RATIO)
[cpp] view plaincopyprint?
//row 2, col 1
int num = 7;
b2Vec2 verts[] = {
b2Vec2(-28.7f / PTM_RATIO, 10.9f / PTM_RATIO),
b2Vec2(-28.9f / PTM_RATIO, -5.4f / PTM_RATIO),
b2Vec2(-23.5f / PTM_RATIO, -10.6f / PTM_RATIO),
b2Vec2(-0.6f / PTM_RATIO, -10.7f / PTM_RATIO),
b2Vec2(4.4f / PTM_RATIO, -6.6f / PTM_RATIO),
b2Vec2(3.5f / PTM_RATIO, 2.5f / PTM_RATIO),
b2Vec2(-5.2f / PTM_RATIO, 10.5f / PTM_RATIO)
有了这样一款工具,我们就可以从大量复杂的多边形定义工作中解放出来了。
本文我们对 Cocos2d-x 内置的两款物理引擎做了简要介绍,并以 Box2D 为重点学习对象,讲解了物理引擎在游戏中的使用方法。通过本文的介绍,我们掌握了大量的物理引擎使用知识,如果读者对物理模拟游戏感兴趣,现在就可以实现你自己的物理模拟游戏了。
从零开始,循序渐进地讲解了如何使用Cocos2d-x引擎开发移动平台游戏。全面、基础并非常具有实战性。由国内资深一线开发工程师撰写。书中系统地讲解了Cocos2d-x引擎的基本功能、使用方法、高级特性、开发技巧及性能优化,在此基础上本书还提供了一个完整的游戏开发实践过程,详细讲解了此游戏从策划到投放市场创造利润的整个流程。本文节选自。
本文目前还没有评论……游戏之物理引擎(BOX2D/Chipmunk)的比较_SandKing沙王_新浪博客
游戏之物理引擎(BOX2D/Chipmunk)的比较
cocos2d自带了两种物理引擎:Box2d和Chipmunk,这两种引擎都是2D游戏设计,可以个、和cocos2d完美结合。举个例子Angry
Birds就是很好的结合了物理引擎创造出更加动态和逼真的游戏世界。物理引擎中存在两种刚体:动态移动(dynamic)和静态(static)的刚体。因此顾名思义静态刚体是不会移动的,不像动态的,它会它们会互相碰撞,也会和静态刚体发生碰撞。动态的参数有位置position旋转rotaion,还有密度density,质量mass(用来衡量刚体有多重)摩擦力fiction(用于定义刚体在平面上移动时遇到的阻力的大小或者有多滑),复原restitution(用于定义刚体的弹性)有了这些刚体间的碰撞,挤压等一系列的动作后,我们在使用关节joints把多个刚体连接起来,这样可以有效的控制关节的活动了。当然物理引擎也不是完美的,也是有漏洞的,它是通过和游戏结合产生这些和现实生活相似的环境,不能做到百分百和生活中的一样。物理引擎比较:Box2d/Chipmunk对于这两种的编程语言有所不同,Box2d是用C++来写的,而Chipmunk是通过C来写的。喜欢用Box2d的朋友,比较倾向于使用C++的接口,可以很好的与面向对象的objec-c进行整合。这两种的差别也在于它们的功能也有所不同,Box2d有的,Chipmunk没有,比如Box2d可以很好的解决子弹穿透wu物体而不用进行碰撞检测的问题。Box2d一般都把活动范围限制在屏幕之内,当然其中的坐标也需要转换,位置呀,坐标的一般都是开发者头疼的事情,因为游戏开发出来,需要不断的修改坐标和位置,这些都需要一些测试人员调试过以适合大众,才决定修改。Box2d有一个名为b2ContactListener的类,它是碰撞检测的回调。chipmunk有一个很受欢迎的object-c的接口,是SpaceManager。你也可以利用SpaceManager直接将精灵添加到刚体上,添加调试的绘图等。对我个人而言比较喜欢chipmunk因为我不太喜欢C++,对于Box2d目前的资料也不是很多,chipmunk比较多一点,不过box2d也在慢慢赶上来,发展的也很快,chipmunk也有缺陷,有些域不可以改变他们,只被使用在内部。
SandKing沙王
博客等级:
博客积分:0
博客访问:1,668
关注人气:0
荣誉徽章:

我要回帖

更多关于 box2d物理引擎 的文章

 

随机推荐