十一 08

游戏开发实战之弹球游戏

作者: baiyuzhong 分类:图书推荐   阅读:14,044 次 添加评论

文/Steffen Itterheim、Andreas Löw

为了更好地使用Box2D物理引擎,本文我们将制作一个真实的弹球游戏。弹球游戏桌利用各种物理世界的效果来创造有趣的体验。然而,在使用物理引擎时,并不局限于真实世界中的物理定律。 通过设定合适的摩擦力、弹性和密度参数,可以创建出弹球游戏中的一些元素,如反弹器(bumper)和球(ball)。其他的元素则需要使用关节(joint):挡板(flipper)需要转动关节(revolute joint),发射器(plunger)需要移动关节(prismatic joint)。当然还需要一些静态图形来定义弹球桌上的碰撞多边形。

由于用代码来定义碰撞多边形是不切实际的,至少对于一个逼真的弹球游戏所需的复杂度来说是这样,因此下面介绍另一个非常有用的工具—— PhysicsEditor。依靠这个工具,只须画出一个个顶点就可以创建碰撞多边形。更快的做法是单击一次鼠标,让PhysicsEditor跟踪形状的轮廓。

图1 弹球游戏

图形:凸多边形和逆时针方式

我们先从碰撞多边形的要求说起。首先需要知道的是,在Box2D和Chipmunk物理引擎中定义碰撞多边形时,需要遵循以下两条原则:

● 逆时针定义各个顶点

● 多边形必须是凸多边形

凸多边形是指图形上任意两点的连线都在图形内部。这和凹多边形正好相反,凹多边形中两点的连线可以不完全包含在图形内部。图2将有助于你理解凸多边形和凹多边形的区别。

图2 凸多边形和凹多边形

可以在心中画一下,就能明白如何按逆时针方向定义凸多边形的顶点。首先在任意位置放置一个顶点,然后在它的左边放置另一个顶点,接着是下面,最后再回到右面。这样就用逆时针方式绘制了一个长方形。或者也可以先放置一个顶点,然后在右边、上面、左边绘制其他3个顶点,这样就绘制出一个以逆时针方式定义的图形。在哪里绘制第一个顶点并不重要,重要的是顶点要沿逆时针方向绘制。

好消息是,在使用PhysicsEditor时,你不需要关心多边形的顶点顺序(方向),或者多边形是凸多边形还是凹多边形。PhysicsEditor会自动处理这些问题。它把凹多边形分割为一个或更多个凸多边形。然后,PhysicsEditor自带的物理对象加载器会把所有图形分配给单个Box2D刚体。应该尽力避免分割图形,以便使每个刚体的碰撞形状最少,从而获得最佳的性能。

提示:

如何才能知道是否错误地创建了一个顺时针图形或凹多边形?每个物理引擎的反应都不一样。有些会事先抛出错误来告知。但是在Box2D中,如果一个移动的刚体碰到上述错误的多边形,这个刚体会在接近那个多边形的时候停下来。如果在Box2D游戏中碰到类似的情况,请检查一下周围的碰撞多边形。

使用PhysicsEditor

知道了如何定义碰撞多边形,现在是时候来学习PhysicsEditor工具了。该工具可从www. physicseditor.de下载。下载完成后,打开PhysicsEditor磁盘镜像,并把PhysicsEditor.app拖动到应用程序的文件夹中,就可以运行PhysicsEditor(见图3)。在PhysicsEditor磁盘镜像中,可以找到一个名为Loaders的文件夹,其中包含了由PhysicsEditor创建的Box2DChipmunk plist文件的加载器代码(图形缓存)。本章的示例项目中将使用GB2ShapeCache类来加载PhysicsEditor创建的图形。

图3 PhysicsEditor应用程序

现在应该把PhysicsBox2D03项目的Assets/pinball文件夹中的PNG文件拖放到PhysicsEditor中最左边的Shapes窗格中。

注意:

创建物理图形时将只使用HD分辨率的图像,而不需要分别创建HDSD分辨率的物理图形。物理模拟世界与物体的图形表示无关,所以与屏幕分辨率也无关。

PhysicsEditor中,首先要修改导出器的设置。PhysicsEditor可以导出为多个游戏引擎的格式,支持Box2DChipMunk物理引擎,甚至允许创建自定义导出格式。要编写与cocos2d兼容的文件,必须将最右边窗格中的Exporter设置为Box2D generic(PLIST)。导出器根据目标物理引擎的功能启用或禁用PhysicsEditor GUI的某些功能,所以首先设置导出器很重要。

接下来应该将PTM-Ratio设置为240。该值的单位为每米的像素数,意味着240个像素等于Box2D物理模拟世界中的1米。因为Box2D经过了优化,最适合处理110米大小的物体,所以Box2D物理世界的尺寸很重要。用更大或更小的物体进行模拟也很容易,但是在物体非常大(几十米甚至几百米)或非常小(零点几米)时,Box2D的精度会降低,并可能呈现奇怪的行为。

我们在PhysicsEditor中使用的是高分辨率图像,所以PTM-Ratio240将创建一个高4(Retina显示屏幕的分辨率960除以240)、宽2.6(Retina显示屏幕分辨率640除以240)的弹球桌。cocos2d中像素与米的实际比率是PhysicsEditorPTM-Ratio设置的一半,在这里就是每米120个像素。这是因为cocos2d的坐标系使用点作为单位,所以标准分辨率显示屏幕和Retina显示屏幕的尺寸是相同的,均为320×480个点。1个点在标准分辨率显示屏幕上为1个像素,在Retina显示屏幕上为2个像素。在Box2D物理世界中,弹球桌的尺寸不受实际屏幕分辨率的影响。如果只使用标准分辨率的图像,而禁用了对Retina显示屏幕的支持,那么PhysicsEditor中的PTM-Ratio设置将与cocos2d相同。

定义发射器形状

首先设置发射器,即把球弹到游戏区的弹簧。在最左边的窗格中选择发射器图像,然后在中间视图的工具栏上单击“添加多边形”按钮。这会在中央工作区创建一个新的三角形并选中它。因为我们需要一个矩形,所以单击某个边,添加第4个顶点。如果添加了过多的顶点,可以右击或者在按住Option键的同时单击一个顶点,然后选择Delete point删除该顶点。

应该把4个顶点拖放到发射器的4个角上。创建一个包围整个发射器的矩形,将弹簧包含在内。这可以避免球偶然落入发射器内出现的问题。

你可能已经注意到了那个包含加号的小蓝圆圈,它是形状的定位点,刚好与形状精灵的定位点相同。后面我们在cocos2d中定位形状时,将使形状的定位点在我们提供的坐标位置居中。

我们要把定位点放到发射器底部的中心位置,以便简化定位发射器的工作。拖动蓝色圆圈是可以的,但是在许多时候这样做不够精确。此时,可以在Image Parameters下的Parameters窗格中修改定位点的绝对像素位置或相对位置。

在图4中,可以看到正在编辑的发射器形状。

图4 在PhysicsEditor中手动定义形状

如果不想从多边形创建形状,也可以使用“添加矩形”按钮,但是这样一来,我就无法解释如何添加或删除顶点,以及如何拖动它们了。

还要在Parameters窗格的Fixture parameters部分设置发射器的碰撞位。这些碰撞位设定了哪些形状会碰撞,哪些不会。它们还用于防止发射器与球以外的其他形状发生碰撞。

为了简化碰撞位的使用,可以改变它们的名称。这些名称只是用于提醒你自己各个位的用途,它们不会被导出。默认情况下,这些位的名称为从bit_0bit_15。这里要将前5个位的名称改为BallBumperFlipperPlungerWall

只有当两个形状的类别位(标记为Cat的复选框列)和掩码位(标记为Mask的复选框列)都被选中时,Box2D形状才会发生碰撞。通常会把每个形状分配给某个特定的类别。就发射器而言,只将Plunger类别的类别位置位。换句话说,是将发射器的形状分配到了Plunger掩码位类别中。然后使用Mask复选框指定这个形状可以与其他哪些类别发生碰撞。对于发射器,应只设置Ball类别的Mask复选框,因为只允许发射器与球发生碰撞。图5显示了Plunger碰撞类别和掩码标志的正确设置。

图5 发射器的碰撞参数

 

注意:

到目前为止,发射器可以与球发生碰撞,但是球不会与发射器发生碰撞。必须记住,碰撞的定义是一个双向的过程,在本例中还要把球放到Ball类别中,并为球选中与Plunger类别对应的Mask位,这样球和发射器就可以彼此发生碰撞了。

还可以为相同的类别设置掩码位,从而允许相同类别的多个对象彼此发生碰撞。对于球,将Ball类别的Mask位置位很合理,因为球与球可以发生碰撞。当想要扩展弹球游戏,以支持在弹球桌上同时有多个球的情况时,这么做很有帮助。

CatMask类别的底部会看到AllNoneInv按钮,它们分别用于选中全部复选框、清除所有复选框以及反转复选框的选中状态。使用它们可以避免连续选中几十个复选框的情况。

定义弹球桌形状

弹球桌包含3个单独的形状,分别叫做table-bottomtable-lefttable-top。弹球桌图像被分割开,以方便编辑形状,并且这样一来,不必替换整张图像就可以创建不同的弹球游戏布局。

Shapes窗格中选择table-top图像,开始编辑弹球桌最上边的部分。从图6可以看到,这是一个凹多边形。前面手动定义了发射器,但是手动地创建这个半圆形的所有顶点十分困难且容易出错,更别说保证得到的形状是凸多边形了。使用PhysicsEditor可以大大简化这些工作:只要用鼠标单击一次,它就会跟踪形状的轮廓,并创建一个合适的形状。

在中心窗格的工具栏上有一个魔棒图标,叫做Shape Tracer。单击该图标将打开如图6所示的Shape Tracer对话框。

图6 Shape Tracer会自动创建形状

 

Shape Tracer显示了单击OK按钮后它会创建的形状的图像以及形状的覆盖层。在图像下方有一个滑动条,两侧有一些按钮,控制图像的缩放级别。图像的缩放设置对创建的形状没有影响。

Shape Tracer中要调整的最重要的一个设置是ToleranceTolerance可以改变在创建形状时图像跟踪操作的精确度,这将直接影响形状中使用的顶点数,进而影响物理模拟的性能。一般来说,应该在实现足够的碰撞响应的前提下,使用尽可能少的顶点。对游戏而言,碰撞的精确度越重要,一些物体需要的顶点数越多。另一方面,如果添加了许多使用同一种形状的物体,那么该形状的顶点数越少,游戏的性能就越高。

通过多次试用Tolerance设置,我发现本例中一个不错的折中是将Tolerance设为(4,0)。这会创建一个顶点数为18的形状,而且是能够保证非常精细地跟踪图像形状的Tolerance最大值。默认的Tolerance设置(1,0)会创建一个顶点数为31的形状,所以我的设置减少了3个顶点。但是如果遍历Tolerance值的话会发现,甚至Tolerance(1,5)也可以将顶点数减少为20

提示:

Shape Tracer中的Frame Mode设置可以用来为动画(一个图像序列)创建形状。要在PhysicsEditor中创建形状,需要在默认的PhysicsEditor窗口中找到Parameters窗格的Image Parameters部分,向形状添加多个图像文件。单击Filename设置旁边的“+”按钮即可向形状添加额外的形状,然后就可以让Shape Tracer创建每个动画帧的形状的交集或并集。

对得到的形状感到满意后,单击OK按钮关闭Shape Tracer对话框。新形状将会创建出来。你仍然需要手动做一些调整,使弹球桌的碰撞更加真实自然。由于屏幕区域将成为弹球桌的碰撞边界,因此应该把弹球桌左下角和右下角的顶点以及左上角和右上角的顶点拖到屏幕稍微靠外的地方,并分别向下和向上拖动一些,使得它们位于table-top图像周围的黑色边框区域以外,如图7所示。

图7 最终确定弹球桌的table-top形状

 

通过以这种方式处理顶点,形状可以平滑地与屏幕边框衔接起来。否则,由于物理模拟中不可避免的小误差,球可能会在这些顶点位置反弹出去。

现在,使用Image ParametersParameters窗格中的定位点设置把定位点(包含“+”的蓝色圆圈)移动到左上角。将Relative的值分别设为(0,0)(1,0),将定位点移动到左上角。由于有了这个定位点,后面可以简单地将图像定位到(0,480)坐标位置,实现图像与屏幕边框的精确对齐。

注意:

如果看不到定位点圆圈,Image Parameters下也没有关于定位点的设置,就说明Parameters窗格中的Exporter没有被设为Box2D generic (PLIST)格式。

最后一步是调整table-top形状的碰撞位。选中Wall的类别(Cat)复选框,然后选中BallMask复选框。这样弹球桌就可以和弹球发生碰撞了。相应的,需要设置table-lefttable-bottom形状的相同碰撞位,因为它们都是Wall类别的一部分,并且应该能够与Ball类别发生碰撞。

使用Shape Tracer,以相同的方式为table-left图像创建形状。在Image Parameters下,将定位点移动到像素坐标(0,0)(50,0)。不要忘了像前面的table-top那样设置碰撞位。

现在跟踪table-bottom图像的形状。需要的步骤要多一些,因为table-bottom图像实际上包含4个彼此不相连的单独元素,它们都需要有自己的形状。PhysicsEditor 1.0.4只能跟踪连续的形状,所以这里就需要打开Shape Tracer 4次。每次打开时,单击想要跟踪的图像部分,然后单击OK按钮创建形状。对于这4个形状,将Tolerance设为(4,0)的效果都很好。最后得到的4个形状就代表了table-bottom图像的4个元素。不要忘了像table-top那样设置碰撞位,如图7所示。

定义挡板

选择图像flipper-left并打开Shape TracerShape Tracer的初始建议形状并不合理,实际的形状要大得多。

这是因为这幅图应用了闪光和阴影效果,在形状周围创建出光环,但是在浅色背景中几乎看不到。为使Shape Tracer创建更好的形状,需要调整Alpha threshold设置。默认值是0,表示在跟踪形状时会考虑所有不完全透明的像素。本例中我们只想考虑形状的完全不透明元素。如图8所示,如果将Alpha threshold设为254,得到的结果会好很多。

图8 在跟踪挡板形状时,设置好Alpha threshold可以忽略图像的阴影

提示:

如果由于某些原因,Shape Tracer得到的结果不符合要求,而ToleranceAlpha threshold设置都不能解决问题,那么可以在关闭Shape Tracer后手动编辑形状。为此,单击任意顶点并进行拖动即可。另外,双击一个顶点可以删除它,双击两个顶点之间的线段可以添加一个新顶点。

flipper-right图像重复相同的过程,并且不要忘了为两幅图像设置碰撞位:选中Flipper类别,选中BallMask复选框。碰撞位的设置参见图8

左挡板的定位点应设为像素坐标位置(27,78),右挡板的定位点应设为像素坐标位置(97,79)

作者Steffen Itterheim,从20世纪90年代开始就一直热衷于游戏开发。他在Doom和Duke Nukem 3D社区表现活跃,并因此获得了他的第一份自由职业,成为3D Realms的一名beta测试人员。作为职业游戏开发者,Steffen拥有10多年的丰富经验,其中大部分时间担任Electronic Arts Phenomic的游戏和工具程序员。2009年Steffen第一次接触cocos2d,那时他与其他人共同创办了一家iOS游戏公司——Fun Armada。他乐于将自己的宝贵经验传授给其他游戏开发者,以帮助他们更上一层楼。有机会你可能会在白天看到他在住所附近茂密的葡萄园周围散步,也可能在晚上看到他在Nevada沙漠收集瓶盖。

作者Andreas Löw,在10岁的时候有了一台Commodore C16,从那时起他就对计算机产生了狂热的兴趣。他自学了编写游戏的技术,并在1994年发布了自己的第一款游戏Gamma Zone,这是一款针对Commodore Amiga平台的游戏,用纯汇编语言编写完成。在获得电子工程学的学位后,他进入Harman International公司,负责为汽车行业开发具有语音识别功能的导航和娱乐系统。他开发了自己的编程语言和开发工具,现在世界上采用语音识别技术的每辆汽车都在使用他的编程语言和开发工具。

本文节选自《iOS 5 cocos2d游戏开发实战》(第2版)一书。()伊特海姆 、()勒夫著 ; 由清华大学出版社出版。

 

 

转播到腾讯微博

----->立刻申请加入《程序员》杂志读者俱乐部,与杂志编辑直接交流,参与选题,优先投稿

One Response to “游戏开发实战之弹球游戏”

  1. liron71 说道:

    一种实现人工智能程序自进化的概念原理 http://blog.ifeng.com/article/20492401.html

请评论

preload preload preload
京ICP备06065162