Skeleton2D
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — Skeleton2D
Skeleton2D
节点继承关系
继承自 Node
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Name | 节点名称 |
| 属性 | ProcessMode | 处理模式(始终 / 暂停时 / 仅编辑器) |
| 属性 | ProcessPriority | 处理优先级,数字越小越先执行 |
| 信号 | ready | 节点进入场景树并准备就绪 |
| 信号 | tree_entered | 节点进入场景树 |
| 信号 | tree_exited | 节点完全离开场景树 |
| 方法 | GetNode<T>() | 按路径获取子节点 |
| 方法 | AddChild() | 添加子节点 |
| 方法 | RemoveChild() | 移除子节点 |
| 方法 | QueueFree() | 帧结束后释放节点 |
| 方法 | GetParent() | 获取父节点 |
定义
Skeleton2D 是 Godot 中的 2D 骨骼系统(Skeleton)节点。它本身不显示任何东西,但它是所有 Bone2D 骨骼节点的"容器"。通过在 Skeleton2D 下面挂载多个 Bone2D 节点,构建出一套完整的骨骼层级结构,再用 AnimationPlayer 来驱动骨骼旋转和位移,就能做出流畅的 2D 角色动画。
想象 Skeleton2D 是一具木偶戏的骨架:单独的骨架不能表演,但你在骨架上绑上线(Bone2D 骨骼),再在骨骼上贴上画好的身体部位(Sprite2D),拉动不同的线就能让木偶做出各种动作。
一句话理解:Skeleton2D 是 2D 骨骼动画(Skeletal Animation)的"骨架容器",负责管理和协调所有骨骼节点的变换,让角色能用骨骼驱动的方式动起来。
使用频率:★★★ 一般常用——制作 2D 骨骼动画角色时必需,如果角色是用逐帧动画(SpriteFrames)做的则不需要。
节点用途
- 作为 2D 骨骼动画的根容器,管理所有 Bone2D 子节点
- 提供骨骼查找和变换计算功能
- 配合 AnimationPlayer 驱动骨骼旋转、位移制作角色动画
- 支持"骨骼蒙皮"(Rest Pose 和骨骼权重),让精灵图片跟随骨骼变形
使用场景
典型场景
- 制作 2D 角色的骨骼动画(比逐帧动画更流畅、更省资源)
- 角色需要换装系统(不同骨骼挂载不同装备图片)
- 需要程序化控制角色肢体(比如角色看向鼠标方向时头部自动转动)
不适用场景
- 角色动画是逐帧动画(SpriteFrames + AnimatedSprite2D)-> 不需要骨骼系统
- 3D 角色动画 -> 使用 Skeleton3D
- 简单的 UI 动画 -> 使用 AnimationPlayer 直接驱动
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| Bone2D | 骨骼节点,构成骨骼层级结构 | 必需 |
| AnimationPlayer | 驱动骨骼动画 | 必需 |
| Sprite2D | 作为骨骼的视觉表现(贴图) | 必需 |
| Polygon2D | 用多边形替代 Sprite2D 实现蒙皮变形效果 | 蒙皮动画时使用 |
| AnimationTree | 管理多个骨骼动画的切换 | 角色动作多时推荐 |
典型骨骼层级结构:
CharacterBody2D
└── Skeleton2D ← 骨骼根节点
├── Hip ← 臀部(根骨骼)
│ ├── Torso ← 躯干
│ │ ├── Head ← 头部
│ │ ├── LeftUpperArm ← 左上臂
│ │ │ └── LeftForearm ← 左前臂
│ │ ├── RightUpperArm ← 右上臂
│ │ │ └── RightForearm ← 右前臂
│ ├── LeftUpperLeg ← 左大腿
│ │ └── LeftLowerLeg ← 左小腿
│ └── RightUpperLeg ← 右大腿
│ └── RightLowerLeg ← 右小腿
└── AnimationPlayer ← 驱动骨骼动画生效必备素材/资源
| 资源 | 类型 | 说明 |
|---|---|---|
| 角色拆分图 | 图片素材(PNG) | 角色身体的各个部位需要拆分成独立的图片(头、躯干、左上臂、右前臂等) |
| Bone2D 节点 | 场景节点 | 在 Skeleton2D 下创建的骨骼节点,构成完整的骨骼层级 |
| Animation | Animation 资源 | 在 AnimationPlayer 中创建的骨骼动画,关键帧驱动各个 Bone2D 的 rotation 和 position |
节点属性与信号
骨骼属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
Modulate | Color | (1,1,1,1) | Node2D | 骨骼整体颜色调制,影响所有子骨骼和精灵 |
ShowRestOnly | bool | false | — | 调试选项:仅显示休息姿态 |
Skeleton2D | SkeletonModificationStack2D | null | — | 2D 骨骼修改器栈(用于 IK 等高级功能) |
信号
| 信号 | 参数 | 说明 |
|---|---|---|
BonePoseChanged | boneIdx: int | 某个骨骼的姿势发生变化时触发 |
BoneSetupChanged | — | 骨骼层级结构发生变化时触发(添加/删除骨骼) |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
GetBoneCount() | int | 获取骨骼总数 |
GetBoneName(boneIdx) | StringName | 获取指定索引的骨骼名称 |
FindBone(name) | int | 根据名称查找骨骼索引,找不到返回 -1 |
GetBoneGlobalPose(boneIdx) | Transform2D | 获取骨骼的全局变换 |
GetBonePose(boneIdx) | Transform2D | 获取骨骼的本地变换 |
SetBonePose(boneIdx, pose) | void | 设置骨骼的本地变换 |
GetBoneRest(boneIdx) | Transform2D | 获取骨骼的休息姿态 |
SetBoneRest(boneIdx, rest) | void | 设置骨骼的休息姿态 |
代码示例
查找并操作骨骼
C
using Godot;
public partial class Skeleton2DController : Node
{
private Skeleton2D _skeleton;
private int _headBoneIdx;
public override void _Ready()
{
_skeleton = GetNode<Skeleton2D>("Skeleton2D");
// 通过名称查找头部骨骼
_headBoneIdx = _skeleton.FindBone("Head");
if (_headBoneIdx == -1)
{
GD.PrintErr("找不到名为 Head 的骨骼!");
return;
}
GD.Print($"头部骨骼索引: {_headBoneIdx}");
GD.Print($"总骨骼数: {_skeleton.GetBoneCount()}");
// 打印所有骨骼名称
for (int i = 0; i < _skeleton.GetBoneCount(); i++)
{
GD.Print($"骨骼 {i}: {_skeleton.GetBoneName(i)}");
}
}
public override void _Process(double delta)
{
// 让头部朝向鼠标方向
if (_headBoneIdx >= 0)
{
var mousePos = GetGlobalMousePosition();
var headGlobalPos = _skeleton.GetBoneGlobalPose(_headBoneIdx).Origin;
// 计算头部到鼠标的角度
float angle = headGlobalPos.AngleToPoint(mousePos);
// 获取头部骨骼的当前变换,修改旋转角度
var pose = _skeleton.GetBonePose(_headBoneIdx);
pose.Rotation = angle;
_skeleton.SetBonePose(_headBoneIdx, pose);
}
}
}GDScript
extends Node
@onready var skeleton: Skeleton2D = $Skeleton2D
var head_bone_idx: int
func _ready():
# 通过名称查找头部骨骼
head_bone_idx = skeleton.find_bone("Head")
if head_bone_idx == -1:
push_error("找不到名为 Head 的骨骼!")
return
print("头部骨骼索引: ", head_bone_idx)
print("总骨骼数: ", skeleton.get_bone_count())
# 打印所有骨骼名称
for i in range(skeleton.get_bone_count()):
print("骨骼 %d: %s" % [i, skeleton.get_bone_name(i)])
func _process(_delta):
# 让头部朝向鼠标方向
if head_bone_idx >= 0:
var mouse_pos = get_global_mouse_position()
var head_global_pos = skeleton.get_bone_global_pose(head_bone_idx).origin
# 计算头部到鼠标的角度
var angle = head_global_pos.angle_to_point(mouse_pos)
# 获取头部骨骼的当前变换,修改旋转角度
var pose = skeleton.get_bone_pose(head_bone_idx)
pose.rotation = angle
skeleton.set_bone_pose(head_bone_idx, pose)Skeleton2D vs AnimatedSprite2D
如果你角色的每个动作都是预先画好的一张张图片(逐帧动画),用 AnimatedSprite2D + SpriteFrames 就够了。如果你的角色是用拆分的身体部件 + 骨骼旋转来做动画,就需要 Skeleton2D + Bone2D。骨骼动画的好处是:更流畅、更省资源、可以程序化控制。
