如何制作 Tappy Plane(Flappy Birds 克隆版)
简介:
欢迎来到本教程!我们将学习如何在 hyperPad 中制作一款属于自己的“Flappy Birds”风格游戏。
我们的版本略有不同,所以把它叫作 Tappy Plane。
本教程面向初学者,帮助大家深入了解我们的行为系统并学习可视化编程。在整个教程中,你也会熟悉 hyperPad 的操作界面。
本教程将制作一款简单的 Flappy Bird 风格游戏。玩家通过点击屏幕控制飞机上下移动,穿过一系列悬崖。每成功越过一座悬崖即可获得一分,得分达到一定数量后,玩家还能获得奖牌。分数越高,奖牌价值越高,最高可获得闪亮的金牌!谁不喜欢闪亮的东西呢!?
如果你还没有 hyperPad,可以从 App Store 下载:https://itunes.apple.com/app/apple-store/id886106438?mt=8
你可以访问我们的网站 http://www.hyperpad.com 了解更多 hyperPad 信息。
话不多说,我们开始吧!
第 1 部分:入门
创建项目:
首先,我们需要创建一个新项目。打开 hyperPad 后,你应该会看到项目界面。在这里,你可以找到自己创建的所有项目以及下载的项目。现在,我们要创建一个新项目。点击屏幕右上方的“新建项目”按钮,如下图所示。
完成后,会弹出一个窗口。在这里,我们可以为项目命名,并根据需要创建云端备份。此外,你也可以点击“改为从示例开始”按钮,导入我们的基础项目。不过这次我们先不这么做。将项目命名为 Tappy Plane,然后点击“下一步”按钮。
在这个新界面中,我们将确定要适配的设备和屏幕方向。对于本项目,请将屏幕方向设为横向,并将设备支持设为 iPad。如果之后需要更改设置,也不用担心。你随时可以在“全局设置”菜单中进行调整。
最后,我们可以选择要制作的游戏类型。目前 hyperPad 支持两种模式:俯视视角和侧视视角。俯视视角,也称为鸟瞰视角,通常用于《塞尔达传说》系列转为 3D 之前的作品、《Bejeweled》这类益智游戏,以及俯视射击游戏。侧视视角则常用于《超级马力欧兄弟》这类平台游戏。
这两种模式的运行方式完全相同,只有一处小小的区别:鸟瞰视角会禁用重力设置(而是依靠空气阻力来模拟朝屏幕深处的重力效果),所以创建项目时请记住这一点。你可以随时在“全局属性”菜单中更改此设置。
本教程将使用侧视视角,请确保已选中该选项。接下来是重力设置和 PTM 比率。重力默认值为 0 和 -25。
这两个值分别代表游戏世界中的 x 轴和 y 轴,也就是水平方向和垂直方向。X 代表水平方向,即左和右;Y 代表垂直方向,即上和下。默认值 0 和 -25 表示不会有重力将物体向左或向右拉动,但物体会以每秒 25 米的速度下落。本教程中,默认值就可以满足需要。
PTM 比率表示“点数与米的比率”,简单来说,就是 1 个 hyperPad 米等于多少像素(点)。默认值为 32 pt/m,即每米 32 像素。制作美术素材时必须了解这一点,所有美术素材都应遵循这一比例。本教程将使用 hyperPad 素材库中的免费素材,因此无需更改比例。
设置完成后,点击“创建”按钮,我们就可以开始了!
编辑器:
现在我们已经进入项目,你应该会看到类似这样的界面:
这是我们的画布,也是构建游戏的地方。在屏幕中央,你应该能看到一个细细的绿色矩形轮廓,它代表屏幕的可视范围。放在这个矩形内的内容会在游戏开始时立即显示,而矩形外的内容则不会渲染。如果你愿意,可以先四处点一点,看看各个按钮的功能,然后再继续下一步。
准备好后,点击右下角的抽屉图标,打开素材浏览器。
素材库:
游戏所需的所有素材都存放在这里。默认情况下,新的 hyperPad 项目只包含少量入门素材。你需要导入自己的素材,或者从 hyperPad 素材商店下载素材包。本教程将重点使用 hyperPad 素材商店提供的素材。左侧有一栏,里面有四个按钮。点击“获取素材”按钮,打开 hyperPad 商店。
这里有我们在 hyperPad 提供的免费素材包,可以帮助你开始制作项目。找到并点击 Tappy Plane 素材包。
现在,只需点击“获取”按钮即可开始导入。(注意:如果出现错误,只需再次点击该按钮即可重新开始导入。)导入完成后,你会看到素材已成功导入的提示。点击屏幕右上方的“关闭”,返回 hyperPad。
就是这么简单。现在,你应该会在素材浏览器中看到一个名为“下载”的新文件夹。点击它,就会看到 Tappy Plane Pack 文件夹,里面就是我们的美术素材。
接下来,我们将开始组装游戏。
第 2 部分:游戏玩法
如果你熟悉 Flappy Bird,就会了解这种游戏玩法。点击屏幕,让小鸟——在我们的游戏中是飞机——保持在空中,同时避免撞上迎面而来的障碍物。这些障碍物会以随机组合生成,因此每次游玩都会有所不同。成功避开障碍物即可获得分数,游戏还会记录你的最高分。
添加飞机:
现在你已经了解基本玩法,我们可以开始了。首先要做的是把玩家角色放到屏幕上。打开素材浏览器中的“下载”文件夹,继续找到美术素材。里面应该有一个名为 Planes 的文件夹。
打开该文件夹,选择你最喜欢的颜色,然后点击第一张飞机图片。这会关闭素材库并返回主编辑器界面,此时飞机应该会显示在底部的对象停靠栏中。这个 UI 区域称为“对象停靠栏”,会显示你最近使用的 5 个素材。现在,要把飞机放到游戏区域,只需将它从停靠栏拖到画布上。
飞机放入游戏后,我们需要快速调整一下。点击飞机将其选中,然后打开右侧的属性选项卡。我们要把飞机设为可穿透墙体对象。很简单,找到“可穿透”开关并点击将其打开。这样做是为了避免玩家还没来得及开始游戏,飞机就先掉下去了。我们还将它设为可穿透,是因为暂时不希望它发生碰撞。
完成后,让我们开始制作可玩的部分。
飞机下落:
我们需要一种启动游戏的方式,因此需要一个按钮。我们可以用一张简单的图片提示玩家点击哪里,但在这个游戏中,我们希望玩家可以点击屏幕上的任意位置。怎么做到呢?我们把整个屏幕都做成按钮!
首先要新建一个图层。不过在此之前,我们需要取消选中飞机。只需点击任意空白处即可取消选中。取消选中后,对象属性会关闭,右侧应该会显示图层选项卡。如果没有显示,只需从屏幕右侧向左滑动手指,将其展开。
如你所见,默认情况下目前有三个图层:Global UI、Scene UI,以及分隔线下方的 Main。简单说明一下:Global UI 图层上的所有内容都会出现在游戏的每个场景中。其他图层则只属于各自的场景。要创建新图层,只需点击图层选项卡底部的 + 图标。系统会提示你为新图层命名。输入 Button,然后点击“确定”。
默认情况下,活动图层会切换到刚创建的新图层。使用图层时,只有活动图层中的对象可以被选中。这是整理游戏内容的好方法,可以避免意外移动不想移动的对象。请始终留意当前正在使用哪个图层。还要记住,位于其他图层上方的图层会渲染在其上面。这样可以避免背景遮住游戏区域。
现在来创建按钮,这很简单。点击对象停靠栏右下角的“特殊对象”按钮(烧杯图标)。系统会弹出一个菜单,让你选择要创建的对象类型。我们需要的是“空对象”。点击后,项目中央会出现一个小的空白方块。不过我们希望它覆盖整个屏幕。点击方块内部将其选中。
选中后,你会看到对象边缘出现了绿色小点。我们可以用这些点手动调整空对象的大小。只需点击并拖动一个角,即可等比例缩放。拖动角上的点,直到对象覆盖整个画布。侧边的点可以用来调整对象,以便更好地贴合画布。最终效果应该类似这样。(注意:如果缩放对象时遇到困难,可以用两根手指向相反方向滑动来放大,向彼此靠近则可以缩小。)
取消选中空对象(点击画布上的任意空白处),然后点击 Main 图层,返回主图层并重新选中飞机。点击“行为”按钮,打开行为界面。
这里就是“行为”界面,也是创造魔法的地方。hyperPad 不使用传统代码,而是通过可视化逻辑块组合动作和事件,来编写交互逻辑。你可以花点时间浏览各个分类,看看有哪些选项。点击左侧选项卡中的某个行为,会打开一个窗口,简要介绍该行为。你也可以查看 hyperPad 文档,了解每种行为的详细说明。
现在我们只需启动游戏,并将飞机从可穿透墙体对象变成物理对象。这样就会对飞机应用物理效果,使它在重力作用下下落。
首先,我们要使用“交互”分类下的“开始触摸”行为。只需将它从菜单拖到空白区域即可。放置后,它就会附加到我们的对象上。你可以点击该行为打开其属性,但我们不需要更改任何内容。
当然,只有这个行为不会发生任何事情,因为触碰飞机之后没有后续操作。我们来解决这个问题。进入“物理”分类,向下滚动,直到看到“模式”部分。将“设为物理对象”行为拖到“开始触摸”行为下方。现在只需将它连接到“开始触摸”即可。在“开始触摸”行为底部,你应该会看到一个圆圈中的小闪电图标。点击并拖动它,你会看到一条线跟着手指移动。将这条线拖到“设为物理对象”行为上,即可将两者连接起来。
就是这么简单。简单说明一下:在 hyperPad 中,行为遵循“事件 -> 动作”的结构。在这个例子中,事件是我们开始触摸飞机,动作则是将飞机变成物理对象。我们先测试一下,确保它正常工作。点击屏幕顶部的播放按钮开始测试。测试完成后,点击右上角的三条横线打开菜单,然后选择“退出”。
如果一切正常,点击飞机后,它应该会掉出屏幕。
现在,我们希望飞机碰到地面时结束游戏。虽然现在还没有地面,但我们可以用一个空游戏对象来模拟。点击屏幕左上角的返回箭头,返回画布。
取消选中飞机,然后点击停靠栏右下角的“特殊对象”图标(烧杯),打开窗口,再创建一个空对象。现在将它放在画布底部,并拉伸到覆盖整个底部区域。
选中飞机,再次打开行为窗口。现在我们要添加“失败”条件。回想一下前面说的,hyperPad 行为遵循“事件 -> 动作”的结构。这里的事件是飞机与地面碰撞。我们来设置它。进入“对象”选项卡,在“碰撞检测”下将“发生碰撞”拖到工作区。完成后,点击它打开属性。顶部会看到两个方框,一个已填入飞机,另一个为空。点击空方框会打开画布。点击屏幕底部的空对象将其选中,然后点击底部的勾号确认。
接下来,我们需要添加动作。我们希望飞机与地面对象碰撞时加载游戏结束画面。进入“场景”分类,向下滚动到“叠加层”部分,找到“加载叠加层”行为并将它拖到“发生碰撞”下方。
将“发生碰撞”连接到“加载叠加层”。然后,点击画布上的“加载叠加层”行为,打开它的属性。在行为属性中,点击“选择叠加层”。系统会显示叠加层列表。选择 Game Over,这是默认自动创建的叠加层(你可以在 hyperPad 文档中了解更多关于叠加层的信息)。如果愿意,也可以添加转场效果,让它更出彩。
完成后,点击播放按钮进行测试。点击飞机后,它应该会下落,并显示 Game Over 画面。
游戏逻辑:
继续之前,我先简单介绍一种整理行为的好方法。为了避免界面杂乱,让今后的修改更容易,我们将把游戏逻辑从飞机对象中分离出来。基本上,我们会创建一个自定义事件,并在飞机与地面碰撞时广播一条消息,而不是直接加载 Game Over 叠加层。
为什么要这样做?如前所述,这样可以让内容更有条理,也方便以后调整。可以这样理解:如果逻辑只影响它所附加的游戏对象,就把逻辑留在对象内部。如果需要引用其他对象或与该对象没有直接关联的逻辑,就将它分离出来。例如,飞机与某个对象碰撞时播放碰撞音效,这个逻辑可以留在飞机本身。但如果碰撞后另一个对象发生变化,那么这个逻辑就应该单独处理。
为此,我们将创建一个中介对象,负责将这些操作集中到一个容易访问的位置。
打开飞机的行为界面,然后选中“加载叠加层”行为。属性旁边会有一个小标签。点击垃圾桶图标,删除“加载叠加层”行为。这样做是因为我们不再直接加载叠加层,而是要广播一条消息,让游戏逻辑接收到消息后加载 Game Over 画面。虽然这样在技术上多了几步,但从长远来看会更有好处。
要广播消息,请进入“自定义”分类,在“广播”部分将“广播消息”拖到“发生碰撞”下方(原来放“加载叠加层”的位置)。将“发生碰撞”连接到“广播消息”,然后打开其属性。在“事件键”中输入 Did Lose。在此情况下,“广播值”可以留空,因为我们只是在广播失败状态。如果某种情况下需要知道玩家是否还活着,就可以设置一个表示状态的值。(例如,Did Lose:是/否。)
添加广播消息后,就可以返回主编辑器了。
接下来,我们需要创建一个对象来存放逻辑。我们可以再创建一个空对象,但为了方便查找逻辑,最好不要这样做;随着场景中添加更多素材,空对象很容易被忽略。因此,我们将使用标签。
创建标签的方法与创建空对象相同。点击烧杯,在窗口中选择“标签”。标签就是一个包含文字的游戏对象。除此之外,它与其他对象的工作方式相同。点击标签将其选中,然后在属性中找到“标签”文本框,输入 Game Logic。你也可以调整对齐方式、描边和阴影属性,让逻辑对象更醒目。不过请注意,文字会受到其边界框大小的限制。
将 Game Logic 移到可见屏幕区域(绿色矩形)之外,这样玩家就看不到它了。可以把 Game Logic 想象成后台管理人员:如果他们工作得好,你就永远不会看到他们,但一切都会顺利运行。
现在打开 Game Logic 的行为。我们需要一种接收消息的方法。在“自定义”分类中找到“接收消息”行为并将它拖入。打开属性并点击“事件键”。输入 Did Lose,并确保拼写与“广播消息”中的完全一致。接下来,进入“场景”分类,将“加载叠加层”拖入,并将其设为 Game Over。将这两个行为连接起来。
“接收消息”行为属于“监听器”类型。它会一直等待,直到收到自己正在等待的消息。在这里,等待的是 Did Lose。一旦收到这条消息,它就会触发连接的动作。
点击播放按钮进行测试。和之前一样,飞机撞到地面后,Game Over 画面应该会立即弹出。
飞机跳跃:
在我们的游戏中,飞机在水平方向上应该保持静止,也就是说,它不会左右移动,只会上下移动。我们不会让飞机在游戏世界中水平飞行,而是让场景围绕飞机移动,营造飞机正在水平前进的效果。这样可以适配我们只需一个按钮的玩法。点击屏幕,飞机会上升,然后开始下落。
重新打开飞机的行为,在“自定义”分类下添加一个新的“行为包”。打开它的属性。与其他行为不同,行为包是完全空白的。不过,我们可以修改它的名称。在属性顶部,点击“行为包”名称,将其改为 Jump。接下来,我们要让这个行为包默认处于关闭状态。在属性旁边的小侧面板中,找到“开启”并点击将它关闭。此时行为包应该会变成灰色。
行为包用于将一组行为组合在一起。此外,这些行为会按顺序依次执行。这样我们就能更好地控制行为的触发时间和方式。我们将这个行为包关闭,是因为在游戏开始之前,我们不希望它以及连接到它的动作启动。
现在,我们要把一些行为连接到行为包。首先是“设置速度”,它位于“物理”选项卡中。打开属性,将 X 和 Y 都设为 0。这样可以消除飞机上的重力作用,并取消仍在生效的先前跳跃。
接下来需要“施加力”,同样位于“物理”选项卡中。X 值留空,修改 Y 值。现在先设为 5。之后我们可以调整这个数值,为飞机找到最佳效果。
在行为包上方添加一个新的“开始触摸”行为,并将它连接到 Jump 行为包。现在我们希望这个“开始触摸”行为响应之前创建的按钮。要更改它,请打开其属性并点击飞机,进入画布。将图层切换到 Button,然后点击按钮内部。
现在你的行为应该类似这样:
不过在测试之前,我们还需要做几件事。首先,我们需要启用行为包。进入“自定义”分类,添加一个“开启行为”并将它连接到“开始触摸”按钮。打开它的属性,点击“选择行为”,然后从列表中选择 Jump 行为包。这样,当我们第一次触碰按钮时,Jump 行为包就会启动,并开始对飞机施加力。当然,我们会遇到之前创建的第一个“开始触摸”行为造成的问题。我们来解决它。
在第一个“开始触摸”行为下方,添加一个“关闭行为”(位于“自定义”分类中),并将它连接到原来的“开始触摸”行为。在属性中,选择要关闭的行为,也就是同一个“开始触摸”行为。这样,系统会先将飞机设为物理对象,然后禁用触摸飞机的功能。不过我们还没完成。接下来需要添加“广播消息”,表示游戏已经开始。添加“广播消息”,并将它连接到“设为物理对象”行为下方。这样可以确保消息在禁用行为之前发送。将“事件键”设为 Did Start。
最后,我们可以添加最后一组行为。添加一个“接收消息”行为,但无需将它连接到任何东西。我们希望它单独运行。将“事件键”设为 Did Start。接下来添加一个“开启行为”,并将它连接到“接收消息”。让它开启我们创建的第二个“开始触摸”行为。
不过你可能会问:这个行为不是已经开启了吗?没错!我们来把它关掉。这样可以避免按钮重叠造成错误。全部完成后,飞机的行为应该类似这样:
我们来测试一下。你可能会发现,即使点击屏幕,飞机还是像石头一样往下掉。这是因为“施加力”的值设为 5,而重力的值是 -25。如果要让飞机飞起来,我们就需要克服重力。打开“施加力”的属性,将 Y 值改为 50,并将倍数设为 5。这样应该能给飞机足够的升力,让它短暂保持在空中。花点时间调整数值,直到感觉效果合适为止。
添加障碍物:
接下来,我们需要添加玩家要躲避的障碍物。游戏中主要有两种障碍物:悬崖和天花板。没错,是天花板。不,我们不会把游戏设定在洞穴里。原因很简单:没有天花板的话,玩家理论上可以疯狂点击屏幕,让飞机飞出屏幕,完全绕开障碍物。那就不好玩了,对吧?
我们先来添加天花板,因为这很简单。和地面一样,我们将使用空对象。确保位于 Main 图层,添加空对象,然后创建并缩放它,使其宽度与屏幕一致,再把它移到画布上方。这样,飞机就可以在屏幕范围内飞行,但飞出边界时会撞上天花板。在空对象的属性中,点击“行为”按钮后,你会看到三个图标:火箭、砖块箱和风景图。这些按钮用于确定空对象的类型。从左到右分别是物理对象、墙体对象和背景对象。
物理对象会受到物理效果影响,我们不希望天花板这样。墙体对象是实体,会发生碰撞,但不会受到外部力量影响。背景对象没有碰撞,也无法与任何东西互动。一般来说,纯装饰性对象都应该设为背景对象,以节省内存并提高游戏性能。
将空对象设为墙体对象,然后在这些按钮下方找到“可穿透”,并打开开关。这样方块就不会掉到地面上,但飞机仍然可以穿过它。这样,飞机碰到方块时不会立刻停下来,而是可以稍微飞出屏幕后才开始下落。
为了方便管理,在选中 Ceiling 对象的情况下,将它重命名为 ceiling。在属性菜单顶部,点击显示 Empty-# 的位置,然后输入 Ceiling。保持条理总是有好处的。
接下来,我们要给 Ceiling 添加一个标签。只要多个对象具有相同的标签,就可以通过标签一次引用多个对象。例如,假设你有一个电灯开关,使用开关时会打开场景中的多盏灯。给所有灯添加相同标签,就能一起引用它们并同时打开。在我们的游戏中,我们希望飞机与天花板或悬崖碰撞时下落,因此会给它们添加一个标签。这样就能触发相应效果,也能节省组装行为的时间。
选中天花板对象并打开属性选项卡后,看看底部的五个按钮。第一个应该是灰色的,接着是火箭图标(默认打开)、四个箭头、四条堆叠的横线,最后是标签图标。点击标签图标打开标签窗口。你可以在这里搜索现有标签或创建新标签。现在我们要创建一个新标签。点击 + 号,输入 Wall,然后点击“确定”。Wall 现在会出现在搜索栏下方,右侧有一个绿色圆圈。这个圆圈表示该标签已添加到对象上。如果要更改标签,只需点击标签名称将其移除即可。
现在我们希望飞机能够与标记为“Wall”的对象碰撞,并在碰撞发生时禁用玩家的输入。这样飞机就会掉到地面并结束游戏。要设置这个效果,请选中飞机并进入“行为”。在“对象”分类下选择“发生碰撞”,并打开属性。现在,我们不再点击“选择对象”并在画布上选择天花板,而是要改为检测标签。滚动到属性底部,点击标签图标。系统会显示标签列表。目前我们只有 Wall。选中它,然后点击带有三条横向滑块的图标,返回主属性窗口。现在你会在“选择对象”框中看到标签图标。
完成后,我们只需在“自定义”选项卡中添加一个“关闭行为”,并在其属性中选择控制 Jump 行为包的“开始触摸”行为。这样,飞机碰到天花板时就无法继续飞行了。我们来测试一下。点击播放,然后点击屏幕,直到飞机飞出边界。你应该会看到它随后掉到地面,并加载 Game Over 画面。
你可能会想:“飞机为什么只会上下移动?它不能前进的话,怎么穿过障碍物呢?”其实很简单,我们会让世界朝飞机移动。听起来可能有些奇怪,不过开始游戏后你就不会注意到了。
现在来添加悬崖。返回素材浏览器,向下滚动找到悬崖。有多个版本可供选择,挑一个你最喜欢的就好。本教程中我会使用基础的岩石款。
将悬崖拖到画布上,再把它移到右侧,确保它不会出现在屏幕上。接下来,将它设为可穿透墙体对象。现在我们要更改锚点。锚点是 hyperPad 认为对象中心所在的位置。因此,在计算位置时,它会参考锚点,而不是对象实际的物理中心。
要更改锚点,我们需要打开变换属性。在属性窗口底部,点击四个箭头,打开变换选项。找到锚点并解除锁定。此时悬崖上应该会出现一个蓝色锚点。点击并拖动锚点,将它放到尽可能靠近悬崖顶端的位置。完成后,重新锁定锚点。
现在,我们要让悬崖开始向玩家移动。打开悬崖的行为,在“物理”分类下添加“设置速度”行为。将 Y 速度设为 0,X 速度设为 -2。这样悬崖就会缓慢向左移动。简单说明一下:X 轴上的负值会让对象向左移动,正值则会让对象向右移动。Y 轴也是如此:负值向下,正值向上。
不过,这个速度太慢了。如果每次要调整都得重新进入悬崖的行为界面,很快就会让人厌烦。我们可以使用“属性”来加快这个过程。进入 Game Logic 标签并打开它的属性。还记得底部那个由四条线堆叠起来的图标吗?点击它打开“属性”窗口。属性的创建方式与标签类似,因此我们来创建一个新属性,命名为 Speed。
你会发现,与标签不同,新建属性下方有一个输入框。我们可以在这里输入数值,供其他对象引用。现在将 Speed 设为 5。接下来返回悬崖的行为,在“对象”选项卡下添加“获取属性”行为。
打开“获取属性”的属性设置,点击出现的悬崖图标。在画布上选择 Game Logic 标签,然后在“属性键类型”下选择“预定义”,并在输入框中选择 Speed。
接下来,我们要确保悬崖向左移动。还记得我说过 X 轴上的正值会让对象向右移动吗?我们要改变这个方向。进入“逻辑”选项卡,选择“数值相乘”。将它连接到“获取属性”,并打开它的属性。现在你会看到两个输入框。第一个框是数值,第二个框是要与之相乘的数值。注意,选中“数值相乘”后,某些行为的角上会出现带向上箭头的绿色小圆圈。这表示我们可以将这些行为的输出用作输入值。要这样做,只需点击并拖动“获取属性”行为上的圆圈,将它放到“数值相乘”属性中的第一个输入框。(要了解更多信息,请查看 hyperPad 文档中的共享数值。)
接下来,在第二个框中输入 -1。这样我们就把值为 5 的 Speed 乘以 -1,结果为 -5。这样悬崖每秒就会向左移动 5 米。现在还不会马上生效。返回“设置速度”行为,将之前输入的 -2 替换为“数值相乘”的输出值。Y 值保持为 0。
测试游戏,看看悬崖如何从屏幕上移动过去。现在悬崖的速度合适了,不过你随时可以回到 Game Logic 标签的属性中快速调整。比每次都进入悬崖的行为界面方便多了,对吧?
不过你会发现,飞机会直接穿过悬崖。这是因为我们将它设为可穿透。我们希望保持这一设置,但仍然让飞机撞上悬崖。我们只需要给它添加 Wall 标签。打开悬崖的属性,进入“标签”选项卡,选择 Wall,然后测试游戏。记得让飞机撞上悬崖。
刚才是不是发生了奇怪的事情?飞机甚至还没碰到悬崖,就开始不受控制地往下掉。这是因为悬崖的碰撞框没有正确设置。默认情况下,对象的碰撞尺寸与边界框相同(也就是你可以触摸并选中对象的区域)。边界框由对象图片的最大宽度和高度决定。因此,无论对象的形状如何,边界框及其碰撞范围都会被拉伸成能够包围整个对象的矩形。
怎么解决呢?很简单。
hyperPad 内置了碰撞编辑器,可以轻松微调对象的碰撞范围。要打开它,先打开悬崖的属性。属性左侧应该会看到一个熟悉的小窗口,里面有三个选项:两个相互指向的箭头、两个重叠的方框,以及一个垃圾桶。
我们要使用第一个选项。点击它打开碰撞编辑器。
你会立即看到侧边栏上的一系列工具。前两个用于导航和移动。选中箭头后,我们可以像缩放对象一样,通过缩放方框来编辑悬崖的碰撞范围。不过,如果想让碰撞范围尽可能准确,矩形可能不是最合适的形状。
接下来的三个工具可以帮上忙。前两个工具分别是圆形和方形,可以将边界框更改为相应的形状。第三个工具看起来像一个不规则的多边形,可以通过点击连接各个点来创建自定义碰撞框。我们来使用这个工具。
选中该工具,然后点击悬崖顶端。原来的碰撞框应该会消失,并出现一个小绿点。现在点击悬崖左下角,创建第二个点,并用黑线与第一个点连接。接着点击右下角创建第三个点,最后回到原来的点,将轮廓闭合。如果没有完全对准也没关系,我们可以轻松调整。点击箭头工具,然后拖动这些点,让它们更贴合悬崖。最终效果应该类似这样:
最后,点击勾号保存更改。如果操作出错,可以使用橡皮擦工具,或者直接点击 X 取消所有更改后重试。完成后,再次测试游戏。现在,飞机撞上悬崖时应该会正常下落。
现在的游戏还是有点太简单了。只有一座悬崖,而且位置始终相同。我们得增加点变化!计划是让悬崖生成时的 Y 轴位置随机变化,并由 Game Logic 控制悬崖的位置和生成频率。悬崖的移动则由悬崖自身控制。这正是我们之前讲到的“分离逻辑”的实际应用。
首先,打开 Game Logic 的“属性”列表,创建一个名为 Cliff Bottom pos 的新属性。
现在,进入 Game Logic 的行为界面,新建一个“行为包”,命名为 Calculate Positions。接下来,进入“逻辑”选项卡,找到“随机数”行为。打开属性,将变量设为 4 和 14。将它连接到 Calculate Positions 行为包。
你可能会想知道我为什么选这两个数值。要弄清楚,我们回到素材浏览器,再次找到悬崖。按住悬崖图片片刻,打开选项窗口。点击“预览”打开“帧预览”。在这里,我们可以看到悬崖的尺寸为 8 米 × 16 米。
我们将数值设为 4 和 14,是因为悬崖生成时,它的 Y 轴位置会在 4 到 14 米之间随机变化,也就是上下移动。设置这些范围也可以避免悬崖生成得太高或太低。
返回 Game Logic 的行为界面,进入“对象”选项卡,找到“设置属性”行为,并将它连接到“随机数”行为。打开“设置属性”的属性,将“属性键”设为“预定义”,并选择 Cliff Bottom pos。对于“属性值”,将“随机数”行为右上角的输出拖到“属性值”输入框中。
我们暂时完成了这部分。接下来返回悬崖的行为界面。
在悬崖的行为中,从“对象”选项卡添加一个新的“获取属性”行为。打开属性并点击悬崖图片,将目标对象改为 Game Logic。返回画布后,点击 Game Logic,再点击勾号确认。将“属性键”设为“预定义”,并选择 Cliff Bottom pos。
现在来设置悬崖的起始位置。在“变换”行为分类中,打开“高级”选项卡。在行为列表底部,你会看到“基础”和“高级”两个选项。点击“高级”显示全部行为。滚动到“位置”部分,选择“移动到点”。将它连接到刚添加的“获取属性”行为。打开“移动到点”的属性。“转场”和“位置类型”保持不变。X 值设为屏幕外的位置。现在先输入 40。Y 值则使用 Cliff Bottom pos 的“获取属性”输出。最后将持续时间设为 0。
测试一下。
很可能悬崖的位置并没有变化。这是因为位置是在悬崖生成后才计算的。我们来生成更多悬崖,看看随机位置的效果!为此,我们需要返回 Game Logic 的行为界面。
从“逻辑”分类中添加一个新的“随机数”行为,将数值设为 1.5 和 3。这两个数值将作为生成计时器,因此新悬崖会每隔 1.5 到 3 秒随机生成一次。生成间隔越短,悬崖之间的距离就越近,反之亦然。现在从“自定义”选项卡中添加“等待”行为。在它的属性中,将等待时间设为新的“随机数”行为。
接下来添加一个“开启行为”,并指定为 Calculate Positions 行为包。这样,每次生成悬崖时都会计算一个新位置。现在我们要生成悬崖。
进入“对象”分类,打开“高级”选项卡,找到“在区域生成”。将它拖到“开启行为”下方并连接起来。打开属性选项卡,你应该会看到 Game Logic 的图片。点击它并选择悬崖。这样,我们生成的就会是悬崖,而不是更多的 Game Logic。接着,在属性底部打开“循环利用”开关,并将“存活对象数”设为 5。开启循环利用后,达到最大悬崖数量时,较旧的对象会自动移除。本例中,最大数量为 5。
如果你不确定某些属性的作用,记住可以随时点击底部的 i 图标,查看该行为的快速参考说明。
接下来,我们需要让它循环,这样悬崖就会不断生成。添加一个新的“开启行为”,并将它设为控制计时器的“随机数”行为。
生成完成后,“随机数”行为就会重新启动,从而不断生成悬崖,试图撞向玩家!太棒了!我们来测试一下。
现在应该能看到悬崖随机地朝我们移动。不过还有一些问题,我们来稍微整理一下。
创建一个新的“行为包”(位于“自定义”分类),打开属性并点击名称,将其重命名为 Initial Cleanup。现在进入“对象”选项卡,添加“销毁对象”行为。在属性中,将目标设为我们的悬崖。还有一个问题是,玩家甚至还没触碰屏幕,悬崖就已经开始移动了。
为了解决这个问题,首先将控制生成的“随机数”行为设为默认关闭。打开它的属性窗口,在小窗口中找到“开启”并点击关闭。要在之后开启它,只需让生成器知道游戏已经开始即可。
打开“自定义”选项卡,找到“接收消息”。“事件键”所需的消息已经设置好了(之前设置飞机时就添加了广播消息)。输入 Did Start。现在添加一个新的“开启行为”,并将它指定为控制计时器的“随机数”行为。
点击播放按钮。现在应该一切正常了……不过游戏还是不够难吧?我们来提升一下难度。
回到主编辑器,选中 Game Logic,并打开“属性”选项卡(属性底部的四条堆叠横线)。创建一个新属性,命名为 Cliff Top pos。接下来进入“逻辑”选项卡,找到“数值相加”行为。我们要把它添加到 Calculate Positions 行为包中。点击连接“随机数”(4–14)和“设置属性”的线,将两者分开,这样我们就可以把“数值相加”放进去。将“数值相加”连接到“随机数”,再将“设置属性”连接到“数值相加”。打开“数值相加”的属性,将“随机数”的输出(行为右上角)放入第一个输入框,并在第二个框中输入 8。
我们要在现有悬崖上方生成第二座倒置的悬崖。这样可以让新悬崖始终比另一座高 8 米,为飞机留出穿过两座悬崖之间的空间。接着,进入“对象”选项卡,添加另一个“设置属性”行为。将它连接到“数值相加”,并打开属性。将“属性键”设为 Cliff Top pos,“属性值”设为“数值相加”的输出(行为右上角)。
不过,这样做仍然看不出任何变化。首先,我们需要返回编辑器并选中悬崖。打开属性后,找到对象菜单(对象属性中)的第二个图标(两个重叠的方框或纸张)。这是复制按钮。点击后,我们现在就有两座悬崖了。
打开新悬崖的行为。你会发现行为也被复制了,这会让事情简单很多。打开第二个“获取属性”的属性(也就是连接到“移动到点”的那个),将“属性键”改为 Cliff Top pos。
返回编辑器,选中悬崖后,你应该会在右上方看到一个圆圈中的弧形箭头图标,两端各有一个点。这是旋转工具。我们要将悬崖旋转 180 度,让它朝下。不过直接使用旋转工具,很难精确旋转 180 度。我们需要打开吸附功能。
启用网格后,吸附功能会自动开启。网格工具位于左侧工具栏中,在屏幕分辨率下方。点击它,然后旋转悬崖,直到它上下颠倒。(另外,你也可以在对象属性中的“变换”选项卡里旋转对象。)
这部分就快完成了。返回 Game Logic,找到 Initial Cleanup 行为包。打开“对象”分类,再添加一个“销毁对象”行为,将它连接到行为包,并把目标设为新悬崖。
最后,我们需要添加第二个“在区域生成”,让这座悬崖也能正常工作。为了节省时间,只需复制现有的“在区域生成”,将它连接到“开启行为”(Calculate Positions),并将目标设为新悬崖。
点击播放进行测试。
你的飞机可能太大,无法安全地穿过两座悬崖之间。如果是这样——我的飞机就是如此——我们来快速调整一下。进入编辑器并选中飞机。在属性底部,点击四个尖角的箭头,打开“变换”属性。在“缩放”部分,点击断开的链条图标。这样会锁定等比例缩放,修改一个数值时另一个数值也会随之改变。
虽然我们可以拖动对象的角来手动缩放,但在“变换属性”中调整会更准确、更简单。锁定等比例缩放后,点击 X 轴输入框并输入 50。这样飞机尺寸就会缩小一半。点击播放再次测试。现在飞机应该能安全地穿过两座悬崖之间。
现在我们已经有一款可以玩的游戏了!不过,只是穿过悬崖还不够有趣。为了给玩家一些动力,接下来我们要在游戏中添加得分。
添加得分:
为什么要添加得分?这是游戏中历史最悠久、最有效的激励方式之一。分数能让玩家不断回来玩你的游戏。谁不想努力刷新最高分呢?我们之后还会添加更多激励内容,比如根据分数获得奖牌,不过那是后面的事了。
那么,我们要如何计算分数呢?很简单,我们会创建一个传感器,在玩家成功穿过悬崖时检测到这一情况,然后给分数加一。做法与创建上方悬崖类似。我们要创建一个空对象(不希望玩家看到它,只需要游戏检测到飞机穿过传感器即可),并添加到已有行为中,让传感器和悬崖一起生成,而且始终处于相对固定的位置。
首先,在编辑器中选中 Game Logic,并打开对象属性中的“属性”选项卡(四条堆叠的横线)。创建一个新属性,命名为 Cliff Score pos。接下来进入行为界面,找到 Calculate Positions 行为包。
现在我们要添加“数值相减”,计算传感器相对于上方悬崖的位置。首先,按住连接“设置属性”和“数值相加”的线,将它们分开。
然后打开“逻辑”分类,拖入“数值相减”行为。将它连接到“数值相加”,然后把“设置属性”连接到“数值相减”。现在,将“数值相加”的输出拖到“数值相减”的第一个输入框,并在第二个框中输入 4。接下来进入“对象”选项卡,添加一个新的“设置属性”。将它连接到“数值相减”,然后将“属性键”设为 Cliff Score pos,“属性值”设为“数值相减”的输出。
现在返回主编辑器,创建传感器对象。点击烧杯并选择“空对象”。然后在它的属性中打开“变换”选项卡(四个箭头),将缩放设为 50x、350y。
现在打开传感器的行为。它与悬崖的设置非常相似(两者需要一起生成和移动),所以你也可以参考悬崖的设置。
首先,从“对象”分类中添加“获取属性”行为,并在属性中将目标对象设为 Game Logic,“属性键”设为 Speed。进入“逻辑”选项卡,添加“数值相乘”行为并将它连接到“获取属性”。在属性中,将“获取属性”的输出(右上角)设为第一个输入值,并将它乘以 -1。
然后进入“物理”选项卡,添加“设置速度”并将它连接到“数值相乘”。在属性中,将 X 值设为“数值相乘”的结果(同样是右上角的输出),Y 值设为 0。
现在从“对象”分类中再添加一个“获取属性”,同样在属性中将目标对象设为 Game Logic,并将“属性键”改为 Cliff Score pos。接着在“变换”分类下打开“高级”选项卡,添加“移动到点”。将 X 位置设为 41,Y 位置设为“获取属性”输出(Cliff Score pos)。这样就能确保传感器始终位于悬崖缺口之后,并将持续时间设为 0。
如果你不太确定怎么做,可以返回悬崖的行为界面进行核对。这里的设置几乎完全相同。
返回 Game Logic 的行为界面,找到生成器行为。我们需要为传感器添加一个新的“在区域生成”。选中现有的某个“在区域生成”,打开行为属性,然后在侧边菜单中点击重叠方框图标,将它复制。接着将目标对象(对象 A)从悬崖改为空对象。
最后,我们要将传感器添加到 Initial Cleanup 行为包中。和之前一样,添加“销毁对象”并将它连接到行为包。打开它的属性,将目标设为我们的空对象。
完成后,下一步是创建一个事件,用于在飞机得分时触发。这意味着我们需要创建一个行为,在飞机穿过传感器时进行检测,然后增加分数计数器。
首先返回传感器对象并打开行为。打开“对象”分类,添加“发生碰撞”行为。将碰撞对象 B 设为飞机。这样做是因为如果使用标签,就必须创建标签;如果所有对象都使用标签,事情会变得有些复杂。然后进入“自定义”分类,添加“广播消息”并将它连接到“发生碰撞”。将消息的“事件键”设为 Did Score。
现在我们需要一种显示分数的方式,因此要创建一个标签。
返回主编辑器并切换到 Scene UI 图层,然后点击停靠栏中的烧杯。选择“标签”,并将它移到游戏区域上方中央。将字号设为 120 pt(你可能需要调整对齐方式才能看到文字),再添加 4 pt 的黑色描边(确保将不透明度调到最大)。然后点击三个互相交叠的彩色圆圈来更改颜色。在新弹出窗口的顶部,你会看到颜色代码。输入 9B8766FF。
接下来,我们需要更改字体。我们要使用 Futura Condensed Extra Bold 字体。要获取该字体,需要快速导入一下。打开 Score 属性,点击显示大号 Helvetica 字样的方框,打开素材浏览器。在左侧找到“导入”并点击,打开新窗口。然后点击“系统字体”。向下滚动,或者点击右侧的 F,找到 Futura- Condensed Extra Bold。点击它,再点击右上角的“完成”。该字体现在应该会出现在素材浏览器中。只需点击它即可应用。最后,我们来更改游戏中显示的文字。在文本框中删除 Label,然后输入 0。
打开新标签的行为,进入“自定义”分类。添加“接收消息”,并将“事件键”设为 Did Score。然后进入“UI”分类,找到“添加到分数”行为并将它连接到“接收消息”。
点击播放,看看你能获得多少分!
最高分:
现在,我们应该保存最高分,因为目前关闭游戏后,分数就会丢失。最高分也能提升游戏的重玩价值。玩家更有可能再次回来游玩,并努力打破自己的纪录。
返回 Game Logic 并打开行为界面(别忘了切换回 Main 图层,或者你保存 Game Logic 的图层)。打开“自定义”分类,添加一个新的“接收消息”,将“事件键”设为 Did Start。接下来向下滚动到“永久存储”部分,找到“从文件加载”并将它连接到“接收消息”。
打开“从文件加载”的属性,将“默认值”设为 0。“键类型”暂时先不用管,我们现在不需要设置它。
接下来,再添加一个“接收消息”行为,并将“事件键”设为 Did Lose。这样,玩家结束一局游戏时就会更新存档。打开“UI”分类,添加“获取标签”行为,并将它连接到 Did Lose 对应的“接收消息”。将对象设为我们的分数标签(选择时可能需要切换图层)。然后进入“逻辑”分类,添加“如果”行为并将它连接到“获取标签”。将“获取标签”的输出放入“如果”行为的第一个输入框,再将“从文件加载”的输出放入第二个输入框。然后将中间的条件从“等于”改为“大于”(“>”符号)。
这样做是因为只有当当前分数高于之前保存的分数时,我们才希望保存它。现在我们需要真正保存这个数值。在“自定义”分类中,向下滚动到“永久存储”部分,找到“保存到文件”并将它连接到“如果”行为。在属性中,将“键类型”设为“现有”。然后点击“选择键”,在新窗口中点击 + 号并输入 Highest Score。现在我们已经创建了一个新键,可以通过“从文件加载”来引用它。接下来,将“要保存的值”设为“获取标签”的输出。
返回“从文件加载”,打开属性,将“键类型”设为“现有”,“选择键”设为 Highest Score。
我们还应该保存当前分数,以便之后调用。
在“获取标签”下方添加一个新的“保存到文件”。打开属性,将“键类型”设为“现有”。点击“选择键”,再点击 + 图标。输入 Previous Score,并将“要保存的值”设为“获取标签”的输出。
接下来,我们将调整 Game Over 画面,显示分数、奖牌等内容。
Game Over 画面:
到目前为止,游戏基本已经完成。剩下的主要工作是设置一个合适的 Game Over 画面,除此之外,其他改进都只是润色。在这个画面中,我们要显示玩家的当前分数和最高分,加入一个小小的成就提示,并添加重新开始按钮。
好消息是,我们不必从头创建 Game Over 画面,因为我们已经在使用 hyperPad 默认创建的叠加层。不过,我们需要稍微美化一下,因为目前它太单调、太无聊了。
要访问叠加层,我们需要打开“场景菜单”。在主编辑器中,点击左上角的三条堆叠横线即可。这里会显示游戏中的所有场景列表(目前我们只有一个场景)。在底部你会看到一个名为“叠加层”的选项卡。点击它,就能看到 hyperPad 默认创建的两个叠加层:Pause Menu 和 Game Over。点击 Game Over,即可切换到并加载该场景。
加载后,你会看到一个相当简单的场景:黑色背景上有一些文字。

