Navigation

    CreatiCode Scratch Forum

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • CreatiCode

    三维 - 化身与物体互动(难度:4)

    小教程
    1
    1
    261
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • info-creaticode
      CreatiCode last edited by admin

      介绍

      在许多游戏中,玩家控制自己的化身与场景内的其他物体交互,比如撞到墙上或者拾取奖励物品。本教程将会演示三种方法:射线投射、包围盒和距离测量。

       
       

      第 1 步 - 重做起始项目

      这是为你分享的一个起始项目:https://play.creaticode.cn/projects/4a308d8eb17ad7ae526cffb4

      请改编这个项目,作为你自己的项目。

      这个项目包含了玩家可以按键控制的数字人化身,以及添加一些其他物体的代码: 一条通往平台的斜坡,皇冠和金币,以及一个圆形目标区域。

      ed5c4340-146e-451a-a0ac-39b4cf2d9c05-image.png

       
       

      第 2 步 - 基于射线投射检测与平台的碰撞

      目前,玩家的化身无法行走在斜坡或平台上。相反,它将穿过斜坡。

      g5.gif

       

      要修复这个问题,我们可以打开基于射线投射的碰撞。在 “化身” 角色中插入以下积木 (你可以通过搜索 “碰撞” 来找到这个积木):

      686f4db6-0c71-43d1-b6a0-dc675231789a-image.png

       
      注意正确设置如下参数:

      • 它是 “不可穿过的” 碰撞,这意味着化身将在产生碰撞时停止;
      • 碰撞目标是 "平台” 角色,所以化身只会与在 “平台” 中创建的物体发生碰撞,也是斜坡和平台。
      • 精度是 “下方和前方”,这样的话化身添加了两个感应射线,一个向下指向地面,一个在脚面高度指向前方。
      • “调试” 选项设置为 “是”,所以我们可以看到射线和碰撞盒子。

       
      当我们再次运行项目时,我们可以看到感应射线和一个碰撞盒子(黄色的盒子),这是三维引擎用来代表化身身体的形状。但是这里还有个问题:黄色盒子位于角色底部,并且感应射线在地面下方。

      g3.gif

       

      这是因为所有化身和模型的位置原点都在其身体的底部中点,而不是整个身体的中心点。要解决这个问题,我们只需要添加一个 “z 位移”, 将黄色盒子向上移动半个化身高度,即 100 / 2 = 50。

      409d4e82-efc4-4a84-ac15-6be9146fe7f4-image.png

       
      现在我们可以看到黄色碰撞盒子和 2 个感应射线都在正确的位置了:

      g4.gif

       
       

      第 3 步 - 跑上斜坡

      现在我们尝试让角色跑上斜坡时,会看到这个:

      g6.gif

       
      好消息是碰撞检测已经起作用了,化身已经“知道”有斜坡,不再穿过它。坏消息是化身被卡住了,因为前向的射线报告说被阻挡了。

      要解决这个问题,我们需要将“精度”更改为“低”,这样会在所有6个方向上安装6个射线,并将前向的射线提高到身体中心的高度。

      3add0e9b-d021-4368-bbe6-5b660e6b35a3-image.png

       

      g7.gif

       
      现在我们的化身能够跑上坡了。这是因为前向射线与前方坡面的距离更大,所以它不再报告前方被坡面阻挡了。

      g1.gif

       
      请注意,如果你使用“移动到 X/Y/Z 位置”积木来移动化身,它仍然会穿过斜坡。你必须使用“设置速度”积木来配合基于射线投射的碰撞。

       
       

      第 4 步 - 修复动画和运动

      现在的问题是角色在坡道上移动时不会停下来,而且一直显示“跳在空中”的动画。

      这是因为程序仍然使用化身的“z位置”来测试它是否在空中,所以化身在斜坡上时候就一直以为它在跳跃。既然我们已经打开了基于射线投射的碰撞检测,我们其实可以检查化身是否脚踩在地面或其他物体上。

      在化身角色中,下滑找到“处理按键”积木的定义,并进行以下更改,这样当化身下方没有任何障碍物时,我们将显示跳跃动画。

      23ba563f-0d13-4f42-9182-c4e70280e271-image.png

       

      现在动画已修复,而且化身也可以停在斜坡上了:

      g2.gif

       
       

      第 5 步 - 与皇冠碰撞

      现在让我们继续下一个任务:使化身与平台上的皇冠发生碰撞。有几种方法可以做到这一点。我们将首先尝试使用基于射线的碰撞检测。

      我们需要进行两个代码更改:

      首先,在化身角色中,我们需要打开化身和“物体”角色之间的“可穿过的”碰撞,因为我们不希望化身被皇冠阻挡。

      b93ea388-07a1-418b-a5df-bb24aeb27d78-image.png

       
      接下来,在“物体”角色中,我们需要使用"当与化身碰撞时"积木来处理与“化身”的碰撞事件。由于在这个角色中创建了2个物体,皇冠和金币,与化身发生碰撞的那个物体会自动被选择为当前的"角色物体"。我们可以通过打印角色物体的名称来验证这一点。

      1a742210-75d6-4050-b323-5f940dd50043-image.png

       
      现在,当化身撞上皇冠时,我们在控制台面板中看到打印的信息。它说“物体”角色打印了一条信息:“a”。这正是与化身发生碰撞的皇冠的名称。

      g4.gif

       

      c88a5136-bd93-44e3-ae59-9bed65a95346-image.png

       
       

      第 6 步 - 删除皇冠

      现在我们知道与化身相撞的物体的名称是“a”,我们可以方便地将其删除,就好像化身已经获得了皇冠一样。

      66637081-8af1-4177-a78a-9092202bbe46-image.png

       
      我们甚至不需要指定要删除的物体的名称,因为在发生碰撞时,皇冠已被选为"角色物体"。现在,当化身碰到它时,皇冠将被删除:

      g5.gif

       
       

      第 7 步 - 用射线碰撞方法收集金币?

      现在,如果我们尝试移动角色来收集金币,我们会发现它不起作用:

      g6.gif

       
      原因是我们使用的是基于射线的方法,所以只有当射线触碰到目标物体时,化身才会与物体产生相撞。在这个场景里,金币位于前向射线的上方,所以不会触发碰撞事件。它也不会与化身指向上方的射线发生碰撞,因为化身没有上升的速度。如果我们让化身跳一下,那么它的向上的射线将触发碰撞事件:

      g7.gif

       
      显然,这不是一个很好的解决方案。我们需要让化身在碰到金币时就删除掉金币。我们下一步换到另一种方法。

       
       

      第 8 步 - 显示边界盒子

      三维场景中的每个物体都有一个隐形的“边界盒子”,这是一个包裹整个物体的盒子。要显示物体的边界盒子,可以添加“显示边界盒子”积木。

      在“化身”角色中,让我们取消与“物体”角色的碰撞,并隐藏碰撞射线。然后让我们添加“显示边界盒子”积木:

      e09f7c32-61c7-42bb-8fe2-0538f7413919-image.png

       
      你将在角色周围得到一个白色框架:

      g8.gif

       
      在“物体”角色中,删除“当与化身碰撞时”的事件处理,并显示皇冠和金币的边界盒子:

      8ad1d57e-3ed9-4533-99db-bb6c35c3e0bf-image.png

       
      现在你可以看到这两个物体的边界盒子:

      g9.gif

       
       

      第 9 步 - 检测边界盒子是否重叠

      每个物体或者化身的外形可以非常复杂,所以比起检查它们的实际形状是否重叠,计算它们的边界盒子是否重叠要快得多。我们可以这样要求游戏引擎:在化身的边界盒子与“物体”角色中的任何物体重叠时,广播一个消息给我们处理。

      首先,在“物体”角色中,让我们创建一个名为“碰到物体”的新消息,并将附加的信息存储在变量“信息”中(这个变量已经为你创建好了)。我们可以这样打印出“信息”的内容:

      d4ff8a0f-2d21-42e6-8b53-722ad5eab706-image.png

       

      接下来,在“化身”角色中,添加这个积木,在化身与“物体”角色的物体重叠时广播“碰到物体”的消息。请注意,“p”是化身的名称,“所有物体”是一个特殊参数值,表示“物体”角色中的所有物体都可以被碰到。

      4836422e-fc42-4bd4-9313-5f0a87e53b48-image.png

       
      现在,当化身碰到皇冠时,“信息”变量将包含以下信息:“p,a”。这是告诉我们物体“p”正在与物体“a”重叠。

      c54bc0c2-e57d-41ed-a300-74debbdae3e7-image.png

       
       

      第 10 步 - 删除被触碰的物体

      现在,我们已经找到了感知化身是否触碰王冠或者金币的另一种方法。这样的话,我们可以在“物体”角色中用这个名称来删除该物体:

      86e37ca5-789e-4e24-9073-cab2c22f0f87-image.png

       
      我们使用“分割”积木,通过逗号分隔符将“信息”变量的内容"p,a"拆分为两部分,第2部分就是名称“a”。这样的话,我们可以使用这个个名称来删除对应的物体。当化身碰到金币时,“信息"变量的内容将变成"p,c",那么第2部分就是“c”,即金币物体的名字。

      g10.gif
       
      请注意,现在我们可以成功检测到金币了,因为化身的边界盒子会与金币的边界盒子重叠。 比起使用碰撞射线,这个重叠方法对于检测小物体更好用,因为两个边界盒子的任何部分的重叠都可以被检测到。

       
       

      第 11 步 - 使用边界盒子检测目标区域

      对于我们的最后一个任务,我们将尝试检测化身是否到达了圆形的目标区域。由于目标区域是一个薄薄的圆柱体,它不会被前向的射线传感器检测到。因此,让我们尝试使用边界盒子重叠方法。

      首先,在“化身”角色中,添加一个新的消息处理程序来接收“碰到目标”的消息。当收到这个消息时,我们将使化身停止移动。我们可以停止所有其他代码积木,并将化身的前进速度设置为零。然后我们让化身显示“胜利”的动画。请注意,起始项目已经为你的角色添加了“胜利”动画。

      475eac6d-500b-4365-a122-f491190babe4-image.png

       
      其次,还是在“化身”角色中,当化身的边界盒子与目标物体的边界盒子重叠时,广播“碰到目标”消息。

      3ea2dc4c-7568-4903-bd30-9cf2d789691d-image.png

       
      现在,当化身碰到目标区域的边界盒子时,它将立即停止:

      t1.gif

       
       

      第 12 步 - 关于物体之间的距离

      当我们使用边界盒子检查目标区域时,存在一些小问题。首先,化身一旦碰到目标区域的边缘就会停下来,而不是在目标的中心。另外,由于边界盒子比目标区域本身要大,所以化身可能会卡在边界盒子的一个方角处:

      t2.gif
       

      此外,如果每个动画帧都需要计算2个边界盒子是否重叠,这还是需要耗费不少的计算时间的,在稍慢的计算机上可能会让动画变得不够流畅。

      为了解决这些问题,我们可以尝试第3种方法:我们可以简单地计算化身和目标之间的距离,如果该距离小于某个阈值,则判定化身已经到达了目标区域。

      请注意,当我们测量两个物体之间的距离时,我们是指它们的位置之间的距离。对于像圆柱体这样的简单形状,其位置是其中心点的位置。对于模型或化身,其位置是其底部中心点的位置。

      例如,下面的图片中,目标区域和角色之间的距离是两个红点之间的距离:

      t3.gif

       
       

      第 13 步 - 使用距离检测目标区域

      为了使用距离测量来检查化身是否到达目标位置,我们需要删除用于检查边界盒子的积木,并将其替换为距离检测积木:

      171b7211-9c2e-4a45-b750-e7d8f749ae79-image.png

       
      注意,我们正在检查“3D”距离,这考虑到两个物体的X/Y/Z位置。如果我们选择“2D”(二维),那么Z位置将被忽略。那样的话,即使化身站在目标正下方的草地上,它们之间的 2D 距离也可能会很小。

      我们使用30的阈值,这样当距离小于30时,游戏引擎会自动广播"碰到目标"的消息。

      现在,“碰到目标”消息只有在角色更接近目标区域中心时才会发送。

      t4.gif

       
       

      总结

      总结起来,你应该根据你要解决的问题来决定哪种方法适合你:

      1. 基于射线的方法非常适用于检测那些阻止化身移动的障碍物,例如墙壁、平台、斜坡和楼梯。当障碍物太小而无法被传感器射线检测到时,这个方法就不是很适合。
      2. 对于较小的物体(例如金币或装备),我们可以检查化身的边界盒子是否与这些物体的边界盒子有重叠。这个方法虽然需要一定的计算时间,但是更加准确。
      3. 如果我们只需要知道化身是否靠近另一个物体,还可以使用基于距离的方法。计算两点之间的距离比前两个方法要快得多。

      请注意,即使玩家是在驾驶汽车或飞机,而不是控制化身,我们还是可以使用类似的方法的。

      1 Reply Last reply Reply Quote 0
      • First post
        Last post