RayCast3D
2026/4/14大约 4 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — RayCast3D
RayCast3D
节点继承关系
继承自 Node3D
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Position | 本地位置(X / Y / Z) |
| 属性 | GlobalPosition | 全局位置 |
| 属性 | Rotation | 旋转角度(欧拉角,弧度) |
| 属性 | Scale | 缩放比例 |
| 属性 | TopLevel | 是否脱离父节点的变换 |
| 方法 | LookAt() | 朝向目标点 |
| 方法 | ToGlobal() | 本地坐标转全局坐标 |
| 方法 | ToLocal() | 全局坐标转本地坐标 |
| 方法 | RotateX/Y/Z() | 绕指定轴旋转 |
继承自 Node
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Name | 节点名称 |
| 属性 | ProcessMode | 处理模式(始终 / 暂停时 / 仅编辑器) |
| 属性 | ProcessPriority | 处理优先级,数字越小越先执行 |
| 信号 | ready | 节点进入场景树并准备就绪 |
| 信号 | tree_entered | 节点进入场景树 |
| 信号 | tree_exited | 节点完全离开场景树 |
| 方法 | GetNode<T>() | 按路径获取子节点 |
| 方法 | AddChild() | 添加子节点 |
| 方法 | RemoveChild() | 移除子节点 |
| 方法 | QueueFree() | 帧结束后释放节点 |
| 方法 | GetParent() | 获取父节点 |
定义
在 3D 空间中投射一条看不见的射线,检测它碰到了什么。
RayCast3D 是 RayCast2D 的 3D 版本,原理完全相同。3D 版本使用 Vector3 作为位置和方向类型,适用于 3D 游戏中的视线检测、地面检测、射击检测等。
使用频率:★★★★ 常用——3D 游戏中非常常用的检测工具。
节点用途
- 3D 视线检测
- 3D 地面检测
- 3D 瞄准检测(FPS 游戏)
- 3D 悬崖检测
使用场景
典型场景
- FPS 射击检测:从摄像机位置向前发射射线,检测是否命中敌人
- 3D 地面检测:在角色脚下放一条向下的射线
- 3D 敌人视线:检测敌人是否能看到玩家
不适用场景
- 需要检测"一整块区域" → 使用 ShapeCast3D
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| Camera3D(作为父节点) | FPS 射击检测 | 推荐 |
| CharacterBody3D(作为父节点) | 角色地面检测 | 推荐 |
典型节点树:
Camera3D
└── GunRay (RayCast3D) ← 射向瞄准方向的射线生效必备素材/资源
无需外部资源。
节点属性与信号
核心属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
Enabled | bool | false | — | 是否启用(默认关闭!记得开启) |
TargetPosition | Vector3 | (0, 0, -50) | — | 射线终点(相对于节点的偏移) |
CollideWithBodies | bool | true | — | 是否检测物理体 |
CollideWithAreas | bool | false | — | 是否检测 Area |
CollisionMask | uint | 1 | — | 碰撞层掩码 |
HitFromInside | bool | false | — | 是否从内部开始检测 |
ExcludeParent | bool | true | — | 是否排除父节点的碰撞 |
信号
| 信号 | 触发时机 | 继承自 | 说明 |
|---|---|---|---|
| 无自有信号 | — | — | — |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
IsColliding() | bool | 射线是否碰到了东西 |
GetCollider() | Object | 碰到的第一个物体 |
GetCollisionPoint() | Vector3 | 碰撞发生的精确位置 |
GetCollisionNormal() | Vector3 | 碰撞面的法线方向 |
GetColliderRid() | RID | 碰撞物体的资源 ID |
GetColliderShape() | int | 碰撞的形状索引 |
ForceRaycastUpdate() | void | 强制立即更新检测结果 |
代码示例
C
using Godot;
/// <summary>
/// FPS 射击检测:从摄像机发射射线检测命中
/// 节点结构:Camera3D + RayCast3D(作为 Camera3D 的子节点)
/// </summary>
public partial class FPSGun : Node3D
{
private RayCast3D _rayCast;
[Export] public int ExDamage = 25;
[Export] private PackedScene _hitEffect;
public override void _Ready()
{
_rayCast = GetNode<RayCast3D>("../Camera3D/RayCast3D");
_rayCast.Enabled = true;
}
public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventMouseButton mouseButton
&& mouseButton.Pressed
&& mouseButton.ButtonIndex == MouseButton.Left)
{
Shoot();
}
}
private void Shoot()
{
_rayCast.ForceRaycastUpdate();
if (_rayCast.IsColliding())
{
var collider = _rayCast.GetCollider();
var hitPoint = _rayCast.GetCollisionPoint();
GD.Print($"命中目标:{collider?.Name},位置:{hitPoint}");
// 对命中的物体造成伤害
if (collider is Node3D target && target.HasMethod("TakeDamage"))
{
target.Call("TakeDamage", ExDamage);
}
// 生成命中特效
if (_hitEffect != null)
{
var effect = _hitEffect.Instantiate<Node3D>();
GetTree().CurrentScene.AddChild(effect);
effect.GlobalPosition = hitPoint;
}
}
}
}
/// <summary>
/// 3D 地面检测:在角色脚底向下发射射线
/// </summary>
public partial class GroundDetector3D : RayCast3D
{
public override void _Ready()
{
Enabled = true;
// 射线向下投射(3D 中 Y 轴负方向为下)
TargetPosition = new Vector3(0f, -1f, 0f);
}
public bool IsOnGround()
{
ForceRaycastUpdate();
return IsColliding();
}
public float GetGroundDistance()
{
ForceRaycastUpdate();
if (IsColliding())
{
return GlobalPosition.DistanceTo(GetCollisionPoint());
}
return Mathf.Inf;
}
}GDScript
# FPS 射击检测:从摄像机发射射线检测命中
# 节点结构:Camera3D + RayCast3D(作为 Camera3D 的子节点)
extends Node3D
@onready var ray_cast: RayCast3D = $"../Camera3D/RayCast3D"
@export var damage: int = 25
@export var hit_effect: PackedScene
func _ready() -> void:
ray_cast.enabled = true
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
shoot()
func shoot() -> void:
ray_cast.force_raycast_update()
if ray_cast.is_colliding():
var collider = ray_cast.get_collider()
var hit_point = ray_cast.get_collision_point()
print("命中目标:%s,位置:%s" % [collider.name if collider else "无", hit_point])
# 对命中的物体造成伤害
if collider is Node3D and collider.has_method("take_damage"):
collider.take_damage(damage)
# 生成命中特效
if hit_effect:
var effect := hit_effect.instantiate()
get_tree().current_scene.add_child(effect)
effect.global_position = hit_point3D 射线的 TargetPosition 默认方向
3D 中 RayCast3D 的 TargetPosition 默认是 (0, 0, -50),也就是向 Z 轴负方向(前方)投射 50 个单位。这和 2D 版本不同(2D 默认向 Y 轴负方向投射)。
