☰
Godot 2D 形状相交查询结果类 PhysicsIntersectShapeResult2D 详解与实战
2026/10/13 14:36:34 网站建设 项目流程
  • 文档
  • 教程
  • 游戏开发

【免费下载链接】godot-docs

Godot Engine official documentation

项目地址:https://gitcode.com/GitHub_Trending/go/godot-docs
点击查看免费下载

本文围绕 Godot 引擎 2D 物理体系中的PhysicsIntersectShapeResult2D结果类展开,讲解它如何承接PhysicsDirectSpaceState2D.intersect_shape_into()产生的形状相交数据,并通过max_intersections与五个取值方法完成多命中对象的读取。读完本文,你将掌握"形状区域查询 + 结果对象复用"这一零分配、可限制命中数量的物理查询模式,并能在 GDScript 与 C# 中独立写出完整的形状探测代码。

类概览:形状相交查询的结果容器

PhysicsIntersectShapeResult2D是 Godot 2D 物理查询体系中专门用于承载"形状与空间中其他形状相交"结果的对象。它的官方定位是Stores the results of a shape intersection query,即"存储一次形状相交查询的结果",其类参考文档位于 classes/class_physicsintersectshaperesult2d.rst。

它的继承关系为:

PhysicsIntersectShapeResult2D < RefCounted < Object

继承自RefCounted意味着该对象由引用计数管理,当不再有任何引用指向它时会被自动释放,因此不需要手动free()。它的直接上游是 PhysicsDirectSpaceState2D:该结果对象本身不能独立产生数据,而是由PhysicsDirectSpaceState2D.intersect_shape_into()在查询成功后把相交信息写入其中。这一"查询方法 + 结果对象"的配对模式在 Godot 4 中是一套贯穿 2D/3D 物理查询的统一设计。

该结果对象可以同时存放多个相交命中(multiple intersections),具体容量由用户通过max_intersections属性控制,默认上限为 32。

核心属性:max_intersections 控制命中容量

PhysicsIntersectShapeResult2D只有一个属性:

属性类型默认值说明
max_intersectionsint32该结果对象最多可以存储的相交数量上限

属性描述原文为The maximum number of intersections this result object can store。它通过set_max_intersections(value)与get_max_intersections()两个访问器读写。

从 PhysicsDirectSpaceState2D.intersect_shape_into() 的方法说明可以确认其用途:查询命中后相交数据被写入结果对象,而"相交数量可以通过max_intersections来限制,以减少处理时间"(The number of intersections can be limited usingmax_intersections, to reduce the processing time)。

实践要点:

  • 默认 32 足够覆盖绝大多数场景(如技能范围探测、AI 感知圈),通常无需修改;
  • 当查询区域可能同时命中大量对象、而你只关心前几个结果时,把max_intersections调小可以显著减少物理引擎的整理与存储开销;
  • 由于该对象通常复用(见下文"复用结果对象"),建议在初始化阶段就设置好容量,避免在热循环中反复调整。

五个取值方法:逐条读取命中信息

结果对象通过以下 5 个方法按索引(intersection_index)访问每一次命中。索引从 0 开始,有效范围是0到get_intersection_count() - 1。

方法签名返回类型含义
get_collider(intersection_index)Object发生碰撞的对象(碰撞体节点实例)
get_collider_id(intersection_index)int碰撞对象的 ObjectID
get_collider_rid(intersection_index)RID相交对象的 RID(服务器层标识)
get_collider_shape(intersection_index)int被碰撞形状在其所属对象上的形状索引(shape index)
get_intersection_count()int与查询形状相交的形状总数

其中get_intersection_count()是整个结果对象的"总数入口",其余四个方法都需要传入intersection_index定位到具体某一次命中。四个取值方法返回的信息维度各不相同,在实际开发中通常组合使用:

  • get_collider()返回的是场景节点层对象,适合直接做类型判断(is Area2D、is CharacterBody2D等)、访问其脚本或属性、调用其方法;
  • get_collider_id()返回对象的唯一 ID,适合做去重、缓存或跨帧追踪,即使对象后来被释放也能通过 ID 判断是否见过;
  • get_collider_rid()返回物理服务器层面的 RID,是对象在PhysicsServer2D中的身份标识,适合与服务器 API 交互或在exclude列表中使用;
  • get_collider_shape()返回碰撞形状索引,当同一对象挂着多个CollisionShape2D时,用它区分到底是哪个子形状被命中。

与intersect_shape()(返回字典数组)不同,这四个方法都是const方法(文档中以const标注,表示不修改实例状态、无副作用),因此可以在任意时间重复读取,无需担心查询结果被破坏。

完整实战:从查询参数到结果遍历

第一步:获取 2D 空间状态

PhysicsIntersectShapeResult2D依赖PhysicsDirectSpaceState2D产生数据。后者不能直接实例化,需要通过World2D.direct_space_state获取(见 PhysicsDirectSpaceState2D 文档说明)。官方 ray-casting 教程 强调:物理空间只在_physics_process()回调期间可以安全访问,在其它时机访问可能因空间被锁定而报错。

extends Node2D func _physics_process(_delta): var space_state := get_world_2d().direct_space_state # 在 _physics_process 内执行查询…
using Godot; public partial class MyNode2D : Node2D { public override void _PhysicsProcess(double delta) { var spaceState = GetWorld2D().DirectSpaceState; // 在 _PhysicsProcess 内执行查询… } }

第二步:构建查询参数 PhysicsShapeQueryParameters2D

intersect_shape_into()的第一参数是 PhysicsShapeQueryParameters2D,它集中描述了查询形状、位置姿态与过滤规则:

var params := PhysicsShapeQueryParameters2D.new() params.shape = preload("res://query_shape.tres") # 查询用的 Shape2D 资源 params.transform = Transform2D(0, global_position) # 形状在全局坐标系中的位置 params.collision_mask = 0b0001 # 只查询第 1 层 params.collide_with_areas = true # 是否把 Area2D 计入结果(默认 false) params.collide_with_bodies = true # 是否把 PhysicsBody2D 计入结果(默认 true) params.exclude = [self] # 排除自身,避免"自命中"

各过滤属性默认值如下(均可在 PhysicsShapeQueryParameters2D 文档中核实):collide_with_areas = false、collide_with_bodies = true、collision_mask = 4294967295(即检测所有碰撞层)、exclude = []、margin = 0.0、motion = Vector2(0, 0)、transform为单位矩阵。

注意exclude数组的语义:它存放的是对象 RID 列表,可以用CollisionObject2D.get_rid()获取某个 2D 碰撞对象的 RID(见 CollisionObject2D 文档)。官方文档还特别提示:该数组返回的是副本,修改后需要重新赋值回属性才生效。

第三步:复用结果对象并执行查询

intersect_shape_into()的签名是bool intersect_shape_into(parameters: PhysicsShapeQueryParameters2D, result: PhysicsIntersectShapeResult2D)。与返回新分配的字典数组的intersect_shape()不同,它把数据写入调用方传入的预分配结果对象,从而避免每帧分配新数组——这是"into 系列"方法(intersect_point_into、intersect_ray_into、collide_shape_into、get_rest_info_into、cast_motion_into)的共同设计。

var result := PhysicsIntersectShapeResult2D.new() result.max_intersections = 8 # 本帧最多取前 8 个命中,降低处理开销 func _physics_process(_delta): var space_state := get_world_2d().direct_space_state var params := PhysicsShapeQueryParameters2D.new() params.shape = my_shape params.transform = Transform2D(0, global_position) params.collide_with_bodies = true if space_state.intersect_shape_into(params, result): for i in result.get_intersection_count(): var collider := result.get_collider(i) var collider_id := result.get_collider_id(i) var rid := result.get_collider_rid(i) var shape_idx := result.get_collider_shape(i) print("命中对象: ", collider, " ID: ", collider_id, " RID: ", rid, " 形状索引: ", shape_idx) else: print("本次查询没有任何形状相交")
using Godot; public partial class MyNode2D : Node2D { private PhysicsIntersectShapeResult2D _result = new() { MaxIntersections = 8 }; public override void _PhysicsProcess(double delta) { var spaceState = GetWorld2D().DirectSpaceState; var parameters = new PhysicsShapeQueryParameters2D { Shape = MyShape, Transform = new Transform2D(0, GlobalPosition), CollideWithBodies = true }; if (spaceState.IntersectShapeInto(parameters, _result)) { for (int i = 0; i < _result.GetIntersectionCount(); i++) { var collider = _result.GetCollider(i); var colliderId = _result.GetColliderId(i); var rid = _result.GetColliderRid(i); var shapeIdx = _result.GetColliderShape(i); GD.Print($"命中对象: {collider}, ID: {colliderId}, RID: {rid}, 形状索引: {shapeIdx}"); } } else { GD.Print("本次查询没有任何形状相交"); } } }

第四步:验证查询是否成功

intersect_shape_into()的返回值本身就是查询结果标志:若发现一个或多个形状与查询形状相交,返回true并把数据写入结果对象;若没有任何相交,返回false。因此最稳妥的读取习惯是:先判断返回值,再遍历get_intersection_count()。如果直接忽略返回值,在零命中的情况下遍历次数为 0,虽然不会崩溃,但容易掩盖"查询到底有没有执行"的问题。

与 intersect_shape() 字典版本的对比

PhysicsDirectSpaceState2D同时提供intersect_shape()与intersect_shape_into()两个形状查询入口,两者结果形态不同(均可参考 PhysicsDirectSpaceState2D 文档):

  • intersect_shape(parameters, max_results = 32)返回Array[Dictionary],每个字典包含collider、collider_id、rid、shape四个字段,与结果对象的方法一一对应,但每次调用都会分配新数组;
  • intersect_shape_into(parameters, result)返回bool,把数据写入调用方持有的PhysicsIntersectShapeResult2D。
维度intersect_shape()intersect_shape_into() + PhysicsIntersectShapeResult2D
返回形式字典数组(每次分配)预分配结果对象(可复用)
命中上限max_results参数max_intersections属性
典型场景偶尔查询、代码简洁优先每帧/高频查询、追求低分配
失败信号空数组返回false

高频物理查询(如每帧执行的角色脚下探测、持续性的范围感知)建议优先使用intersect_shape_into()加结果对象复用的组合,以减少每帧的对象分配与 GC 压力。

查询参数细节:影响结果的六个开关

结果对象本身只负责存储,命中哪些对象由PhysicsShapeQueryParameters2D决定。理解以下参数能精确控制PhysicsIntersectShapeResult2D里装入什么:

  • shape与shape_rid:shape持有Shape2D资源引用,文档明确建议优先使用它,因为它持有实际引用、避免形状在查询期间被释放;shape_rid则用于走 Servers API 的高性能路径,可用PhysicsServer2D.circle_shape_create()等创建服务器形状后直接赋值;
  • transform:查询形状在全局坐标中的Transform2D,决定形状的位置与旋转;查询使用的是全局坐标而非节点局部坐标;
  • collision_mask:以位掩码指定要检测的物理层,默认4294967295表示全层检测;
  • collide_with_areas/collide_with_bodies:默认false/true,即默认只命中PhysicsBody2D类对象;需要把Area2D也纳入结果时,必须显式打开collide_with_areas;
  • exclude:从结果中剔除指定 RID 的对象,典型用途是查询发起者自身,避免"自命中";
  • margin:形状的碰撞边距,默认0.0;调大边距会使查询形状在物理上"变胖",用于容忍微小间隙的探测场景。

调用时机:为什么必须在 _physics_process 内查询

ray-casting 教程 明确指出:Godot 物理默认与游戏逻辑同线程运行,但也可配置为独立线程;因此访问空间状态的安全时机仅限于Node._physics_process()回调,从该函数之外访问可能因空间处于锁定状态而报错。这一约束同样适用于使用PhysicsIntersectShapeResult2D的intersect_shape_into()查询。若确需在_input()等时机做形状探测,应先把查询意图记录下来,延迟到下一个_physics_process()中执行。

3D 对应类:PhysicsIntersectShapeResult3D

2D 与 3D 的物理查询 API 保持对称。3D 空间中的对应结果是 PhysicsIntersectShapeResult3D,它拥有完全相同的属性与五个方法(max_intersections、get_collider、get_collider_id、get_collider_rid、get_collider_shape、get_intersection_count),由 PhysicsDirectSpaceState3D.intersect_shape_into() 填充,查询参数则对应为PhysicsShapeQueryParameters3D。换言之,理解本文的 2D 结果对象后,迁移到 3D 只需替换类名与坐标系类型。

一个值得注意的差异:PhysicsDirectSpaceState3D.intersect_shape_into()的方法说明中额外注明"该方法不考虑motion属性"(This method does not take into account the motion property of the object)。在 2D 的对应方法文档中未见此限制,但在依赖motion做扫掠式(sweep)查询时,仍应优先使用专门的cast_motion/cast_motion_into流程。

典型应用场景

PhysicsIntersectShapeResult2D适合一切"用一个形状去探测一片区域内的所有对象"的需求:

  • 技能/武器命中判定:在角色面前生成扇形或圆形查询形状,一次性取回所有被击中的敌人,再按get_collider_id()去重;
  • AI 感知:以圆形或锥形形状模拟视野/听觉范围,每帧把范围内的玩家与友军装入结果对象;
  • 道具拾取与交互:在交互点放置小圆形查询形状,检测玩家是否站在可交互物附近;
  • 地形/平台探测:角色脚下放置胶囊或矩形探测形状,判断脚下是否有可站立表面(配合collide_with_bodies = true、exclude = [self]);
  • 群体验证:结合max_intersections设定上限,只关心"范围内是否超过 N 个敌人"这类阈值判断,提前结束处理。

以上场景都能复用同一套模式:构建PhysicsShapeQueryParameters2D→ 调用intersect_shape_into()→ 判读返回值 → 遍历get_intersection_count()逐条读取。

延伸阅读

  • PhysicsIntersectShapeResult2D 类参考:本文主文档,属性与方法签名权威出处;
  • PhysicsDirectSpaceState2D 类参考:查询入口intersect_shape_into()及其姊妹查询方法;
  • PhysicsShapeQueryParameters2D 类参考:查询参数的全部属性与默认值;
  • PhysicsIntersectShapeResult3D 类参考:3D 对称实现;
  • Ray-casting 教程:空间状态获取、_physics_process调用约束与exclude用法;
  • CollisionObject2D 类参考:get_rid()与碰撞层/掩码相关接口;
  • PhysicsDirectSpaceState2DExtension 类参考:自定义物理服务器接入时的空间状态扩展点。
  • 文档
  • 教程
  • 游戏开发

【免费下载链接】godot-docs

Godot Engine official documentation

项目地址:https://gitcode.com/GitHub_Trending/go/godot-docs
点击查看免费下载

相关推荐

上一篇:JetBrains IDE 试用期重置终极方案:告别30天限制的完整指南
下一篇:DLSS Swapper深度解析:三分钟掌握游戏超采样文件管理技巧

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询