- 文档
- 教程
- 游戏开发
【免费下载链接】godot-docs
Godot Engine official documentation
本文围绕 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_intersections | int | 32 | 该结果对象最多可以存储的相交数量上限 |
属性描述原文为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
相关推荐
douyin-downloader 抖音无水印下载完整指南:3 步完成首次批量下载
douyin downloader 抖音无水印下载完整指南:3 步完成首次批量下载 douyin downloader 是一款免费的抖音无水印下载工具:粘贴视频
文档教程游戏开发Godot Shape2D 详解:2D 物理碰撞形状基类、自定义 Solver Bias 与碰撞检测 API 实战
Godot Shape2D 详解:2D 物理碰撞形状基类、自定义 Solver Bias 与碰撞检测 API 实战 Shape2D 是 Godot 引擎中所有
文档教程游戏开发k-skill lotto-results:第三方商标在查询型技能中的合规使用边界与实现佐证
k skill lotto results:第三方商标在查询型技能中的合规使用边界与实现佐证 本文围绕 lotto results 技能的商标法律声明 http
后端即时通讯API设计
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考