本文档介绍了 BooleanSpriteCutterWithTaggedShapes 脚本和 Fragment Manager 脚本。
注意:第 1 部分在此处 BooleanSpriteCutterWithTaggedShapes / FragmentManager English Manual Part 1(About Sample Project)
BooleanSpriteCutterWithTaggedShapes 概述
BooleanSpriteCutterWithTaggedShapes 是一个 Node2D 脚本,它针对指定组中的 Sprite2D 节点(以及可选的重新切割片段),使用来自另一个组的“遮罩形状节点”来切割相交区域,通过沃罗诺伊分割(Voronoi partitioning)和布尔运算将其碎片化,并生成 RigidBody2D 碎片。
碎片被分类为内部(在遮罩内)和外部(剩余部分),您可以分别为每种类型配置力、物理、材质等。
功能
- 通过组批量处理多个目标精灵(一次切割多个)
- 从另一个组收集遮罩形状(顺序处理多个遮罩)
- 内部/外部**力(方向/强度/扭矩)**的独立设置
- 碎片物理设置模式:手动 / 继承自 Sprite / 继承自 Shape / 继承自指定节点
- 碎片生成父节点模式:自身 / 指定节点 / 所有者的父节点 / 所有者的子节点 / 管理器
- 支持重新切割(再次碎片化),内部/外部有独立的允许标志
- 支持边缘线(
Line2D)和材质继承/覆盖
前置条件和需求
| 项目 |
内容 |
| 所需插件 |
res://addons/gdDelaunay/Delaunay.gd 必须存在(已 preload) |
| 目标 |
target_sprite_group 中的 Sprite2D(需要纹理)/ 可重新切割的 RigidBody2D 碎片 |
| 遮罩 |
shape_node_group 中的形状节点(支持的类型如下) |
| 相交 |
仅当遮罩 AABB 与目标 AABB 相交且存在多边形相交时才进行切割 |
| 注意 |
对于精灵基础多边形,仅使用 opaque_to_polygons() 的第一个元素(具有多个不透明岛屿的材质可能与预期行为不同) |
设置
- 在场景中放置一个
Node2D 并附加此脚本。
- 将您要破碎的
Sprite2D 添加到 target_sprite_group(默认:SpriteGroup)。
- 将遮罩节点添加到
shape_node_group(默认:CutterShapeGroup)。
- 示例:
Polygon2D / CollisionPolygon2D / CollisionShape2D(凸/凹/圆/矩形)
- 在检查器中配置参数(最小要求:
alpha_threshold、simplify_tolerance、voronoi_seed_count)。
- 在所需时刻调用
call_cut()。
生成的节点规范
| 生成的对象 |
结构 |
元数据 / 组 |
备注 |
| 内部碎片 |
RigidBody2D(子节点:Polygon2D + CollisionPolygon2D + 可选的 Line2D) |
META_IS_FRAGMENT=true / META_FRAGMENT_TYPE="inside" / META_FRAGMENT_SOURCE_SPRITE=源 Sprite / 添加到 target_sprite_group |
如果 unfreeze_delay>0,碎片将暂时冻结,然后在计时器结束后解冻并施加力 |
| 外部碎片 |
同上 |
META_FRAGMENT_TYPE="outside" |
应用外部力/物理/材质设置 |
源 Sprite2D |
隐藏 |
META_ALREADY_CUT=true |
防止对同一精灵进行双重切割 |
| 重新切割源(碎片) |
queue_free() |
- |
在重新切割期间,原始碎片被替换 |
使用示例
| 目标(用例) |
设置 |
结果 |
备注 |
| 仅切割被遮罩触碰的区域 |
将遮罩形状添加到 shape_node_group → call_cut() |
仅相交的精灵生成碎片 |
多个遮罩按顺序处理 |
| 将内部碎片向右抛出 |
inside_force_direction_mode=FixedVector,inside_force_fixed_vector=(1,0) |
内部碎片沿恒定方向飞行 |
强度为 inside_force_base_strength |
| 从爆炸中心径向散射 |
*_force_direction_mode=ExplosionFromPoint,设置 *_explosion_center_node |
碎片向外散射 |
您可以通过 call_cut(force_config) 覆盖中心 |
| 较大的碎片获得更强的力/旋转 |
use_area_scaling_for_impulse=true / use_area_scaling_for_torque=true |
力和扭矩按面积比例缩放 |
由 area_ratio_min/max 限制 |
| 将碎片组织到特定节点下 |
fragment_parent_mode=SpecifiedNode(设置 fragment_parent_node) |
碎片分组在指定节点下 |
您也可以选择 Manager |
| 重新切割(完成切割) |
allow_recutted_inside_fragments=true(和/或外部) |
下次 call_cut() 也包括碎片 |
碎片添加到 target_sprite_group |
| 切割后禁用附近碰撞 |
disable_related_collisions_on_cut=true |
禁用原始精灵周围的碰撞 |
生成的碎片(META_IS_FRAGMENT)被排除 |
属性列表
基础
| 属性 |
类型 / 默认值 |
描述(行为/计算/备注) |
target_sprite_group |
String / "SpriteGroup" |
收集切割目标的组名(Sprite2D 和允许的碎片) |
shape_node_group |
String / "CutterShapeGroup" |
收集遮罩形状节点的组名 |
alpha_threshold |
float / 0.1 |
BitMap.create_from_image_alpha 的不透明阈值(alpha >= 阈值即为不透明) |
simplify_tolerance |
float / 2.0 |
opaque_to_polygons() 的简化容差(越高越轻量但粗糙) |
voronoi_seed_count |
int / 10 |
沃罗诺伊种子数量(碎片越多,计算越重) |
density |
float / 1.0 |
质量系数:mass = area_world * density |
unfreeze_delay |
float / 0.0 |
解冻生成身体前的延迟秒数(>0 产生暂时暂停效果) |
circle_approx_segments |
int / 32 |
将 CircleShape2D 近似为多边形的段数 |
debug_log |
bool / false |
如果为 true,则打印处理日志(通常保持 false) |
沃罗诺伊种子分布
| 属性 |
类型 / 默认值 |
描述 |
voronoi_seed_density_mode |
enum / Uniform |
Uniform / TowardMaskCenter / TowardSpriteCenter / TowardNodeCenter |
voronoi_seed_density_power |
float / 2.0 |
居中偏置的强度(pow(t, power)) |
voronoi_seed_center_node |
NodePath / 空 |
TowardNodeCenter 的中心(Node2D.global_position) |
力设置(内部)
| 属性 |
类型 / 默认值 |
描述 |
inside_force_base_strength |
float / 1000.0 |
内部碎片的基础冲量强度 |
inside_force_strength_jitter_ratio |
float / 0.0 |
强度抖动(±比例;方向固定) |
inside_force_direction_mode |
enum / FixedVector |
FixedVector / ExplosionFromPoint |
inside_force_fixed_vector |
Vector2 / (1,0) |
FixedVector 的方向(内部归一化) |
inside_explosion_center_node |
NodePath / 空 |
ExplosionFromPoint 的爆炸中心 Node2D |
inside_torque_impulse |
float / 0.0 |
施加给内部碎片的扭矩 |
力设置(外部)
| 属性 |
类型 / 默认值 |
描述 |
outside_force_base_strength |
float / 600.0 |
外部碎片的基础冲量强度 |
outside_force_strength_jitter_ratio |
float / 0.0 |
强度抖动(±比例) |
outside_force_direction_mode |
enum / FixedVector |
FixedVector / ExplosionFromPoint |
outside_force_fixed_vector |
Vector2 / (0,-1) |
FixedVector 的方向 |
outside_explosion_center_node |
NodePath / 空 |
爆炸中心 |
outside_torque_impulse |
float / 0.0 |
施加给外部碎片的扭矩 |
大小缩放
| 属性 |
类型 / 默认值 |
描述 |
use_area_scaling_for_impulse |
bool / true |
按面积比例缩放冲量 |
use_area_scaling_for_torque |
bool / true |
按面积比例缩放扭矩 |
area_ratio_min |
float / 0.2 |
面积比例的最小限制 |
area_ratio_max |
float / 3.0 |
面积比例的最大限制 |
impulse_area_exponent |
float / 0.5 |
impulse_scale = pow(area_ratio, exponent) |
torque_area_exponent |
float / 1.0 |
torque_scale = pow(area_ratio, exponent) |
材质设置(通用 / 内部 / 外部)
| 属性 |
类型 / 默认值 |
描述 |
fragment_inherit_material |
bool / true |
继承原始材质(通用默认值) |
fragment_use_custom_material |
bool / false |
强制应用通用自定义材质 |
fragment_custom_material |
Material / null |
通用自定义材质 |
inside_fragment_inherit_material |
bool / true |
仅内部:是否继承 |
inside_fragment_use_custom_material |
bool / false |
仅内部:使用自定义材质 |
inside_fragment_custom_material |
Material / null |
仅内部材质 |
outside_fragment_inherit_material |
bool / true |
仅外部:是否继承 |
outside_fragment_use_custom_material |
bool / false |
仅外部:使用自定义材质 |
outside_fragment_custom_material |
Material / null |
仅外部材质 |
边缘线设置
| 属性 |
类型 / 默认值 |
描述 |
draw_edge_line |
bool / true |
使用 Line2D 绘制碎片边缘 |
edge_line_width |
float / 2.0 |
线宽 |
edge_line_color_inside |
Color / 白色 |
内部线条颜色 |
edge_line_color_outside |
Color / 白色 |
外部线条颜色 |
重新切割设置
| 属性 |
类型 / 默认值 |
描述 |
allow_recutted_inside_fragments |
bool / false |
在下一次切割中将内部碎片作为目标 |
allow_recutted_outside_fragments |
bool / false |
在下一次切割中将外部碎片作为目标 |
禁用原始碰撞
| 属性 |
类型 / 默认值 |
描述 |
disable_related_collisions_on_cut |
bool / false |
扫描并禁用原始精灵周围的碰撞(排除生成的碎片) |
碎片父节点(生成目标)
| 属性 |
类型 / 默认值 |
描述 |
fragment_parent_mode |
enum / Self |
Self / SpecifiedNode / OwnerParent / OwnerChild / Manager |
fragment_parent_node |
NodePath / 空 |
SpecifiedNode 的生成目标 |
| 备注 |
- |
OwnerChild 在重新切割时应用回退(所有者是碎片) |
碎片物理(内部)
| 属性 |
类型 / 默认值 |
描述 |
inside_fragment_physics_mode |
enum / FromSprite |
Manual / FromSprite / FromShape / FromSpecified |
inside_fragment_physics_reference_node |
NodePath / 空 |
FromSpecified 的参考节点 |
inside_fragment_gravity_scale_manual |
float / 1.0 |
手动:重力比例 |
inside_fragment_collision_layer_manual |
int(flags) / 1 |
手动:碰撞层 |
inside_fragment_collision_mask_manual |
int(flags) / 1 |
手动:碰撞掩码 |
inside_fragment_linear_damp_manual |
float / 0.0 |
手动:线性阻尼 |
inside_fragment_angular_damp_manual |
float / 0.0 |
手动:角阻尼 |
inside_fragment_physics_material_manual |
PhysicsMaterial / null |
手动:摩擦/弹跳 |
inside_fragment_lock_rotation_manual |
bool / false |
手动:锁定旋转 |
碎片物理(外部)
| 属性 |
类型 / 默认值 |
描述 |
outside_fragment_physics_mode |
enum / FromSprite |
Manual / FromSprite / FromShape / FromSpecified |
outside_fragment_physics_reference_node |
NodePath / 空 |
FromSpecified 的参考节点 |
outside_fragment_gravity_scale_manual |
float / 1.0 |
手动:重力比例 |
outside_fragment_collision_layer_manual |
int(flags) / 1 |
手动:碰撞层 |
outside_fragment_collision_mask_manual |
int(flags) / 1 |
手动:碰撞掩码 |
outside_fragment_linear_damp_manual |
float / 0.0 |
手动:线性阻尼 |
outside_fragment_angular_damp_manual |
float / 0.0 |
手动:角阻尼 |
outside_fragment_physics_material_manual |
PhysicsMaterial / null |
手动:摩擦/弹跳 |
outside_fragment_lock_rotation_manual |
bool / false |
手动:锁定旋转 |
管理器集成
| 属性 |
类型 / 默认值 |
描述 |
manager_mode |
enum / Autoload |
None / Autoload / SpecifiedNode |
manager_autoload_name |
String / "FragmentManagerSingleton" |
Autoload 名称(引用 /root/<name>) |
manager_node |
NodePath / 空 |
SpecifiedNode 的引用目标 |
| 行为 |
- |
在生成碎片时,调用已解析的 Manager 上的 register_fragment(body)(仅当该方法存在时) |
运行时覆盖 (call_cut(force_config))
通过 call_cut() 的 force_config 参数,您可以仅在该次调用中覆盖检查器中的力设置。
| 目标 |
键 |
示例值 |
| 内部/外部 |
base_strength |
1400.0 |
| 内部/外部 |
strength_jitter_ratio |
0.15 |
| 内部/外部 |
direction_mode |
FORCE_DIR_FIXED_VECTOR 或 FORCE_DIR_EXPLOSION |
| 内部/外部 |
fixed_vector |
Vector2(1, 0) |
| 内部/外部 |
explosion_center |
Vector2(100, 200)(世界坐标) |
| 内部/外部 |
torque_impulse |
3.0 |
FragmentManager 概述
FragmentManager 是一个 Node2D 脚本,用于管理由 Cutter 生成的 RigidBody2D 碎片。碎片通过 register_fragment() 注册,它可以管理数量限制、TTL(生存时间)、静止冻结和可选的屏幕外删除,内部/外部有独立的策略。
功能
- 内部/外部独立的管理策略(限制、TTL、冻结、屏幕外删除)
- 通过
WeakRef 持有引用;如果碎片离开树结构,引用将自动清理
- 可选地在冻结时禁用碰撞(将层/掩码设置为 0)
- 屏幕外检查从视口
Camera2D 计算视图矩形(如果不可用则跳过)
前置条件和需求
- 假设使用 Godot 4.x 2D 节点结构。
- 管理的对象是传递给
register_fragment(body) 的 RigidBody2D。
body 必须具有 Cutter 设置的 META_FRAGMENT_TYPE("inside" / "outside")。
- 要排除某些碎片的管理,请设置
META_FRAGMENT_NO_MANAGE=true。
设置
- 将此脚本附加到
fragment_manager.tscn 的根节点。
- 将
fragment_manager.tscn 注册为 Autoload,使其保持在 /root 下。
- 确保 Cutter 在生成碎片时调用
FragmentManager.register_fragment(body)。
- 如果 Cutter 已经实现了“在生成时调用
register_fragment”,请确保 Autoload 名称和引用匹配。
生成/管理的数据
- 此节点保持为
Node2D,并在内部维护两个列表:
_fragments_inside
_fragments_outside
- 注册的碎片接收元数据:
_boolean_fragment(碎片标志)
_fragment_spawn_msec(生成时间,毫秒)
_fragment_last_active_msec(最后活跃时间,毫秒)
- 如果
inside_fragment_group_name / outside_fragment_group_name 非空,碎片在注册时将被添加到这些组。
使用示例
| 目标(用例) |
设置 |
结果 |
备注 |
| 防止碎片过多 |
设置 inside_max_fragments / outside_max_fragments |
超过限制时删除旧碎片 |
如果 <= 0,则无限制 |
| 随时间自然消失 |
*_enable_ttl=true,设置 *_ttl_seconds |
TTL 后删除 |
注册时记录生成时间 |
| 静止后停止物理 |
*_enable_freeze_on_settled=true |
低速持续后冻结 |
还可以选择禁用碰撞 |
| 收集屏幕外的碎片 |
*_delete_when_offscreen=true |
在屏幕外停留一定时间后删除 |
如果无法获取相机,则跳过检查 |
| 保留特定碎片 |
body.set_meta("_fragment_no_manage", true) |
管理器忽略该碎片 |
最好在生成后立即设置 |
属性列表 (FragmentManager)
| 属性 |
类型 / 默认值 |
描述(行为/计算/备注) |
inside_fragment_group_name |
String / "FragmentGroupInside" |
注册时添加到内部碎片的组名。如果为空,则不添加。 |
inside_max_fragments |
int / 300 |
内部碎片最大数量。如果 <= 0,则无限制。超出部分通过 queue_free() 按最旧顺序删除。 |
inside_enable_ttl |
bool / true |
启用内部碎片的 TTL 删除。 |
inside_ttl_seconds |
float / 8.0 |
生存时间(秒)。当 now - spawn_msec >= 此值时删除。 |
inside_enable_freeze_on_settled |
bool / true |
启用内部碎片的静止冻结。 |
inside_settled_linear_speed |
float / 15.0 |
线性速度阈值。高于此值视为“活跃”并更新最后活跃时间。 |
inside_settled_angular_speed |
float / 1.5 |
角速度阈值。高于此值视为“活跃”。 |
inside_settled_grace_seconds |
float / 0.6 |
如果低速状态持续此时间,则应用冻结。 |
inside_disable_collision_when_frozen |
bool / true |
冻结时,将碰撞层/掩码设置为 0。不执行解冻恢复。 |
inside_delete_when_offscreen |
bool / false |
启用内部碎片的屏幕外删除。 |
inside_offscreen_grace_seconds |
float / 1.0 |
如果屏幕外停留此时间,则删除。如果返回屏幕内,则更新最后活跃时间。 |
outside_fragment_group_name |
String / "FragmentGroupOutside" |
注册时添加到外部碎片的组名。如果为空,则不添加。 |
outside_max_fragments |
int / 300 |
外部碎片最大数量。如果 <= 0,则无限制。超出部分按最旧顺序删除。 |
outside_enable_ttl |
bool / true |
启用外部碎片的 TTL 删除。 |
outside_ttl_seconds |
float / 8.0 |
外部生存时间(秒)。过期时删除。 |
outside_enable_freeze_on_settled |
bool / true |
启用外部碎片的静止冻结。 |
outside_settled_linear_speed |
float / 15.0 |
外部碎片的线性速度阈值。 |
outside_settled_angular_speed |
float / 1.5 |
外部碎片的角速度阈值。 |
outside_settled_grace_seconds |
float / 0.6 |
外部碎片的低速宽限期。 |
outside_disable_collision_when_frozen |
bool / true |
冻结时,将碰撞层/掩码设置为 0。不恢复。 |
outside_delete_when_offscreen |
bool / false |
启用外部碎片的屏幕外删除。 |
outside_offscreen_grace_seconds |
float / 1.0 |
外部碎片的屏幕外宽限期(秒)。 |
debug_log |
bool / false |
如果为 true,则记录因限制/TTL/屏幕外等导致的删除。 |
1 个赞