如何为敌方史莱姆创建人工智能

**注意:**本教程的完整项目文件可在本文末尾找到。
简介
在本教程中,我们将为一款平台类游戏创建一个令人信服的敌方史莱姆人工智能(AI)。我们将介绍 hyperPad 中一些更高级的功能和行为,因此本教程假设你已经对 hyperPad 编辑器有一些基本了解。如果你觉得需要进一步熟悉如何从头开始制作游戏,可以先查看完整指南 - 创建平台游戏教程。
为了让史莱姆看起来“聪明”,它不能只是在原地来回移动,还应该对周围环境有一定的感知能力。
听起来很有意思!不过,在开始之前,我们先明确一下敌方史莱姆应该如何行动:
- 史莱姆不会走路,而是向左或向右跳跃移动。
- 史莱姆会朝玩家所在的方向跳跃。
- 如果玩家离得太远,史莱姆就不会移动(待机)。
- 史莱姆接触玩家时会扣除玩家的生命值。
- 如果玩家跳到史莱姆头上,史莱姆就会被击败。
明确了目标之后,我们开始吧!
第 1 部分:项目设置
在本教程中,为了简单起见,我们将从头创建一个新项目。新建项目并将视图设置为“侧视图”,其他设置保持默认值即可。
创建好新项目后,前往 Asset Library,在资源商店中下载 hyperPad 的“Platformer Starter Pack”。(它是免费的!)
现在有了一些可用的资源,接下来放置一些地面方块并创建你的游戏世界。如果你还没有打开资源库,请前往 Asset Library,轻点“Downloads”,然后轻点“Platformer Starter Pack”。
下图中放置了一些地面方块(“Grass World”文件夹),并设置了一个背景(“Backgrounds”文件夹)。
现在场景已经准备就绪,接下来添加玩家和史莱姆对象。前往 Asset Library,打开“Downloads”文件夹,然后打开“Platformer Starter Kit”文件夹(如果它们尚未打开)。
我们将使用“Green Spaceman”作为玩家角色。轻点绿色太空人资源,查看它的所有动画循环。默认情况下,我们希望玩家只是站立不动,因此轻点“Stand”动画并将其放置到场景中。
在 Asset Library 的同一文件夹中,还有一个名为“Slime Pink”的动画角色。它非常适合用作史莱姆敌人!轻点史莱姆资源,选择“Move”动画,然后将史莱姆放置在场景中,与玩家角色一起。
到目前为止一切顺利!现在我们已经有了玩家对象和史莱姆对象,可以开始使用了。但如果现在运行项目,我们还无法与游戏进行任何互动。因此,我们需要创建一些逻辑,让游戏活起来。
第 2 部分:玩家控制
在为史莱姆敌人添加行为之前,我们先为绿色太空人设置玩家控制。
轻点绿色太空人,将它的物理模式从 Wall 更改为 Physical,这样玩家就可以自由移动。然后轻点“Behaviors”按钮,打开玩家角色的行为编辑器,以便添加控制逻辑。
在玩家角色的行为编辑器中,你应该已经能看到一个单独的播放动画行为。这个行为可以保留不动,但我们可以给它添加一些伙伴。
在交互部分中,任意放置一个摇杆控制行为和一个按钮跳跃行为。添加这两个行为后,玩家就可以进行控制了。不过,玩家还缺少动画效果。
轻点“Joystick Controlled”行为,将“Joystick Left Animation”设置为 Green Spaceman 资源中的“Walk”动画循环。“Joystick Right Animation”也进行相同设置。
现在玩家角色可以行走了,但跳跃时仍然没有动画。
轻点“Jump with Button”行为,将“Falling Animation”和“Jumping Animation”都更改为“Jump”动画循环。
现在运行游戏,我们就可以移动和跳跃了!接下来,我们来制作史莱姆敌人。
第 3 部分:史莱姆移动
正如本教程简介中所说,我们希望史莱姆朝玩家跳跃。为此,史莱姆需要知道玩家在游戏世界中的位置。因此,我们应该为玩家角色添加一个标签,这样行为就可以在任何场景中找到玩家角色。
轻点玩家角色,然后在属性视图底部选择“Tags”选项卡。在标签菜单顶部的文本框中输入“Player”,然后轻点旁边的添加(+)按钮。现在玩家角色就带有“Player”标签了。
和设置玩家角色时一样,轻点史莱姆,将它的物理模式从 Wall 更改为 Physics。然后轻点“Behaviors”按钮,打开史莱姆的行为编辑器。
在行为编辑器中,前往自定义行为部分,并将“Timer”行为拖到编辑器中。
轻点 Timer 行为,将其间隔设置为 2 秒。
这将作为史莱姆人工智能逻辑的起点。
思路是每隔 2 秒,史莱姆就会“思考”接下来要做什么,例如:要不要跳?如果决定跳,应该朝哪个方向跳?
接下来,前往变换行为部分,放置一个获取位置行为。轻点它,然后将目标设置为我们之前创建的“Player”标签:轻点属性视图底部的“Tags”选项卡,然后选择“Player”。现在将 Timer 连接到 Get Position 行为。
现在我们知道玩家在游戏世界中的位置了!要判断玩家在史莱姆的左边还是右边,我们还需要知道史莱姆自己在游戏世界中的位置。
再将一个 Get Position 行为拖到编辑器中。默认情况下,该行为已将目标设为史莱姆,因此除了将它连接到逻辑分支以外,我们不需要做其他设置。将获取玩家位置的 Get Position 连接到获取史莱姆位置的 Get Position。
**可选:**为了让流程更容易理解,我将 Get Position 行为重命名为更清楚的名称,以标明它们追踪的对象:“Get Position Player”和“Get Position Slime”。这一步不是必须的。如果你也想更改行为名称,可以轻点该行为,然后轻点属性视图最顶部的名称。
目前我们设置的逻辑是:每隔 2 秒,史莱姆就获取玩家角色和自身的位置。有了这些信息,我们就可以判断史莱姆应该向左还是向右跳。
在逻辑选项卡中,放置并连接一个 If 行为。在它的属性中,将第一个值设为第一个 Get Position(“Player”标签)的 x 位置:将该行为的输出值拖到 If 属性的字段中。第二个值设为第二个 Get Position(史莱姆)的位置。最后,将 If 行为的条件设置为“Is Less Than”(<)。
**注意:**对象的 x 位置表示该对象在游戏世界中沿 x 轴的位置。(左和右)
那么,这些设置代表什么呢?If 行为会检查玩家的 x 位置是否小于史莱姆的 x 位置。如果条件成立,它就会执行下一个已连接的行为。也就是说,如果玩家位于史莱姆的左侧,行为就会继续执行。
好了,现在我们已经设置好让史莱姆向左跳的逻辑,接下来就让史莱姆照着做吧!
在物理行为部分中,放置一个施加力行为并将它连接到 If 行为。在属性中,将力设置为:x = -0.5,y = 1。然后将倍率设置为一个较大的数值,例如 200。
现在,如果史莱姆发现玩家位于自己左侧,它就会向上跳(y = 1 × 200),同时稍微向左移动(x = -0.5 × 200)。
试试看!运行游戏并确认一切正常。只要玩家在史莱姆左边,你就会看到史莱姆每隔 2 秒向左跳一次。如果你把玩家移到史莱姆右边,它就会停止跳跃,直到玩家再次回到它的左边。
**注意:**如果史莱姆没有移动,请按照前面的步骤检查是否有遗漏。确认行为连接正确,并且史莱姆的物理模式设为 Physics(可移动),而不是 Wall(不可移动)。稍后我们也会修复史莱姆有时会侧翻或倒置的问题。
进展不错!如果史莱姆正如预期那样跳来跳去,我们就可以继续了。接下来完成它的移动行为,让它也能向右跳。
回到史莱姆的行为编辑器,复制 If 行为。将新复制的 If 行为拖到原 If 行为的右侧并与之对齐,这样它就会变成“Else If”行为。
再复制 Apply Force 行为,并将它连接到新的 Else If 行为。
在 Else If 的属性中,将条件从“Is Less Than”(<)改为“Is Greater Than”(>)。这样就会产生与第一个 If 相反的效果。如果第一个 If 条件不成立,它就会检查 Else If 是否成立。也就是说,如果玩家不在史莱姆左侧,它就会检查玩家是否在史莱姆右侧;如果成立,就会继续执行连接到 Else If 的行为。
现在,你的行为分支应该类似这样:
在第二个 Apply Force(Else If 下方)中,更改属性,将力设置为 x = 0.5,而不是 x = -0.5。这样史莱姆就会向右跳,而不是向左跳。
运行项目再试试看!现在史莱姆应该会朝着玩家所在的方向跳跃了。太棒了!
你可能在测试时注意到,如果撞到史莱姆,它有时会侧翻或倒过来。我们希望史莱姆保持直立,所以现在就来快速修复这个问题。
回到史莱姆的行为编辑器,前往 Transform 行为部分,将一个锁定旋转行为拖到编辑器中。无需将它连接到其他行为,因为我们希望史莱姆创建后立刻锁定旋转,所以保持原样即可。完成后,再试一次游戏。这次你会发现,把史莱姆撞翻要困难得多。
你可能还注意到史莱姆的动画播放得太快。如果是这样,请轻点史莱姆行为编辑器中的 Play Animation 行为,将每秒帧数调低。每秒 6 帧看起来效果不错。
不错!现在史莱姆不仅移动得很自然,看起来也很棒。大体上,史莱姆的移动逻辑已经完成。
不过,我们还希望只有玩家靠近时,史莱姆才会跳跃。这样,如果我们创建一个更大的世界,远处的史莱姆就不会立刻朝玩家跳来并发动攻击。下一部分中,我们将添加一个条件:如果玩家离得太远,就阻止跳跃逻辑执行。
第 4 部分:史莱姆待机
在这一部分中,我们将为史莱姆添加一些行为,让它在玩家离得太远时进入待机状态(也就是说不移动)。
为此,我们需要找到一种方法来测量史莱姆和玩家之间的距离。方便的是,有现成的行为可以完成这项工作!开始吧。
打开史莱姆的行为编辑器,从 Logic 部分拖入一个计算距离行为。在它的行为属性中,第一个对象已经设为史莱姆。对于第二个对象,打开 Tabs 菜单并选择“Player”标签。
执行此行为时,它会计算史莱姆到玩家之间的距离,单位为米。利用这个信息,我们可以检查玩家是否太远,例如查看距离是否超过某个数值。
从 Logic 部分再放置一个 If 行为,并将它连接在 Calculate Distance 行为下方。在 If 行为属性中,将第一个值设为 Calculate Distance 的输出值。将条件设为“Is Less Than”,第二个值设为 15。
这样,我们就可以检查玩家是否离得太远:如果史莱姆与玩家之间的距离小于 15 米,条件就成立。如果条件不成立,就代表玩家离得太远,If 行为不会执行下一个行为。
现在新的条件已经准备好可以使用了,断开上一部分中的 Get Position(史莱姆)和旧 If 行为,并为新条件腾出空间。断开行为时,轻点并按住行为之间的连接线即可。
放置好新的距离条件后,将 Get Position(史莱姆)连接到 Calculate Distance 行为,再将新的 If 行为连接到旧 If 行为。现在应该类似这样:
现在看起来有点复杂了,不过思路很简单:在检查史莱姆应该朝哪个方向跳之前,我们先检查史莱姆和玩家之间的距离是否小于 15 米。
如果玩家距离史莱姆不到 15 米,逻辑就会继续执行,并像往常一样判断应该朝哪个方向跳。如果玩家离得超过 15 米,逻辑就会停止执行,直到史莱姆下一次“思考”(2 秒后)。
试试游戏!如果你靠近史莱姆,它应该会开始朝你跳来;如果你走得太远,它就会停止移动,等你再次靠近。
现在史莱姆开始显得很有威胁了,不过它还缺少伤害玩家的能力。在本教程的下一部分中,我们将为玩家添加生命值条,并实现对玩家造成伤害的逻辑。
第 5 部分:攻击玩家
正如简介中所说,我们将通过让史莱姆接触玩家时造成伤害来实现攻击。首先,为了让史莱姆能够攻击玩家,我们需要给玩家添加生命值。
在主编辑器中,选择 Scene UI 图层,然后使用特殊对象按钮创建一个新对象。轻点“Health Bar”,为玩家创建一个生命值条。
由于它放置在 Scene UI 图层中,即使我们扩展游戏世界并让屏幕跟随玩家移动,它也会保持在屏幕的相同位置。
你可以将它放在屏幕上任何合适的位置。我把它放在了屏幕底部附近的中央。
为生命值条找好位置后,我们就可以添加扣除生命值的逻辑了。回到史莱姆所在的 Main 图层,再次打开它的行为编辑器。
在史莱姆行为中找一个空白位置,从 Object 部分拖入一个发生碰撞行为。在它的属性中,将第二个对象设为“Player”标签。
在 Custom 行为部分中,拖入一个广播消息行为,并将它连接在 Collided 行为下方。在 Broadcast Message 行为属性中,将 Event Key 设为“player hit”,并将值设为 -10。
**请记住:**事件键区分大小写!为简单起见,本教程将事件键设为小写。你也可以使用大写字母,但之后一定要记住哪些字母用了大写。
现在我们已经能够检测玩家何时应该扣除生命值了。当玩家与史莱姆碰撞时,会广播一个事件键为“player hit”、值为 -10 的消息。我们将用 -10 来告诉生命值条“增加” -10 点生命值;由于这个值是负数,因此会扣除 10 点生命值。
我们还需要为生命值条添加相应逻辑,现在就来设置。退出史莱姆的行为编辑器,然后在主编辑器中轻点 Scene UI 图层,再轻点生命值条。打开生命值条的行为编辑器。
在生命值条的行为编辑器中,从 Custom 部分拖入一个接收消息行为。在它的属性中,将 Event Key 设为“player hit”。(记住,它区分大小写!)
这个行为会监听玩家撞到史莱姆时发送的“player hit”消息。只要它检测到游戏中任意位置广播了“player hit”消息,就会执行。
接下来,在用户界面行为部分中添加一个增加生命值条数值行为,并将它连接在 Receive Message 行为下方。
在 Add to Health Bar 属性中,将 Receive Message 的输出值拖到“Value to add”字段中。这个值就是我们之前在史莱姆的 Broadcast Message 行为中设置的 -10。这样,如果我们希望其他敌人造成不同数值的伤害,只需更改广播的值,生命值条就会使用相应数值!
确保“Event On Full”关闭,“Event On Empty”开启。这意味着生命值条降到零时,会执行下一个行为。
在场景行为部分中,拖入一个加载叠加层行为,并将它连接到 Add to Health Bar 行为。
在 Load Overlay 设置中,将所选叠加层更改为“Game Over”。创建新项目时,系统会自动为你创建这个叠加层。
运行游戏试试看!现在,每当你碰到史莱姆时,它都会扣除生命值条中的生命值。当生命值条降到零,游戏就结束了。
太棒了!现在我们已经可以伤害玩家并让游戏结束了。
不过,总觉得有些不对劲。除了生命值条减少以外,玩家被击中时几乎没有得到其他反馈。
我们可以通过让玩家和史莱姆互相弹开来解决这个问题。这样既能清楚地表现出双方发生了碰撞,也能避免玩家因为快速连续撞到史莱姆而在短时间内受到过多伤害。
前往史莱姆的行为编辑器(可能需要先选择 Main 图层),在 Physics 部分拖入一个推动对象行为。将它连接在之前的 Broadcast Message 行为下方,然后打开它的属性。
在属性中,打开 Tags 选项卡并选择“Player”,将第二个对象设为“Player”标签。将 Force 值设为 200,Object A Multiplier 设为 0.25,Object B Multiplier 设为 1。
现在,玩家与史莱姆碰撞时,玩家会以 200 的力(1 × 200 的力)被推离史莱姆,而史莱姆则会以 50 的力(0.25 × 200 的力)被推离玩家。
我们的游戏开始有趣起来了!目前唯一的问题是史莱姆无敌,而玩家没有办法打败它。下一部分中,我们将实现玩家反击的方式。
第 6 部分:击败史莱姆
为了让玩家通过跳到史莱姆头上来攻击它,我们需要调整碰撞处理方式:史莱姆造成伤害时,忽略玩家的底部(也就是玩家的脚)。
打开史莱姆的行为编辑器,轻点上一部分创建的 Collided 行为。关闭“On Bottom”选项,这样当史莱姆与玩家碰撞箱的底部发生碰撞时,就会忽略这次碰撞。
现在,玩家跳到史莱姆身上时,史莱姆就不会伤害玩家了。我们希望这种情况下执行另一套逻辑。
选中 Collided 事件后,复制它,并反转新 Collided 行为中的所有选项,使得只有“On Bottom”事件开启。
这将作为玩家跳到史莱姆头上时的触发入口。
接下来,从 Object 行为部分拖入并连接一个销毁对象行为。默认情况下,它应该已经设置为销毁史莱姆对象。
现在运行游戏时,跳到史莱姆头上就能摧毁它了。不过,和之前被史莱姆击中时一样,这样的效果还不够令人满意。
就像上一部分中那样,我们再添加一个 Propel Object。复制玩家受伤逻辑中较早添加的 Propel Object 行为,并将它连接在 Destroy Object 行为下方。新行为的属性可以保持和原来的 Propel Object 一样。
现在运行游戏,跳到史莱姆头上时就会有很棒、令人满足的弹跳效果。
总结与练习
基本上就是这些!我们已经完成了简介中列出的所有目标:
- 史莱姆不会走路,而是向左或向右跳跃移动。完成!
- 史莱姆会朝玩家所在的方向跳跃。完成!
- 如果玩家离得太远,史莱姆就不会移动(待机)。完成!
- 史莱姆接触玩家时会扣除玩家的生命值。完成!
- 如果玩家跳到史莱姆头上,史莱姆就会被击败。完成!
如果你读到了这里,现在应该已经对如何赋予敌人一定的智能、让它们自行思考并做出决定有了不错的了解。做得好!
不过,还有很多可以改进的地方。试着独立完成以下练习:
- 玩家跳到史莱姆身上时,播放史莱姆的“hit/dead”动画。
- 史莱姆攻击玩家时,播放玩家的“hit”动画。
- 加入一些随机性,让史莱姆每次跳跃的距离有所不同。
本教程的完整项目文件可在此处下载:下载教程项目

