三维 - 化身与物体互动(难度:4)
-
介绍
在许多游戏中,玩家控制自己的化身与场景内的其他物体交互,比如撞到墙上或者拾取奖励物品。本教程将会演示三种方法:射线投射、包围盒和距离测量。
第 1 步 - 重做起始项目
这是为你分享的一个起始项目:https://play.creaticode.cn/projects/4a308d8eb17ad7ae526cffb4
请改编这个项目,作为你自己的项目。
这个项目包含了玩家可以按键控制的数字人化身,以及添加一些其他物体的代码: 一条通往平台的斜坡,皇冠和金币,以及一个圆形目标区域。
第 2 步 - 基于射线投射检测与平台的碰撞
目前,玩家的化身无法行走在斜坡或平台上。相反,它将穿过斜坡。
要修复这个问题,我们可以打开基于射线投射的碰撞。在 “化身” 角色中插入以下积木 (你可以通过搜索 “碰撞” 来找到这个积木):
注意正确设置如下参数:- 它是 “不可穿过的” 碰撞,这意味着化身将在产生碰撞时停止;
- 碰撞目标是 "平台” 角色,所以化身只会与在 “平台” 中创建的物体发生碰撞,也是斜坡和平台。
- 精度是 “下方和前方”,这样的话化身添加了两个感应射线,一个向下指向地面,一个在脚面高度指向前方。
- “调试” 选项设置为 “是”,所以我们可以看到射线和碰撞盒子。
当我们再次运行项目时,我们可以看到感应射线和一个碰撞盒子(黄色的盒子),这是三维引擎用来代表化身身体的形状。但是这里还有个问题:黄色盒子位于角色底部,并且感应射线在地面下方。这是因为所有化身和模型的位置原点都在其身体的底部中点,而不是整个身体的中心点。要解决这个问题,我们只需要添加一个 “z 位移”, 将黄色盒子向上移动半个化身高度,即 100 / 2 = 50。
现在我们可以看到黄色碰撞盒子和 2 个感应射线都在正确的位置了:
第 3 步 - 跑上斜坡
现在我们尝试让角色跑上斜坡时,会看到这个:
好消息是碰撞检测已经起作用了,化身已经“知道”有斜坡,不再穿过它。坏消息是化身被卡住了,因为前向的射线报告说被阻挡了。要解决这个问题,我们需要将“精度”更改为“低”,这样会在所有6个方向上安装6个射线,并将前向的射线提高到身体中心的高度。
现在我们的化身能够跑上坡了。这是因为前向射线与前方坡面的距离更大,所以它不再报告前方被坡面阻挡了。
请注意,如果你使用“移动到 X/Y/Z 位置”积木来移动化身,它仍然会穿过斜坡。你必须使用“设置速度”积木来配合基于射线投射的碰撞。
第 4 步 - 修复动画和运动
现在的问题是角色在坡道上移动时不会停下来,而且一直显示“跳在空中”的动画。
这是因为程序仍然使用化身的“z位置”来测试它是否在空中,所以化身在斜坡上时候就一直以为它在跳跃。既然我们已经打开了基于射线投射的碰撞检测,我们其实可以检查化身是否脚踩在地面或其他物体上。
在化身角色中,下滑找到“处理按键”积木的定义,并进行以下更改,这样当化身下方没有任何障碍物时,我们将显示跳跃动画。
现在动画已修复,而且化身也可以停在斜坡上了:
第 5 步 - 与皇冠碰撞
现在让我们继续下一个任务:使化身与平台上的皇冠发生碰撞。有几种方法可以做到这一点。我们将首先尝试使用基于射线的碰撞检测。
我们需要进行两个代码更改:
首先,在化身角色中,我们需要打开化身和“物体”角色之间的“可穿过的”碰撞,因为我们不希望化身被皇冠阻挡。
接下来,在“物体”角色中,我们需要使用"当与化身碰撞时"积木来处理与“化身”的碰撞事件。由于在这个角色中创建了2个物体,皇冠和金币,与化身发生碰撞的那个物体会自动被选择为当前的"角色物体"。我们可以通过打印角色物体的名称来验证这一点。
现在,当化身撞上皇冠时,我们在控制台面板中看到打印的信息。它说“物体”角色打印了一条信息:“a”。这正是与化身发生碰撞的皇冠的名称。
第 6 步 - 删除皇冠
现在我们知道与化身相撞的物体的名称是“a”,我们可以方便地将其删除,就好像化身已经获得了皇冠一样。
我们甚至不需要指定要删除的物体的名称,因为在发生碰撞时,皇冠已被选为"角色物体"。现在,当化身碰到它时,皇冠将被删除:
第 7 步 - 用射线碰撞方法收集金币?
现在,如果我们尝试移动角色来收集金币,我们会发现它不起作用:
原因是我们使用的是基于射线的方法,所以只有当射线触碰到目标物体时,化身才会与物体产生相撞。在这个场景里,金币位于前向射线的上方,所以不会触发碰撞事件。它也不会与化身指向上方的射线发生碰撞,因为化身没有上升的速度。如果我们让化身跳一下,那么它的向上的射线将触发碰撞事件:
显然,这不是一个很好的解决方案。我们需要让化身在碰到金币时就删除掉金币。我们下一步换到另一种方法。
第 8 步 - 显示边界盒子
三维场景中的每个物体都有一个隐形的“边界盒子”,这是一个包裹整个物体的盒子。要显示物体的边界盒子,可以添加“显示边界盒子”积木。
在“化身”角色中,让我们取消与“物体”角色的碰撞,并隐藏碰撞射线。然后让我们添加“显示边界盒子”积木:
你将在角色周围得到一个白色框架:
在“物体”角色中,删除“当与化身碰撞时”的事件处理,并显示皇冠和金币的边界盒子:
现在你可以看到这两个物体的边界盒子:
第 9 步 - 检测边界盒子是否重叠
每个物体或者化身的外形可以非常复杂,所以比起检查它们的实际形状是否重叠,计算它们的边界盒子是否重叠要快得多。我们可以这样要求游戏引擎:在化身的边界盒子与“物体”角色中的任何物体重叠时,广播一个消息给我们处理。
首先,在“物体”角色中,让我们创建一个名为“碰到物体”的新消息,并将附加的信息存储在变量“信息”中(这个变量已经为你创建好了)。我们可以这样打印出“信息”的内容:
接下来,在“化身”角色中,添加这个积木,在化身与“物体”角色的物体重叠时广播“碰到物体”的消息。请注意,“p”是化身的名称,“所有物体”是一个特殊参数值,表示“物体”角色中的所有物体都可以被碰到。
现在,当化身碰到皇冠时,“信息”变量将包含以下信息:“p,a”。这是告诉我们物体“p”正在与物体“a”重叠。
第 10 步 - 删除被触碰的物体
现在,我们已经找到了感知化身是否触碰王冠或者金币的另一种方法。这样的话,我们可以在“物体”角色中用这个名称来删除该物体:
我们使用“分割”积木,通过逗号分隔符将“信息”变量的内容"p,a"拆分为两部分,第2部分就是名称“a”。这样的话,我们可以使用这个个名称来删除对应的物体。当化身碰到金币时,“信息"变量的内容将变成"p,c",那么第2部分就是“c”,即金币物体的名字。
请注意,现在我们可以成功检测到金币了,因为化身的边界盒子会与金币的边界盒子重叠。 比起使用碰撞射线,这个重叠方法对于检测小物体更好用,因为两个边界盒子的任何部分的重叠都可以被检测到。
第 11 步 - 使用边界盒子检测目标区域
对于我们的最后一个任务,我们将尝试检测化身是否到达了圆形的目标区域。由于目标区域是一个薄薄的圆柱体,它不会被前向的射线传感器检测到。因此,让我们尝试使用边界盒子重叠方法。
首先,在“化身”角色中,添加一个新的消息处理程序来接收“碰到目标”的消息。当收到这个消息时,我们将使化身停止移动。我们可以停止所有其他代码积木,并将化身的前进速度设置为零。然后我们让化身显示“胜利”的动画。请注意,起始项目已经为你的角色添加了“胜利”动画。
其次,还是在“化身”角色中,当化身的边界盒子与目标物体的边界盒子重叠时,广播“碰到目标”消息。
现在,当化身碰到目标区域的边界盒子时,它将立即停止:
第 12 步 - 关于物体之间的距离
当我们使用边界盒子检查目标区域时,存在一些小问题。首先,化身一旦碰到目标区域的边缘就会停下来,而不是在目标的中心。另外,由于边界盒子比目标区域本身要大,所以化身可能会卡在边界盒子的一个方角处:
此外,如果每个动画帧都需要计算2个边界盒子是否重叠,这还是需要耗费不少的计算时间的,在稍慢的计算机上可能会让动画变得不够流畅。
为了解决这些问题,我们可以尝试第3种方法:我们可以简单地计算化身和目标之间的距离,如果该距离小于某个阈值,则判定化身已经到达了目标区域。
请注意,当我们测量两个物体之间的距离时,我们是指它们的位置之间的距离。对于像圆柱体这样的简单形状,其位置是其中心点的位置。对于模型或化身,其位置是其底部中心点的位置。
例如,下面的图片中,目标区域和角色之间的距离是两个红点之间的距离:
第 13 步 - 使用距离检测目标区域
为了使用距离测量来检查化身是否到达目标位置,我们需要删除用于检查边界盒子的积木,并将其替换为距离检测积木:
注意,我们正在检查“3D”距离,这考虑到两个物体的X/Y/Z位置。如果我们选择“2D”(二维),那么Z位置将被忽略。那样的话,即使化身站在目标正下方的草地上,它们之间的 2D 距离也可能会很小。我们使用30的阈值,这样当距离小于30时,游戏引擎会自动广播"碰到目标"的消息。
现在,“碰到目标”消息只有在角色更接近目标区域中心时才会发送。
总结
总结起来,你应该根据你要解决的问题来决定哪种方法适合你:
- 基于射线的方法非常适用于检测那些阻止化身移动的障碍物,例如墙壁、平台、斜坡和楼梯。当障碍物太小而无法被传感器射线检测到时,这个方法就不是很适合。
- 对于较小的物体(例如金币或装备),我们可以检查化身的边界盒子是否与这些物体的边界盒子有重叠。这个方法虽然需要一定的计算时间,但是更加准确。
- 如果我们只需要知道化身是否靠近另一个物体,还可以使用基于距离的方法。计算两点之间的距离比前两个方法要快得多。
请注意,即使玩家是在驾驶汽车或飞机,而不是控制化身,我们还是可以使用类似的方法的。