本文作者为TexturePacker和PhysicsEditor的工具的开发者。
通过本文,你将学习如何制作一款有关猴子一天糟糕经历的游戏。它专注于自己的事情,但很多疯狂物体持续从天而降。
大家可以参考如下视频:
视频晚些时候发布
到本文结尾,你将完成一款基于物理原理的杰出游戏,知晓TexturePacker和PhysicsEditor如何帮你节省大把开发时间。
要读懂本文,你需对Cocos2D有所了解。
你还需要具有TexturePacker和PhysicsEditor工具。你可以从TexturePacker.com和physicseditor.de下载二者的评估版,但需注意,评估版的功能并不完整。

入门指南

我们将从设计阶段着手。所以首先我将简要概述这款游戏的运作方式。
就如你所看到的,我们的主角是猴子,其运动将由加速计控制——也就是通过倾斜iPhoneiPad的左右方向。当我们触动屏幕时,猴子就会跳跃。
游戏中,道具会从屏幕顶部落下,降落频率会随游戏的进展而提高。我们将在游戏中设置降落指示器,告知玩家下个道具的降落位置。道具持续累积,猴子需停留于道具的顶部,方能保持存活。
游戏包含两类道具:伤害和治愈猴子的道具(dApps注:例如香蕉会治愈猴子)。猴子的健康状态会在屏幕左上方以香蕉状呈现。
玩家分数会显现于屏幕右上方,通常是在道具堆的最高点位置。

要着手制作,首先要下载指南源代码,将其压缩至首选位置。你的起始点是0-BaseProject,这包含基本Cocos2d设置和若干整合资产。
我已在若干开发阶段中添加目录,其中包含你需完成的结果。这些目录会简化你的工作,防止你迷失方向或跳过项目的某块内容。
各文件夹都包含独立完整项目,且包含两个子文件夹:
第一个文件夹叫做Assets,包含TexturePacker和PhysicsEditor保存文件之类的内容,目录形式的Xcode项目及Vicki Wenderlich创建的免费游戏图像集。
Assets文件夹进一步分解成子背景和jungle文件夹,前者包含背景图像,后者则是近景物件和动画内容。
第二个文件夹是MonkeyJump,包含Xcode和文件源,文件源位于第二个MonkeyJump文件中,第二个MonkeyJump文件包含如下子文件:

  • libs:Cocos2d、Box2d和Cocos Denshion等所有Cocos2d内容
  • GBox2D:我的ObjectiveC++ Box2d包装内容
  • Resources:音效和配乐

创造子画面表单

现在可以开始着手真正的内容,首先从子画面表单入手。
打开0-BaseProject文件夹,查看资产文件。我已安排好图像内容。我们将把“背景”文件中的子画面添加至首个子画面表单中,再来是将“jungle” 中的子画面内容添加至第二个子画面表单中。
背景表单将运用RGB565(三原色光模式),这是16位元的图像格式,能够减少50%的存储容量。运用RGB565也能够加速渲染过程。包含多数内容的近景表单也将采用RGBA8888,呈现高质量画面。

创建背景子画面表单

我们从制作背景表单入手。首先是启用TexturePacker,访问O-BaseProject\Assets\background folder,将其拖至TexturePacker窗口的右侧。你将看到jungle背景图像出现在窗口中间。

background settings

background settings


要设立纹理参数,首先要选择Data格式,这当然就是Cocos2d。接着选择Texture格式。我们将采用PVR压缩格式.pvr.ccz。
TexturePacker提示我们应打开预乘alpha,然后表示同意,点击“Apply”。
预乘的意思是,保存文件时所有颜色值同透明值相乘。这加速游戏的图像渲染,相乘步骤无需在运行时间中执行。
pvr.ccz的主要优点是,其能够很快加载,通常比PNG消耗更少内存。在TexturePacker右下角标记,内存消耗量如何从8192kB减少至4096kB。
图像质量会受到细微影响:我们可以发现渐变色没那么流畅,出现若干所谓的banding伪影。我们可以通过在FloydSteinberg中融入Dithering(抖动递色)弥补这种情况。
下面两个图像呈现部分jungle内容。左侧没有dithering,右侧有:

然后,将Data文件设置成Xcode项目Resources目录中的background-hd.plist。系统会自动将Texture文件移至background-hd.pvr.ccz。
不要担心路径会以绝对模式呈现。TexturePacker会在文件保存后立即创建自己的相对路径。这意味着,只要不改变资产&资源同.tps file保存文件的相对位置,我们就能够随意移动项目。
-hd扩展名非常重要,因为TexturePacker能够保存视网膜屏幕,降低图像分辨率服务陈旧设备。要做到这点,只需查看AutoSD选项。这能够创造服务视网膜屏幕的background-hd.plist和background-hd.pvr.ccz文件,以及background.plist和background.pvr.ccz内容,满足低图像分辨率需求。
Max. width和Max. height以红色呈现,这意味着TexturePacker无法在纹理尺寸规格里呈现子画面,因为边距填充的默认值是2。
向下滚动左窗格,将边距填充和模型填充设置成0。当前所有数值都应以黑色呈现。
背景图设置

背景图设置


最后,通过点击Save,将表单以background.tps格式保存于Assets文件夹中。这令Resources文件生成4个文件:background-hd.plist、 background-hd.pvr.ccz、background.plist和background.pvr.ccz。

创建Jungle子画面表单

现在通过点击工具栏中的New按键创建近景内容的新表单。将资产文件中的完整jungle文件夹拖至空白的右窗格中。
TexturePacker如何在右窗格中建造完整目录结构?(dApps注:你可以通过点击“jungle”左侧的箭头按键扩展树形视图)。

Folder Hierarchy

Folder Hierarchy


我们采用Smart Folders功能,在此每次我们于文件夹中添加子画面时,TexturePacker都会重新扫描目录。若你想要添加新资产或给既有资产重命名,只需将其放入有关文件机制的文件夹中,然后当你重新登陆TexturePacker时,系统就会自动更新表单。
注意:若你需要立即更新众多子画面表单,可以切换至Terminal,通过调用TexturePacker *.tps更新命令行中的所有.tps文件。
你甚至可以将TexturePacker整合进自己的Xcode创建过程中。这有若干优点。
首先,你不再需要担心子画面表单——只需将子画面添加至自己的资产文件夹中。
其次,若你采用版本控制,子画面表单就会以二进制blob模式呈现。这将快速扩展你的工作副本尺寸,特别是在控制版本中采用Git或Mercurial软件。关于此的简单操作方式是,不要在版本控制中添加子画面表单,而是抽空制作这些内容。
关于选项,我们采用和背景表单相似的设置方式。确保图像采用RGBA8888格式,以高质量状态呈现。
Folder Hierarchy

Folder Hierarchy


同时要将边距填充的默认值设置成2。这将减少子画面的边界伪影情况。有时OpenGL会融入相邻子画面的像数。边距填充通过在子画面周围添加透明边距避免此问题。
注意:若你想要无缝隙地将子画面用作并列图层,你就得避开或减少边界伪影(dApps注:这将透明边界换成彩色模式)。若你没有这么做,并列图层中的横线就会变成透明状态。
将项目Resources文件夹中的jungle-hd.plist设置成Data文件,将同个文件夹中的jungle-hd.pvr.ccz设置成Texture文件。查看AutoSD旁的方框。
最后,将表单以“jungle.tps”格式保存于资产文件中,然后点击Publish。这令Resources文件夹生成4个文件:jungle-hd.plist、jungle-hd.pvr.ccz、jungle.plist和jungle.pvr.ccz。查看它们是否存在那里。
foreground settings

foreground settings

手动制作物理模型

下面我们将通过PhysicsEditor创建物理模型。
启动PhysicsEditor,从基本装置着手。我们需要将Exporter设置成Box2d Generic (PLIST)。为此,我添加一个载入程序,你可以将此运用至自己的Cocos2d项目。若你不满意PhysicsEditor所支持的格式,可以创建自己的自定义数据输出装置。
将PTM-Ratio设置成170。这告知Box2d,170像数=1公尺(39.37英寸),公尺是Box2d的内部测量单位。我选择170像数是因为这刚好是猴子的高度,在模拟情境中猴子的高度将变成1公尺。
基于不同分辨率创建不同模型将令物件生成不同集合,从而带来不同物理行为(dApps注:这是我们所不需要的)。这里的理念是基于各种设备运行相同模拟情境,然后只调整图像元素。

physicseditor setup

physicseditor setup

设定固定装置

我们现在将要手动创建自己的首个模型。将jungle/floor/grassfront.png模型拖至PhysicsEditor的左窗格。当你这么做时,模型也会同时出现于中间窗格,这是核心编辑区域。
在蓝色小圈圈中标上叉叉:这是模型的定位点。我们将维持此模型的定位点位置,也就是右下角的位置。稍后我将向你展示如何改变此定位点。
首先运用顶部工具条中的多边形工具。只要你点击此工具,小型红色三角形就会出现。你可以通过自己的鼠标拖曳此三角形。
控制键让你得以调整三角形的形状。在线条旁进行双击操作,就能够添加额外顶点。双击顶点可以进行移除操作。
你无需考虑多边形方向或凸面、凹面模型这类的元素。这些都可以通过PhysicsEditor进行处理。
现在我们将给地面创建四边形模型。地面应该盖过土壤,但不要盖过草坪,呈现如下样式:

editing shapes

editing shapes

设定参数

地面属于静态模型,因此其参数非常基础。
密度(Density)影响主体/固定装置的重量。地面不会移动,所以密度数值无关紧要。返还(Restitution)是指碰撞模型会从另一物体弹回。我们希望将地面的数值设置成0。
摩擦力(Friction)是这里唯一重要的数值,这决定子画面在平面的滑动数量。所以将此设置成0.7。
下个要设置的道具是触碰位置。PhysicsEditor令你得以轻松处理这些参数——也就是说,无需进行16进制运算。首先,你需要在相关文本字段中设定名称,这样二进制数值就能获得有效名称:
* 平面——包括地面和墙面
* 猴子
* good_objects——不会伤害猴子的物件
* bad_objects——会伤害猴子的物件
忽略其他二进制数字——我们不需要这些内容。

setting the parameters

setting the parameters


两个物体只有在这样的情况下才会发生碰撞:B物体的二进制码范畴(category)被用来充当A物体的掩码(mask),反之亦然。我们将给平面二进制码勾选Category字段,因为此模型就是个平面,然后给所有的二进制码勾Mask字段。这能够促使各物件同平面的碰触。
将项目以“shapes.pes” 格式保存于资产文件夹中。

基于Tracer创建模型

手动创建模型通常总是缺乏趣味。所以不妨让PhysicsEditor替我们效劳。
将下列物体抛至左窗口:背包、香蕉、香蕉皮、食堂、帽子、菠萝和雕像。

autotrace

autotrace


选择背包,点击工具栏中的魔杖图标。这将打开新一个窗口tracer。tracer会呈现以平面模式所追踪模型的当前形状。
tracer

tracer


最重要的设置内容是Tolerance。此数值告知tracer应该如何匹配模型。这直接影响多边形定点的数量。例如,若将Tolerance设置成20,我们将获得5个顶点的多边形,这已不适合模型;将此数值设置成1就会获得39顶点的匹配多边形。
tracer

tracer


数值为5的Tolerance值属于能够被接受的匹配度,这约有15个顶点。完全没有问题!点击OK回到主屏幕。你可以持续调整模型,但不要过于吹毛求疵。

Not enough vertexes & Too many vertexes & Good trace
现在就来设置背包的参数。将密度设置成5.00,将Restitution设置成0.10,将Friction设置成0.5。你定会想要把握这些参数,以更清楚知晓它们的运作情况。
在此碰触截面中,勾选bad_objects旁的Cat. box,通过勾选所有Mask 方框,允许内容同其他所有物件碰触。
同时将定位点(dApps注:中间有叉叉的蓝色圈圈)拖至背包模型的中间。或者,你可以通过把右边工具条的Relative定位点值设成0.5和0.5,从而将定位点设置于模型正中心。
setting up the backpack

setting up the backpack


现在你知道如何创建模型,或手动,或运用tracer,那就接着自己动手制作剩余内容。运用如下图表所呈现的参数。别忘记将各模型的定位点拖至下图像所指示的位置中。

Object Tolerance Density Restitution Friction Category (Cat.) Mask
backpack 5 5.0 0.1 0.5 bad_objects floor, monkey, bad_objects, good_objects
canteen 5 3.0 0.1 0.2 bad_objects floor, monkey, bad_objects, good_objects
hat 5 1.0 0.15 0.4 bad_objects floor, monkey, bad_objects, good_objects
statue 5 10.0 0.05 0.7 bad_objects floor, monkey, bad_objects, good_objects
pineapple 5 1.0 0.4 0.7 bad_objects floor, monkey, bad_objects, good_objects
banana 5 1.0 0.5 0.5 good_objects floor, monkey, bad_objects, good_objects
bananabunch 5 1.0 0.3 0.7 good_objects floor, monkey, bad_objects, good_objects

items

items


最后元素:猴子
我们所要创建的模型还有一个,这是最复杂的元素。猴子包含若干动画阶段(总共14个):
monkey phases

monkey phases


我首先想到的就是给各动画画面添加触碰多边形,从而完美配合各动画阶段。但这是个糟糕的主意。
首先,频繁更换固定装置会消费众多CPU能量。但更主要的问题是,随着新模型的出现,多数有关猴子的元素将发生改变。
这是因为Box2d基于多边形的面积和密度计算体积。若你改变多边形,猴子将得到或失去重量!这会导致物理模拟内容的呈现变得不规律。
解决方案是,只给猴子制作一个模型,尽量确保其匹配度。首先,将一个猴子模型拖至PhysicsEditor中。你可以通过双击模型名称进行重命名。
add monkey

add monkey


现在点击“+” 按键给猴子添加其他动画阶段。文件会在组合框中呈现,你可以进行转换。
通过点击魔杖图标启动tracer。现在你所看到的是模型已不适合猴子。这正是我们所期望的。
tracer

tracer


tracer现在处于动画追踪模式。你可以在两种画面模式中切换:交叉(intersection)和合并(union)。intersection只基于所有子画面都覆盖的内容生成多边形,而union则运用任一子画面所覆盖的元素。应该选择intersection。
滑块让你能够浏览各动画阶段,查看模型如何配合各不同阶段。
我们将把tracer创造的模型当作粗略模式。这是因为我们需要将猴子的身体分成若干部分。这里是我们所要创建的内容:
monkey shape

monkey shape


有时多边形模型无法顺畅滑过其他多边形,它们相互羁绊。这也是我们基于圆形模式设计猴子的原因所在。
另一原因是运用圆圈会带来更快速的碰撞检测。检验圆点是否处于圆圈之内所涉及的数学运算要比测试圆点是否处于多边形内简单得多。所以我们会节省CPU能量。完成其他组件后,我们将删除tracer模型。
首先创建猴子的头部。采用圆圈模型,将其变得和追踪版本一样大。头部应和其他部位区别对待,因为我们希望当物体从空中降落,击中猴子的头部时,猴子会受伤。
要将头部同其他部位区分开,就将Id设置成“head”。头部的category是猴子,其同good_objects、bad_objects和平面触碰,所以确保将这些元素设置成mask(掩码)。将密度设置成2.0,restitution设置成0.1,摩擦值(friction)设置成0.5。
接着基于两个圆圈制作猴子的身体,一个覆盖躯干,一个覆盖腿部。将Id设置为“body”。身体的category是猴子,它同good_objects、bad_objects和平面碰触。将身体的密度设置成2.0,restitution设置成0.1,摩擦值设置成0.5。
我们可以通过选择Filename组合框中的各种图像循环穿梭于各个动画阶段。查看圆圈是否适合各阶段。这无需是完美的搭配,你可以随时返回PhysicsEditor,调整接触组合。
最后,删除基于tracer创建的多边形。
游戏中,我们需要查看左右是否有物体促成此伸展动画。要做到这点,我们需在猴子左右两侧放置两个感应器。
感应器是无需同其他身体部位互动的固定装置,它们只会汇报触碰情况。要将固定装置变成感应器,就需要设置isSensor。
将左传感器的Id设置成“push_left”,右传感器的设置成“push_right”。category是猴子,它们只和bad_objects触碰——我们不希望猴子将平面和香蕉推开。
monkey shape

monkey shape


最后就是:保存,然后点击Publish。将文件以shapes.plist格式存储于项目的Resources文件夹中。
上面就是有关PhysicsEditor制作的全部内容,下面我们将转而谈论Xcode,着手游戏编码。
Xcode项目:综述
我利用附带Cocos2d元素的标准Cocos2d+Box2d模版制作首个项目,移除所有演示内容。我还添加声音资源和若干类(class),通过运用Cocos2d中的Box2d,你的工作将变得简单许多。
有关此项目,需注意的一点是,所有文件的扩展名应是.mm,而非.m。这是因为Box2d基于C++,所以我们必须在开发中采用Objective-C++。
现在我们就来深入谈论此初始项目:
GBox2D
首先先来谈论几点有关GBox2D的内容。GBox2D是Box2d的Objective-C转换内容,主要服务我即将问世的项目《TurtleTrigger》。
Gbox2D包含两个主要class:
* GB2Engine:此class覆盖Box2d的虚拟世界。其运作虚拟内容,更新所有子画面的位置和循环模式,能够循环访问游戏空间的所有物件。GB2Engine以单class模式执行,极大方便访问操作。
* GB2Node:此class型结合CCNode和B2Body。这是物理模拟内容和Cococs2d图像表现的粘合剂。它还包含简单管理物理物件的选择器。,同时植入代理服务器,以访问内部节点的数据。
* GB2Sprite:此class源自GB2Node,主要以CCSprite作为自己的内部物件。
* GB2DebugDrawLayer:这是覆盖调试绘图的Cocos2d图层。你可以像添加正常图层一样将其添加至自己的项目中。添加后,此软件将绘制物理模型的轮廓。这一软件的优点在于能够察觉内容是否运作于视网膜显示目标,然后相应地扩充内容。
* GB2Contact:当察觉存在冲突时,此结构将转变成物件的参数。每次接触都会调用进行碰触的两个相关物件。
* GB2WorldContactListener:这是C++ class,软件在物理模拟情况中反应碰撞。
若你有兴趣,可以自己查阅相关知识。但若你不清楚它们的实际操作内容,也不要担心,在下面的内容中,你将把握这些工具的运用方式。