Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

布娃娃系统

介绍

Godot 支持布娃娃物理。布娃娃依靠物理仿真来创建逼真的程序式动画,它们被用于许多游戏中的死亡动画。

在本教程中,我们将使用 Platformer 3D 演示来进行布娃娃的设置。

备注

你可以在 GitHub 上下载 Platformer 3D 演示项目,也可以使用资产库

你还可以参考 布娃娃物理演示 中完整的布娃娃系统设置示例。

设置布娃娃

创建物理骨骼

与引擎中的许多其他功能一样,设置布娃娃系统也使用了两个节点:

  • PhysicalBoneSimulator3D 节点。该节点是所有物理骨骼的父节点,负责控制模拟。

  • 一个或多个 PhysicalBone3D 子节点。每个节点代表布娃娃模型中的一个骨骼 。

在 Godot 中打开 Platformer 演示项目,然后打开 player/player.tscn 场景。选择 Skeleton3D 节点。3D编辑器视口顶部会显示一个骨架按钮:

在编辑器中创建物理骨架

在编辑器中创建物理骨架

单击它并选择 Create Physical Skeleton 选项。Godot 将为骨架中的每个骨骼生成 PhysicalBone3D 节点和碰撞形状,并用钉关节将它们连接在一起:

创建物理骨骼之后玩家场景的场景树

创建物理骨骼之后玩家场景的场景树

一些生成的骨骼不是必需的:例如这个场景中的 MASTER 骨骼。因此,我们将通过删除它们来清理骨架。

清理并优化骨骼

引擎需要模拟的每一个 PhysicalBone3D 都会消耗一定的性能,因此,你需要移除所有尺寸过小、对模拟影响甚微的骨骼 ,以及所有辅助骨骼。

例如,如果我们拿一个人形动物举例,就不希望每个手指都有物理骨骼。可以用一根骨骼代替整个手,或者用一根骨骼代替手掌,一根骨骼代替拇指,最后一根骨头代表其他四个手指。

移除这些 PhysicalBone3D 节点:MASTERwaistneckheadtracker。这样就有了一个优化的骨架,使其更容易控制布娃娃。

调整关节和约束

一旦你调整了碰撞形状,布娃娃就差不多准备好了。现在只需要调整钉关节以获得更好的模拟效果。PhysicalBone3D 节点在默认情况下有一个不受限制的钉关节。要改变钉关节,请选择 PhysicalBone3D 节点,然后在检查器的 Joint 部分改变约束类型。在那里,你可以改变约束的方向和限制。

关节在 3D 编辑器中也有可见的小工具 ,因此可以查看其约束的实际效果。

在选择 PhysicalBone3D 节点后,在检查器中调整关节

在选择 PhysicalBone3D 节点后,在检查器中调整关节

小技巧

为了在编辑关节和碰撞形状时视图效果更好,你可以执行以下操作:

  • 隐藏当前未在处理的 PhysicalBone3D 节点,以便你可以专注于正在调整的节点。

  • 在场景树面板中 ,点击角色旁边的眼睛图标 ,即可隐藏角色的 MeshInstance3D。

  • 隐藏 Skeleton3D 小工具 ,这样代表骨架的橙色三角形就不会占用视口空间,同时保持其他小工具可见。为了执行此操作,请单击 3D 编辑器视口顶部的 View > Gizmos > Skeleton3D ,直到眼睛图标合起来。

  • 单击 3D 编辑器视口顶部的地球图标 ,即可禁用预览环境。

  • 在项目设置中,将 默认清屏颜色 项目设置设为纯黑色。此设置仅在禁用预览环境时有效。

  • 使用 3D 编辑器视口左上角的 Perspective 按钮以更改调试绘制模式。Display WireframeDisplay Overdraw 选项在调整碰撞形状时非常好用,它们可以让你透过原始网格查看内部情况。

  • 单击 3D 编辑器视口右上角的 X/Y/Z 按钮,即可使用正交相机 。

可用的关节列表如下:

  • None: 无,不执行任何约束。

  • ConeJoint: 球窝型关节。适用于肩部、髋部、颈部。

  • HingeJoint: 铰链关节。提供角度约束;可以把它想象成门的铰链 。适用于肘部和膝部。

  • PinJoint: 销关节,保持两个身体连接 (默认)。它会导致骨骼“变形”,因此建议大多数角色使用其他关节类型。

  • SliderJoint: 滑动关节。使一根骨骼沿特定轴线沿另一根骨骼滑动。

  • 6DOFJoint: 功能最强大的关节,提供线性和角度约束,但配置也最复杂。

如有疑问,请先从 HingeJoint 和 ConeJoint 入手,因为它们涵盖了大多数使用场景:

  • 对于 HingeJoint ,请确保在检查器的 Joint Constraints 中启用 角度限制 。启用该选项后,你可以在视口中看到关节的约束角度。你可以旋转 PhysicalBone3D 来改变约束关节的轴,然后调整角度。

  • 对于 ConeJoint ,通常最好将 摆动范围 限制在 20 到 90 度之间,同时将 扭转范围 限制在 20 到 45 度之间。

调整碰撞形状

下一步是调整碰撞形状和物理骨骼的大小,以匹配每个骨骼应该模拟的身体部位。

建议在调整关节和约束 之后 再调整碰撞形状,因为旋转关节也会旋转碰撞形状。为了避免重复调整碰撞形状,最好先调整关节。

请注意,PhysicalBone3D 节点可以包含多个碰撞形状作为子节点。对于原本刚性的肢体,这种方法能够有效呈现其极其复杂的形态。

小技巧

要在调整布娃娃时暂停动画播放,请选择 AnimationTree 节点,然后在检视面板中禁用 Active 属性。完成后记得重新启用它,因为它控制着游戏过程中的动画播放。

在 3D 编辑器中调整碰撞形状

在 3D 编辑器中调整碰撞形状

这是最终效果:

调整关节和碰撞形状后的结果(为了便于查看,玩家模型已隐藏)

调整关节和碰撞形状后的结果(为了便于查看,玩家模型已隐藏)

模拟布娃娃

现在布娃娃已可以使用了。要开始模拟并播放布娃娃动画,你需要调用 PhysicalBoneSimulator3D.physical_bones_start_simulation() 方法。将脚本附加到场景中所有的 PhysicalBone3D 节点的父节点 PhysicalBoneSimulator3D 上,然后在脚本的 _ready 方法中调用该方法:

func _ready():
    physical_bones_start_simulation()

要停止模拟,请调用 PhysicalBoneSimulator3D.physical_bones_stop_simulation() 方法。

你还可以将模拟限制为仅包含少数骨骼。对于创建诸如布娃娃肢体或可与世界交互的附件等效果时,这种操作非常有用。为此,请将骨骼名称( 而非 PhysicalBone3D 节点的名称)作为参数传递 。要查看骨骼名称,请在选择 PhysicalBone3D 节点后,查看检查器中的 骨骼名称 属性。

小技巧

当使用本教程中所示的自动生成的物理骨骼时, 骨骼名称也包含在节点名称中。例如,在 Physical Bone l-arm 中, l-arm 就是骨骼名称。

func _ready():
    physical_bones_start_simulation(["l-arm", "r-arm"])

请注意,如果骨骼名称不存在,则不会打印任何错误或警告。如果在启动模拟时没有任何反应(或者整个身体都像布娃娃一样运动,而不仅仅是特定骨骼),请仔细检查所提供的骨骼列表。

以下是一个局部布娃娃模拟的例子:

小技巧

要控制部分布娃娃模拟对整体动画的影响程度,你可以调整所有 PhysicalBone3D 节点的父节点 PhysicalBoneSimulator3D 中的 Influence 属性。默认情况下,该属性设置为 1.0 ,这意味着布娃娃模拟会完全覆盖其余动画。

碰撞层与遮罩

请务必正确设置碰撞层和遮罩,以免 CharacterBody3D 的胶囊体干扰物理模拟 。同时,也请记得调整金币场景中的碰撞层和遮罩 ,以便玩家仍然可以收集到金币。

必须在检查器中将每个节点的图层和遮罩调整为这些值

必须在检查器中将每个节点的图层和遮罩调整为这些值

你可以在 3D 平台游戏演示的 stage/grid_map.scn 中找到 GridMap。硬币的 Area3D 节点(必须调整其图层和遮罩)位于 coin/coin.tscn

小技巧

为了快速选择所有 PhysicalBone3D 节点,请在场景树停靠栏顶部的搜索栏中输入 t:PhysicalBone3D 。这将会筛选场景树,使其仅显示 PhysicalBone3D 节点,这样你就可以使用 Shift + Left mouse button 一次性选择第一个和最后一个节点。

如果不这样做,碰撞检测将出现异常,因为玩家会与自身(非激活状态)的布娃娃模型发生碰撞。这可能导致玩家出现剧烈弹跳或卡住。

与 RigidBody3D 类似,PhysicalBone3D 也支持通过代码使用 physical_bones_add_collision_exception()physical_bones_remove_collision_exception() 方法来处理碰撞异常。该功能可以用于在无需依赖图层和遮罩的情况下,防止与特定对象发生碰撞。

参见

有关更多信息,请阅读 碰撞层与遮罩