PhysicsDirectSpaceState2D.intersect_ray
2026/4/14大约 4 分钟
最后同步日期:2026-04-15 | Godot 官方原文 — PhysicsDirectSpaceState2D.intersect_ray
PhysicsDirectSpaceState2D.intersect_ray
定义
intersect_ray 就是从一个点发出一条看不见的"射线",检测射线沿途碰到了哪些物体。就像激光笔照射一样——射线从起点出发,沿着指定方向飞行,碰到第一个物体就停下来,告诉你"碰到了什么、在哪里碰到的"。
打个比方:想象你站在房间里用手电筒照前方。光束打到墙壁上形成一个光斑。intersect_ray 就是这个手电筒——你告诉它"从哪里照、往哪个方向照",它告诉你"照到了什么、照到的位置在哪"。
在实际游戏开发中,射线检测是最常用的物理查询之一:检测视线是否被遮挡、判断鼠标点击了哪个物体、实现子弹射击命中判定等。
函数签名
C#
public Dictionary IntersectRay(PhysicsRayQueryParameters2D parameters)GDScript
func intersect_ray(parameters: PhysicsRayQueryParameters2D) -> Dictionary参数说明
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
parameters | PhysicsRayQueryParameters2D | 是 | 射线查询参数,包含起点、终点、碰撞掩码等 |
PhysicsRayQueryParameters2D 常用属性
| 属性 | 类型 | 说明 |
|---|---|---|
From / from | Vector2 | 射线起点 |
To / to | Vector2 | 射线终点 |
CollisionMask / collision_mask | int | 碰撞层掩码,只检测指定层 |
Exclude / exclude | Array | 排除的物体列表(如排除自身) |
HitFromInside / hit_from_inside | bool | 是否检测从内部开始的碰撞 |
返回值
Dictionary —— 如果射线碰到了物体,返回包含以下键的字典:
| 键 | 类型 | 说明 |
|---|---|---|
position | Vector2 | 碰撞点的位置 |
normal | Vector2 | 碰撞面的法线方向 |
collider | Object | 碰撞的物体节点 |
collider_id | int | 碰撞物体的实例 ID |
rid | RID | 碰撞物体的资源 ID |
如果没碰到任何东西,返回空字典 {}。
代码示例
基础用法:从角色前方发射射线
C#
using Godot;
public partial class RaycastTest : CharacterBody2D
{
public override void _PhysicsProcess(double delta)
{
var spaceState = GetWorld2D().DirectSpaceState;
var query = PhysicsRayQueryParameters2D.Create(
GlobalPosition,
GlobalPosition + new Vector2(100, 0) // 向右 100 像素
);
var result = spaceState.IntersectRay(query);
if (result.Count > 0)
{
GD.Print($"射线碰到了:{result["collider"]}");
// 运行结果: 打印碰到的物体信息
}
}
}GDScript
extends CharacterBody2D
func _physics_process(delta):
var space_state = get_world_2d().direct_space_state
var query = PhysicsRayQueryParameters2D.create(
global_position,
global_position + Vector2(100, 0) # 向右 100 像素
)
var result = space_state.intersect_ray(query)
if result:
print("射线碰到了:%s" % result["collider"])
# 运行结果: 打印碰到的物体信息实际场景:检测前方是否有地面(地面检测)
C#
using Godot;
public partial class Player : CharacterBody2D
{
[Export] public float ExRayLength = 50.0f;
private bool IsNearEdge()
{
var spaceState = GetWorld2D().DirectSpaceState;
// 从角色脚底向下发射射线
var origin = GlobalPosition + new Vector2(15, 0); // 偏右一点
var target = origin + new Vector2(0, ExRayLength);
var query = PhysicsRayQueryParameters2D.Create(origin, target);
query.CollisionMask = 1; // 只检测地面层
var result = spaceState.IntersectRay(query);
// 如果没碰到地面,说明前方是悬崖
return result.Count == 0;
// 运行结果: 前方有地面返回 false(没有悬崖),没有地面返回 true(有悬崖)
}
}GDScript
extends CharacterBody2D
@export var ray_length: float = 50.0
func is_near_edge() -> bool:
var space_state = get_world_2d().direct_space_state
# 从角色脚底向下发射射线
var origin = global_position + Vector2(15, 0) # 偏右一点
var target = origin + Vector2(0, ray_length)
var query = PhysicsRayQueryParameters2D.create(origin, target)
query.collision_mask = 1 # 只检测地面层
var result = space_state.intersect_ray(query)
# 如果没碰到地面,说明前方是悬崖
return result.is_empty()
# 运行结果: 前方有地面返回 false,没有地面返回 true(悬崖)进阶用法:视线检测(排除自身)
C#
using Godot;
public partial class EnemyAI : CharacterBody2D
{
[Export] public float ExSightRange = 300.0f;
private CharacterBody2D _player;
public override void _Ready()
{
_player = GetNode<CharacterBody2D>("/root/Game/Player");
}
public bool CanSeePlayer()
{
var spaceState = GetWorld2D().DirectSpaceState;
var query = PhysicsRayQueryParameters2D.Create(
GlobalPosition,
_player.GlobalPosition
);
// 排除自身,避免射线碰到自己
query.Exclude = new Godot.Collections.Array<Rid> { GetRid() };
query.CollisionMask = 1 | 2; // 检测地面层和玩家层
var result = spaceState.IntersectRay(query);
if (result.Count > 0)
{
var collider = result["collider"].AsGodotObject();
bool seesPlayer = collider == _player;
float distance = GlobalPosition.DistanceTo(_player.GlobalPosition);
// 运行结果: 如果射线直接碰到玩家(中间没有障碍物)返回 true
return seesPlayer && distance <= ExSightRange;
}
return false;
}
}GDScript
extends CharacterBody2D
@export var sight_range: float = 300.0
@onready var _player: CharacterBody2D = %Player
func can_see_player() -> bool:
var space_state = get_world_2d().direct_space_state
var query = PhysicsRayQueryParameters2D.create(
global_position,
_player.global_position
)
# 排除自身,避免射线碰到自己
query.exclude = [get_rid()]
query.collision_mask = 1 | 2 # 检测地面层和玩家层
var result = space_state.intersect_ray(query)
if result:
var collider = result["collider"]
var sees_player = collider == _player
var distance = global_position.distance_to(_player.global_position)
# 运行结果: 如果射线直接碰到玩家(中间没有障碍物)返回 true
return sees_player and distance <= sight_range
return false注意事项
- 必须在
_PhysicsProcess中调用:intersect_ray应该在物理帧(_PhysicsProcess)中调用,确保物理世界状态是最新的。 - 排除自身很重要:如果射线从自身内部发出,会先碰到自己。使用
query.Exclude排除自身的 RID。 - 碰撞层掩码:通过
CollisionMask可以指定只检测特定层的物体,避免不必要的碰撞。 - 返回空字典表示没碰到:GDScript 中空字典
{}是 falsy 的,可以直接用if result:判断。 - 2D 和 3D 的区别:2D 使用
PhysicsDirectSpaceState2D,3D 使用PhysicsDirectSpaceState3D,API 基本相同只是 Vector2/3 的区别。
