RayCast2D
2026/4/14大约 5 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — RayCast2D
RayCast2D
节点继承关系
继承链:Node → CanvasItem → Node2D → RayCast2D
继承自 Node2D
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Position | 本地位置(相对于父节点) |
| 属性 | GlobalPosition | 全局位置 |
| 属性 | Rotation | 旋转角度(弧度) |
| 属性 | Scale | 缩放比例 |
| 属性 | Skew | 倾斜角度(弧度) |
| 方法 | Rotate() | 旋转指定弧度 |
| 方法 | ToGlobal() | 本地坐标转全局坐标 |
| 方法 | ToLocal() | 全局坐标转本地坐标 |
继承自 CanvasItem
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Visible | 是否可见 |
| 属性 | Modulate | 整体颜色叠加(乘法) |
| 属性 | SelfModulate | 自身颜色叠加(不影响子节点) |
| 属性 | ZIndex | 绘制层级(Z 轴排序) |
| 信号 | visibility_changed | 可见性变化时触发 |
| 方法 | GetGlobalMousePosition() | 获取鼠标全局坐标 |
继承自 Node
| 类型 | 名称 | 说明 |
|---|---|---|
| 属性 | Name | 节点名称 |
| 属性 | ProcessMode | 处理模式(始终 / 暂停时 / 仅编辑器) |
| 属性 | ProcessPriority | 处理优先级,数字越小越先执行 |
| 信号 | ready | 节点进入场景树并准备就绪 |
| 信号 | tree_entered | 节点进入场景树 |
| 信号 | tree_exited | 节点完全离开场景树 |
| 方法 | GetNode<T>() | 按路径获取子节点 |
| 方法 | AddChild() | 添加子节点 |
| 方法 | RemoveChild() | 移除子节点 |
| 方法 | QueueFree() | 帧结束后释放节点 |
| 方法 | GetParent() | 获取父节点 |
定义
从节点位置向前射出一条看不见的线,检测它碰到了什么——就像手电筒的光束。
想象你拿着一支激光笔往前照——光线照到的地方你就知道那里有东西。RayCast2D 就是这支"激光笔"。它从自身的位置开始,向一个方向投射一条射线(一条无限细的线),检测射线路径上第一个碰到的物体。
它不是一条可见的线,而是物理引擎内部的一条检测线,在游戏画面中是看不到的(除非在编辑器中开启了调试显示)。
使用频率:★★★★ 常用——非常常用的检测工具。
节点用途
- 视线检测(敌人能不能"看到"玩家)
- 地面检测(角色脚下是不是有地面)
- 瞄准检测(枪口前方有没有敌人)
- 悬崖检测(角色前方是不是悬崖)
- 激光/子弹(瞬间命中的武器)
使用场景
典型场景
- 敌人 AI 视线:敌人前方有一条射线,碰到玩家就追击
- 地面检测:在角色脚底放一条向下的射线
- 跳跃辅助:检测角色前方是否有平台可以跳上去
不适用场景
- 需要检测"一整块区域"有没有障碍物 → 使用 ShapeCast2D
常用节点搭配
| 搭配节点 | 用途 | 必需? |
|---|---|---|
| CharacterBody2D(作为父节点) | 把射线绑定到角色上 | 推荐 |
典型节点树:
Enemy (CharacterBody2D)
├── CollisionShape2D
└── SightRay (RayCast2D) ← 射向玩家方向的射线生效必备素材/资源
无需外部资源。
节点属性与信号
核心属性
| 属性 | 类型 | 默认值 | 继承自 | 说明 |
|---|---|---|---|---|
Enabled | bool | false | — | 是否启用(默认关闭!记得开启) |
TargetPosition | Vector2 | (0, -50) | — | 射线终点(相对于节点的偏移) |
CollideWithBodies | bool | true | — | 是否检测物理体 |
CollideWithAreas | bool | false | — | 是否检测 Area |
CollisionMask | uint | 1 | — | 碰撞层掩码(只检测指定层) |
HitFromInside | bool | false | — | 是否从内部开始检测 |
ExcludeParent | bool | true | — | 是否排除父节点的碰撞 |
信号
| 信号 | 触发时机 | 继承自 | 说明 |
|---|---|---|---|
| 无自有信号 | — | — | RayCast 通过方法检测,不通过信号 |
常用方法
| 方法 | 返回值 | 说明 |
|---|---|---|
IsColliding() | bool | 射线是否碰到了东西 |
GetCollider() | Object | 碰到的第一个物体 |
GetCollisionPoint() | Vector2 | 碰撞发生的精确位置 |
GetCollisionNormal() | Vector2 | 碰撞面的法线方向 |
GetColliderRid() | RID | 碰撞物体的资源 ID |
GetColliderShape() | int | 碰撞的形状索引 |
ForceRaycastUpdate() | void | 强制立即更新检测结果 |
代码示例
C
using Godot;
/// <summary>
/// 敌人视线检测:用射线检测能不能看到玩家
/// 节点结构:
/// Enemy (CharacterBody2D)
/// ├── RayCast2D (视线射线)
/// └── ...
/// </summary>
public partial class EnemySight : CharacterBody2D
{
private RayCast2D _sightRay;
private float _detectionRange = 300f;
public override void _Ready()
{
_sightRay = GetNode<RayCast2D>("SightRay");
_sightRay.Enabled = true;
}
public override void _PhysicsProcess(double delta)
{
// 检查是否看到了玩家
if (CanSeePlayer())
{
GD.Print("发现玩家!追击!");
// ... 追击逻辑
}
}
/// <summary>
/// 检查射线是否碰到了玩家
/// </summary>
private bool CanSeePlayer()
{
// 强制更新射线(在当前帧立即获取结果)
_sightRay.ForceRaycastUpdate();
if (!_sightRay.IsColliding())
return false;
var collider = _sightRay.GetCollider();
// 检查碰到的物体是不是玩家
return collider is Player;
}
/// <summary>
/// 让射线朝向指定位置
/// </summary>
public void LookAtTarget(Vector2 targetPosition)
{
// 计算从敌人到目标的方向
Vector2 direction = (targetPosition - GlobalPosition).Normalized();
// 设置射线终点(朝向目标方向,指定距离)
_sightRay.TargetPosition = direction * _detectionRange;
}
}
/// <summary>
/// 悬崖检测器:检测角色前方是不是有地面
/// 在角色前方偏下放置一个射线,朝下方投射
/// </summary>
public partial class CliffDetector : RayCast2D
{
public override void _Ready()
{
Enabled = true;
// 射线向下投射
TargetPosition = new Vector2(0f, 20f);
}
/// <returns>true = 前方有地面,false = 前方是悬崖</returns>
public bool HasGroundAhead()
{
ForceRaycastUpdate();
return IsColliding();
}
}GDScript
# 敌人视线检测:用射线检测能不能看到玩家
# 节点结构:
# Enemy (CharacterBody2D)
# ├── SightRay (RayCast2D)
# └── ...
extends CharacterBody2D
@onready var sight_ray: RayCast2D = $SightRay
var detection_range: float = 300.0
func _ready() -> void:
sight_ray.enabled = true
func _physics_process(_delta: float) -> void:
# 检查是否看到了玩家
if can_see_player():
print("发现玩家!追击!")
# ... 追击逻辑
## 检查射线是否碰到了玩家
func can_see_player() -> bool:
# 强制更新射线(在当前帧立即获取结果)
sight_ray.force_raycast_update()
if not sight_ray.is_colliding():
return false
var collider = sight_ray.get_collider()
# 检查碰到的物体是不是玩家
return collider is Player
## 让射线朝向指定位置
func look_at_target(target_position: Vector2) -> void:
# 计算从敌人到目标的方向
var direction := (target_position - global_position).normalized()
# 设置射线终点(朝向目标方向,指定距离)
sight_ray.target_position = direction * detection_range射线的 Enabled 默认是 false!
如果你在编辑器中添加了 RayCast 节点但忘了勾选 Enabled,射线不会工作。记得在编辑器的属性面板中勾选,或者在代码中设置 Enabled = true。
