SpringArm3D
2026/4/14大约 3 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — SpringArm3D
SpringArm3D
节点继承关系
继承自 Node
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Name | 节点名称 |
| 属性 | ProcessMode | 处理模式(始终 / 暂停时 / 仅编辑器) |
| 属性 | ProcessPriority | 处理优先级,数字越小越先执行 |
| 信号 | ready | 节点进入场景树并准备就绪 |
| 信号 | tree_entered | 节点进入场景树 |
| 信号 | tree_exited | 节点完全离开场景树 |
| 方法 | GetNode<T>() | 按路径获取子节点 |
| 方法 | AddChild() | 添加子节点 |
| 方法 | RemoveChild() | 移除子节点 |
| 方法 | QueueFree() | 帧结束后释放节点 |
| 方法 | GetParent() | 获取父节点 |
定义
SpringArm3D 是一个3D"弹簧臂",专门用来挂载第三人称相机。它可以自动伸缩(像弹簧一样),当相机要穿墙时,弹簧臂会自动缩短,把相机拉回到墙壁前方,防止相机穿进墙里。
打个比方:想象你拿着一根伸缩杆,杆子一端固定在角色身上,另一端挂着相机。当你走到墙边时,伸缩杆会自动缩短,相机就不会穿过墙壁了。这就是 SpringArm3D。
简单说:它是挂载3D相机的"弹簧杆",能防止相机穿墙。
使用频率:★★★★ 常用
节点用途
- 第三人称相机:挂在角色身上,相机跟随角色移动
- 防穿墙:相机不会穿进墙壁和地面
- 相机距离控制:通过调整弹簧长度控制相机远近
- 平滑跟随:相机平滑地跟随角色移动
使用场景
| 场景 | 说明 |
|---|---|
| 第三人称动作游戏 | 相机挂在 SpringArm3D 上,跟随角色移动 |
| 第三人称射击游戏 | 瞄准时弹簧臂缩短到角色肩膀位置 |
| RPG游戏 | 相机平滑跟随角色探索世界 |
常用节点搭配
| 搭配节点 | 搭配方式 |
|---|---|
| Camera3D | 作为 SpringArm3D 的子节点 |
| CharacterBody3D | SpringArm3D 作为角色的子节点 |
生效必备素材/资源
SpringArm3D 的碰撞检测需要场景中有 CollisionObject3D(如 StaticBody3D、CSGBox3D 等)。
节点属性与信号
属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
| spring_length | float | 1.0 | SpringArm3D | 弹簧的长度(相机到角色的默认距离) |
| margin | float | 0.01 | SpringArm3D | 边缘距离。相机离碰撞体至少保持这个距离 |
| shape | Shape3D | null | SpringArm3D | 碰撞检测形状。默认用线段检测 |
| collision_mask | int | 1 | SpringArm3D | 碰撞层掩码,决定和哪些物体碰撞 |
| process_callback | int | 0 | SpringArm3D | 处理回调模式:0=空闲帧,1=物理帧 |
信号
SpringArm3D 没有自己的特有信号。
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
| GetHitLength() | float | 获取碰撞后弹簧的实际长度 |
代码示例
C
// C# - 第三人称相机系统
using Godot;
public partial class ThirdPersonCamera : Node3D
{
private SpringArm3D _springArm;
private Camera3D _camera;
private float _mouseSensitivity = 0.002f;
private float _cameraDistance = 5.0f;
public override void _Ready()
{
_springArm = GetNode<SpringArm3D>("SpringArm3D");
_camera = _springArm.GetNode<Camera3D>("Camera3D");
// 配置弹簧臂
_springArm.SpringLength = _cameraDistance;
_springArm.CollisionMask = 1; // 与第1层碰撞体碰撞
_springArm.Margin = 0.1f;
}
public override void _UnhandledInput(InputEvent @event)
{
// 鼠标移动控制相机旋转
if (@event is InputEventMouseMotion mouseMotion)
{
// 水平旋转整个 SpringArm
RotateY(-mouseMotion.Relative.X * _mouseSensitivity);
// 垂直旋转 SpringArm
_springArm.RotateX(-mouseMotion.Relative.Y * _mouseSensitivity);
// 限制垂直旋转角度
_springArm.RotationDegrees = new Vector3(
Mathf.Clamp(_springArm.RotationDegrees.X, -60f, 60f),
_springArm.RotationDegrees.Y,
_springArm.RotationDegrees.Z
);
}
}
public override void _Process(double delta)
{
// 滚轮调整相机距离
if (Input.IsActionJustPressed("zoom_in"))
{
_cameraDistance = Mathf.Max(2.0f, _cameraDistance - 0.5f);
_springArm.SpringLength = _cameraDistance;
}
if (Input.IsActionJustPressed("zoom_out"))
{
_cameraDistance = Mathf.Min(15.0f, _cameraDistance + 0.5f);
_springArm.SpringLength = _cameraDistance;
}
}
}GDScript
# GDScript - 第三人称相机系统
extends Node3D
@onready var spring_arm: SpringArm3D = $SpringArm3D
@onready var camera: Camera3D = $SpringArm3D/Camera3D
var mouse_sensitivity: float = 0.002
var camera_distance: float = 5.0
func _ready():
# 配置弹簧臂
spring_arm.spring_length = camera_distance
spring_arm.collision_mask = 1 # 与第1层碰撞体碰撞
spring_arm.margin = 0.1
func _unhandled_input(event):
# 鼠标移动控制相机旋转
if event is InputEventMouseMotion:
# 水平旋转整个 SpringArm
rotate_y(-event.relative.x * mouse_sensitivity)
# 垂直旋转 SpringArm
spring_arm.rotate_x(-event.relative.y * mouse_sensitivity)
# 限制垂直旋转角度
spring_arm.rotation_degrees.x = clampf(spring_arm.rotation_degrees.x, -60, 60)
func _process(_delta):
# 滚轮调整相机距离
if Input.is_action_just_pressed("zoom_in"):
camera_distance = maxf(2.0, camera_distance - 0.5)
spring_arm.spring_length = camera_distance
if Input.is_action_just_pressed("zoom_out"):
camera_distance = minf(15.0, camera_distance + 0.5)
spring_arm.spring_length = camera_distance