找回密码
 立即注册
查看: 619|回复: 0

[简易教程] Unity基础教程-物体运动(七)——移动地面(Going for a Ride)

[复制链接]
发表于 2020-11-25 09:35 | 显示全部楼层 |阅读模式
200+篇教程总入口,欢迎收藏:
本文重点内容:
1、创建可以动的平台
2、保持对连接主体的追踪
3、尝试保持相对关系
4、支持轨道连接点
这是有关控制角色移动的教程系列的第七部分。它解决了在运动中的地形上站立和导航的问题。
本教程是CatLikeCoding系列的一部分,原文地址见文章底部。
本教程使用Unity 2019.2.21f1编写。它还使用了ProBuilder包。
移动的时候,大多数物体仍然保持站立
1 几何体动画化
有很多种方法可以移动几何体。可以创建一个脚本来调整对象的Transform, 可以使用Unity的动画系统对其进行动画处理。还可以编写自己的playable graph并以此方式创建动画。或者我们可以依靠PhysX并让对象响应外力和碰撞而移动。但不管哪种方式,我们都必须确保在运动中的地形和障碍物与PhysX、我们的运动球体以及我们的轨道摄像机可以完美配合。
1.1 动画
在本教程中,我们将使用Unity的动画系统在编辑器中创建简单的动画。我们通过“Animation”窗口执行此操作,该窗口可以通过“Window/ Animation / Animation”打开。如果选择的对象还没有Animator组件,则窗口将显示一个按钮,以便让你添加该组件并立即为其创建新的动画。
为 up Down物体创建动画
我制作了一个简单的方形平台对象,名为Up Down,然后为其创建了一个新的动画剪辑,名为Up Down Animation。动画是一个新资产,但是按下“Create”按钮还会创建另一个资产,我将其重命名为“ Up Down Controller”。这是运行动画所需的动画控制器资产。它可以用来创建复杂的混合树和动画状态机,但是如果我们只需要一个动画剪辑,就不必处理它。我把它们都放在一个新的Animation文件夹中。
动画资产
添加到平台对象的Animator组件将自动设置为使用新的控制器资产。我们最初可以将其所有其他配置选项保留为默认值。为该对象提供一个启用了运动功能的刚体组件,因为它是动态PhysX对象。虽然这不是必要的,但可以确保所有交互均按预期进行。
Animator和刚体组件
要使动画剪辑执行某项操作,需要在场景中选择相关对象。“Animation”窗口将在时间轴控制按钮下方的左侧显示我们的动画剪辑。按下录制按钮(红点),然后在右侧的时间线栏中选择所需的时刻。你可以缩放以到达当前不可见的区域。然后,通过其检查器或在场景视图中调整对象的Transform。这将创建具有新配置的关键帧。
例如,我将两秒钟的Y位置从0更改为3,并在四秒钟将其设置回0。然后关闭录制。
带有关键帧的Animation窗口
现在就可以预览动画了。进入播放模式后还会自动以及循环播放。
在一个动画的平台上移动
默认情况下,Unity通过缓和过渡来平滑动画。您可以通过“Animation”窗口底部的切换选项从“Dopesheet”切换到“Curves”模式来精确的控制行为。
动画曲线,Y坐标为绿色
为什么不能移动动画对象?
如果对象正在播放更改其位置的动画,则该动画的位置将覆盖该对象的配置位置。你可以通过将动画对象变成另一个对象的子对象,然后将其移动到其他位置。
1.2 动画同步
当球体被向上推动并随着平台的垂直运动而下降时,我们的球体已经可以在平台上跳跃并随之移动。但是默认情况下,交互的时间并不正确。当将轨道摄像机的“Focus Radius”设置为零,使其随球体刚性移动时,这个现象非常明显。
正常的动画模式
事实证明,向上运动有点抖动,而向下运动则更糟,因为球体反复下降一小段距离,撞击平台,然后再次下降。发生这种情况是因为默认情况下,动画每帧更新一次,因此运动与PhysX不同步。通过将Animator组件的Update Mode设置为Animate Physics,我们可以设置动画来更新每个物理步长。
动画和物理同步
现在我们的球体在向下移动的时候可以附着在平台上。但平台的运动会像其他运动中的物理物体一样抖动,如果需要的话,可以通过设置它的刚体来解决。
插值平台运动
1.3 侧面移动
解决了垂直运动,我们还需要支持向其他方向运动的平台。因此,我用自己的动画剪辑和控制器制作了另一个平台,该动画剪辑和控制器沿X轴左右移动。
侧向移动的时候并没有吸附
我们的球体可以沿着平台的表面移动,但是当平台静止时,它忽略了平台的水平移动。其他PhysX对象确实会随平台一起拖动,但如果平台移动得太快的话,它们仍然会左右滑动。因为我们的球体没有任何抓地力,因此也不会受到拖拽。它的阻力系数为零,不然的话会干扰其他的物体。我们必须针对此问题提出解决方案。
2 连接主体
为了能够沿着其站立的表面移动,我们的球体首先需要意识到该表面。通常,这意味着球体可以随时与可能运动的另一个物体进行连接。第一步是跟踪此主体,我们将其称为“连接主体”。可能同时存在多个这样的主体,但是这种情况很少见,因此我们将自己限制为一个单一的主体。因此,如果球体最终与多个物体接触,我们将使用任意物体,而忽略其他物体。一旦知道了主体,我们就必须检测其运动并将其以某种方式应用于球体。
2.1 检测连接
我们不在乎为什么某物在移动,而只是它是否在移动。这个想法是所有动态对象都有一个刚体组件,因此我们将通过向它添加一个字段到MovingSphere来跟踪连接的实体。
如果我们在评估碰撞中检测到地面接触,我们可以简单地将碰撞的刚体属性分配给我们的字段。如果另一个对象有一个Rigidbody组件,那么我们现在有一个对它的引用,否则它被设置为null。请注意,组件不必直接连接到我们碰撞的对象。我们可能会与某个复合对象发生碰撞,该对象的组件位于其层次结构的某个较高位置。
请注意,通过简单地总是分配连接的物体,我们替换了以前被视为地面的任何接触点,因此我们最终会跟踪最后评估的地面物体。这很棒,因为碰撞顺序是任意的,但在时间上是稳定的。
但是,我们也有可能会走在斜坡上而不是地面上。在这种情况下,我们还应该跟踪主体。但是,我们应优先选择地面而不是斜坡,因此,仅在没有地面接触的情况下才分配斜坡主体。
如果没有连接的物体,是不是不应该总是使用斜坡?
不是,因为地面可能是静态的,在这种情况下它不会有刚体组件。在这种情况下,我们将站在不动的地面上,而不应该在碰巧也接触斜坡的时候,受到移动的斜坡的影响。
如果我们在SnapToGround中检测到地面,也应该跟踪连接的物体。
最后,在ClearState中将连接的正文重置为null。
2.2 连接状态
仅仅知道我们在当前物理步长中已连接到主体是不够的。我们必须能够弄清楚自上一步以来我们是否仍与同一个主体保持联系,因为这表明我们应该与之保持联系。因此,我们需要另一个字段来存储对先前连接的主体的引用。重置前应将其设置为当前连接的主体。
再将连接速度存储在一个字段中。虽然这不是特别有必要,但它会很方便。在ClearState中将其设置为零。
2.3 检测移动
如果连接的主体是自由移动的物理对象,那么它将具有速度,但是在运动动画对象的情况下,其速度将始终为零。因此,我们必须通过跟踪其位置来自己推断出连接速度。为此添加一个字段,并将其设置为新的UpdateConnectionState方法中连接主体的位置,如果我们具有连接主体,则将在UpdateState的末尾调用该方法。
但需要小心,不要粘附在与我们相撞的较轻的物体上,否则我们可能会随着它们一起自由移动,或者把它们推开,然后把我们自己弹射出去。可以通过更新连接体的连接状态来避免这种情况,如果连接体是运动的,至少应该和球体本身的质量一样大。
在更新连接之前,可以通过从连接的当前位置减去我们已经拥有的连接位置,在UpdateConnectionState中找到连接的运动。通过将其运动除以时间增量来找到其速度。
但是,只有当当前和先前的连接体相同时,该计算才有意义,因此请检查一下。否则,连接速度应保持为零。
2.4 相对于连接做移动
至此,我们知道了我们所站的平台的速度。下一个问题是我们如何将其纳入球体的运动中。实际上,当你从正在移动的物体移到静止的物体(反之亦然)时,需要补偿相对运动的突然变化。这很费力,如果变化很大,可能会很困难。如果太大,最终会掉下去。另外,如果你站在可以加速的物体上,则必须做好准备,否则你也会跌倒。最后,应该有可能相对于我们所站立的物体以最大速度移动。请注意,这可能导致世界空间速度超过配置的最大速度,例如在行驶中的火车中行驶。
最简单的建模方法是使球体加速以匹配其所连接的物体的速度,然后再加速至相对于连接速度的所需速度。我们可以在AdjustVelocity中做到这一点,方法是从球体的速度中减去连接速度,然后使用此相对速度来确定当前的X和Z速度。因此,球体的速度调整变得相对于连接速度,而其他所有条件保持不变。
在侧面移动的平台上移动
2.5 旋转
现在,我们的球体试图匹配其所站立的物体的速度,但受到其自身加速度的限制。在与平台的运动匹配之前,球体将会有滑动效果。而且,如果平台快速加速,球体无法跟上的话,可能会滑落。因此,在快速加速的东西上行走可能很尴尬,这与现实相符。可以通过增加球体的最大加速度来缓解。
忽略了平台旋转
在旋转连接的情况下,我们无法跟踪其位置,因为它不受旋转的影响。因此需要追踪被连接物体的局部空间中的连接位置,因为该点有效地绕过了物体的本地原点。
从现在开始,我们将使用球体的位置作为世界空间中的连接位置,而不是连接本身的位置。这是我们一开始跟踪的点。连接的局部位置是相同的点,但是在连接体的局部空间中,我们通过在连接体的转换组件上调用InverseTransformPoint来找到它。在UpdateConnectionState的最后执行此操作。
在旋转的平台上行走
现在,我们的球体会加速以跟上旋转,但请注意,它不会调整其方向来匹配。由于我们的球体永不旋转,它会自动重新定向以保持朝相同的方向看。
另请注意,旋转可能会是高速旋转。你离旋转中心越远,轨道速度就越快。如果旋转足够快,你会被甩开,要么迅速从轨道弹出,要么缓慢向外盘旋。
2.6 复杂的动画
因为我们的方法不在乎表面如何移动,所以我们的效果不会局限于简单的动画。我们支持所有复杂的动画和脚本化运动,也支持在不受控制的PhysX对象上运动,但这会有一点点尴尬,就像在现实生活中在不稳定的地面上行走一样。创建复杂运动的另一种方法是通过构建其中包含多个动画师的对象层次结构。你也可以在层次结构中放置多个物理对象,但请记住,不要将具有刚体的任何对象作为另一个此类对象的子对象,因为物理干扰,这会产生奇怪的结果。
复杂的动画和平台
下一章,介绍攀爬。
欢迎扫描二维码,查看更多精彩内容。点击 阅读原文 可以跳转原教程。
本文翻译自 Jasper Flick的系列教程
原文地址:
https://catlikecoding.com/unity/tutorials

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-23 11:04 , Processed in 0.087279 second(s), 24 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表