By using this script, you can split/split sprites into arbitrary shapes, assign physical bodies, and create destruction effects.
You can freely set the size of fragments, physical properties, number of divisions, density gradients, materials, and more.
As an option, you can further divide the split fragments.
fragment_manager.gd (16.3 KB)
boolean_sprite_cutter_with_tagged_shapes.gd (59.0 KB)
BooleanSpriteCutterWithTaggedShapesSampleProject.zip (635.2 KB)

※ This script requires GDScript Delaunay + Voronoi.
※ Due to its complexity, we recommend downloading the sample project.
Usage Examples and Sample Project Explanation
0. Terminology
| Term | Meaning |
|---|---|
| Cutter | BooleanSpriteCutterWithTaggedShapes (The main cutting logic. Has call_cut()) |
| Cut Target | Sprite2D in target_sprite_group (Includes RigidBody2D fragments for re-cutting if needed) |
| Mask Shape | Shape nodes in shape_node_group (Circle, Rectangle, Polygon, etc.) |
| Inside Fragment | Fragments generated from the area overlapping the mask (_fragment_type="inside") |
| Outside Fragment | Fragments generated from the remaining area outside the mask (_fragment_type="outside") |
| Manager | FragmentManager (Automatically manages fragment lifespan, limits, etc. Usually runs as an Autoload) |
1. Setup (Creating a “Cuttable State”)
1-1. Enable gdDelaunay to use Voronoi splitting
Purpose
The Cutter performs Voronoi splitting to determine how to “divide” the fragments. It uses res://addons/gdDelaunay/Delaunay.gd for this Voronoi calculation. Therefore, the addon must exist in the project, and the Plugin must be enabled. If this is not configured, the Cutter cannot load Delaunay internally, and the cutting process will fail.
Setup Steps (When adding to your own project)
- Place
addons/gdDelaunay/in your project - In
Project > Project Settings > Plugins, enablegdDelaunay
In the Sample
res://addons/gdDelaunay/is includedres://addons/gdDelaunay/plugin.cfgis already registered in[editor_plugins] enabledinproject.godot
1-2. Make FragmentManager run as an Autoload (Recommended) to automatically manage fragments
Purpose
When cutting, many RigidBody2D fragments are generated. Since fragments have physics calculations, collision detection, and rendering, leaving them unmanaged can increase load. Running FragmentManager as an Autoload automates “fragment cleanup” as follows:
- Delete fragments after a certain time based on their lifespan (TTL)
- Delete oldest fragments if the fragment count exceeds the limit
- Freeze fragments when their speed drops sufficiently to reduce physics load
- (Optional) Delete fragments that move off-screen
Setup Steps (For operation similar to the sample)
- Prepare
fragment_manager.tscn(Ensure the rootNode2Dhas theFragmentManagerscript attached) - Add it to
Project > Project Settings > Autoload
- The Name must match the name referenced by the Cutter
- The Path specifies the location of
fragment_manager.tscn
In the Sample
- Autoload Name:
FragmentManagerSingleton - Path:
res://fragment_manager.tscn - Since this matches the default value on the Cutter side
manager_autoload_name="FragmentManagerSingleton", no additional configuration is needed for automatic linking.
1-3. Configure InputMap to allow calling cutting via input
Purpose
The Cutter is not a “node that monitors input,” but rather a “node that performs cutting when call_cut() is called.”
Therefore, you need an entry point to call call_cut() at any desired timing, such as player actions or button presses. The most convenient entry point in standard Godot is InputMap (Input Action).
Setup Steps (Minimal configuration for standard Godot input)
- Add an action to
Project > Project Settings > Input Map(e.g.,call_cut) - Assign a key (e.g., Space)
- Attach an input monitoring script to any node to call
call_cut()
In the Sample
call_cutis registered inInputMap- Space is assigned to
call_cut
1-4. Add the cut target Sprite2D to the “Target Group”
Purpose
The Cutter collects “cut target candidates” every time using get_tree().get_nodes_in_group(target_sprite_group).
Therefore, the Sprite2D you want to cut must definitely be in this group. If this is not set, calling call_cut() will result in “zero targets,” and visually nothing will happen.
Additionally, the Cutter reads the alpha from the sprite of the cut target to create a base polygon (the cuttable area). If the sprite has no texture attached, or if no opaque area can be obtained due to the alpha threshold, it will be skipped.
Setup Steps
- Select the
Sprite2Dyou want to cut - Add
SpriteGroup(or the group name specified on the Cutter side) to the Node’s Groups - Ensure
Sprite2D.textureis set
In the Sample
Egginres://sample.tscnis ingroups=["SpriteGroup"]
1-5. Add the mask shape nodes to the “Mask Group”
Purpose
The Cutter collects “mask shapes” from the group in shape_node_group and searches for “cut targets overlapping that shape” for each shape.
In other words, if you do not register any mask shapes, the Cutter cannot have a “criterion for cutting (what counts as inside),” and the cutting process cannot proceed.
The supported shapes are branched within the script, but typically handles:
Polygon2D/CollisionPolygon2DCollisionShape2D(CircleShape2D/RectangleShape2D/ConvexPolygonShape2D/ConcavePolygonShape2D, etc.)
Setup Steps
- Prepare the shape node you want to use as a mask (e.g.,
CollisionShape2D+CircleShape2D) - Add that node to Groups as
CutterShapeGroup(or the group name specified on the Cutter side) - Place it so it overlaps with the sprite you want to cut
- If the positional relationship is incorrect, it will be treated as “AABBs do not intersect” and processing will not occur.
In the Sample
CollisionShape2D2inres://spritecutter.tscnis ingroups=["CutterShapeGroup"]- Shape:
CircleShape2D,radius=135.004 - The mask shape is placed as a child of
BooleanSpriteCutterWithTaggedShapesand is positioned to overlap with the cut target in the scene.
1-6. Place the Cutter in the scene
Purpose
The Cutter operates on the premise that the following all “exist as nodes in the scene”:
- Search for groups from the SceneTree (collecting cut targets and mask shapes)
- Use
to_global()of mask shape nodes to convert shapes into polygons in world coordinates - Use
to_global()of cut target sprites to convert alpha-derived local polygons into world coordinates - Add generated fragments as children of “which node” (depends on the generation destination mode)
- If necessary, reference the explosion center node (
inside_explosion_center_node, etc.) viaNodePath
Therefore, simply placing the script is not enough; you must actually place the Cutter node in the scene and ensure it can reference cut targets, mask shapes, and explosion centers.
Setup Steps (Same configuration as the sample)
- Place a Cutter node (
Node2D) in the scene - Attach
boolean_sprite_cutter_with_tagged_shapes.gd - Place mask shape nodes (
CutterShapeGroup) as children of the Cutter
- This makes it easy to create a configuration where “moving the Cutter = moving the mask together”
- If using an explosion center, place a
Node2DlikeForceCenteras a child of the Cutter and reference it viainside_explosion_center_node, etc.
In the Sample
res://spritecutter.tscnhas aNode2DBooleanSpriteCutterWithTaggedShapeswith the script attachedForceCenteris a child of the Cutter and is referenced viainside_explosion_center_node=NodePath("ForceCenter")- The mask shape
CollisionShape2D2is also a child of the Cutter and is registered inCutterShapeGroup
2. Execution (How to operate to cut)
2-1. Executing the cut
Process Flow
- Pressing the Space key calls
call_cut() - The Cutter collects cut target candidates from
SpriteGroup
Sprite2D“generates a base polygon from alpha”- Skips sprites that have already been cut (
_already_cut=true)
- The Cutter collects mask shapes from
CutterShapeGroupand performs the following for each shape:
- Narrow down in order: AABB intersection → Rectangle polygon intersection → Base polygon intersection
- Only targets that actually intersect are fragmented
- The inside area is subdivided into Voronoi cells and fragments are generated via Boolean intersection
- The outside area is clipped by the mask to generate fragments
- The generated fragments are added to the scene as
RigidBody2D, and impulse/torque are applied - If the original was
Sprite2D, it is hidden (visible=false,_already_cut=true)
Operation Steps in the Sample
- Run (F5)
- Input Space (Input Action
call_cut) - The
Eggdisappears, and fragments scatter
2-2. Fragments disappearing (When Manager is enabled)
Purpose
If left unmanaged, fragments will continue to increase. The sample is configured to “delete after a certain time” so that the load does not increase even during verification. This is more of an operational safety measure than a visual effect.
In the Sample
FragmentManagerSingletonruns as an Autoload- TTL is enabled in
fragment_manager.tscninside_ttl_seconds = 10.0outside_ttl_seconds = 10.0
- Therefore, fragments are deleted approximately 10 seconds after generation
3. Cutter Settings (Sample Values)
3-1. “What to cut / With which shape”
| Item | Purpose (What it affects) | Sample Value (spritecutter.tscn) |
|---|---|---|
target_sprite_group |
Source for collecting cut targets. Sprites not in this group are not processed at all | Default ("SpriteGroup") |
shape_node_group |
Source for collecting mask shapes. If empty, inside/outside determination is impossible, and processing does not occur | Default ("CutterShapeGroup") |
Supplementary notes (Typical reasons for not cutting)
- Target is not in
SpriteGroup - Shape is not in
CutterShapeGroup - Target sprite has no texture
- Mask and target do not overlap in world coordinates (AABBs do not intersect)
3-2. Fragment Fineness (Voronoi)
| Item | Purpose (What it affects) | Sample Value (spritecutter.tscn) |
|---|---|---|
voronoi_seed_count |
Number of Voronoi seeds. Increasing this increases the number of cells, making inside fragments finer | 20 |
voronoi_seed_density_mode |
Bias of seeds. Increasing density towards the center tends to create “finer cracks in the center” | 1 (TowardMaskCenter) |
Supplementary notes (Relationship between load and appearance)
- Increasing
voronoi_seed_countincreases polygon intersection calculations, making the load heavier - If you want to concentrate “where to cut finely,” use the density mode rather than simply increasing the number, which makes adjustment easier
3-3. Scattering Direction (Inside / Outside)
| Item | Purpose (What it affects) | Sample Value (spritecutter.tscn) |
|---|---|---|
inside_force_base_strength |
Strength of inside fragment scattering (Base impulse) | 1300.0 |
inside_force_direction_mode |
Direction determination for inside (Fixed vector / Radial from explosion center) | 1 (ExplosionFromPoint) |
inside_explosion_center_node |
Inside explosion center (NodePath) |
NodePath("ForceCenter") |
outside_force_direction_mode |
Direction determination for outside | 1 (ExplosionFromPoint) |
Sample Explosion Center
ForceCenteris a child node of the CutterForceCenter.position = (0, 134)- The explosion direction is “Explosion Center → Fragment Center” (outward), resulting in a visual effect of scattering from the center
3-4. Appearance (Edge Lines)
| Item | Purpose (What it affects) | Sample Value (spritecutter.tscn) |
|---|---|---|
draw_edge_line |
Draw the outline of fragment polygons with Line2D to make cracks more visible |
false |
Supplementary notes
- Edge lines increase
Line2Dfor each fragment, so if there are many fragments, the rendering cost tends to increase - In the sample, to prioritize load and visual simplicity, it is disabled
4. FragmentManager Settings (Sample Values)
4-1. Lifespan (TTL)
| Item | Purpose (What it affects) | Sample Value (fragment_manager.tscn) |
|---|---|---|
inside_enable_ttl / inside_ttl_seconds |
Delete inside fragments after a certain time to prevent them from remaining | true / 10.0 |
outside_enable_ttl / outside_ttl_seconds |
Delete outside fragments after a certain time | true / 10.0 |
Supplementary notes
- TTL is judged by “elapsed time since generation,” not by “whether physics has stopped”
- If you want to keep them for a while after breaking for visual effects, increase the seconds
- If you want them to remain indefinitely, set
*_enable_ttl=false, but be aware that the load may increase unless combined with limit management or freeze
4-2. Freeze when settled (Sample is disabled)
| Item | Purpose (What it affects) | Sample Value (fragment_manager.tscn) |
|---|---|---|
inside_enable_freeze_on_settled |
Freeze inside fragments when sufficiently settled to suppress physics updates | false |
outside_enable_freeze_on_settled |
Same for outside fragments | false |
inside_disable_collision_when_frozen |
Set collision layer/mask to 0 after freezing to suppress collision calculations | false |
outside_disable_collision_when_frozen |
Same for outside | false |
Supplementary notes (When to enable freeze)
- Used when you want a visual effect of fragments “falling to the ground and stopping,” but want to reduce physics updates after they stop
- Once frozen, they will not move unless an external force is applied later (Enable with the premise that this does not conflict with visual specifications)
5. Modification Steps (Common Use Cases)
5-1. Increase cut targets
Purpose
Enable cutting multiple sprites with the same Cutter. Since the Cutter collects targets via group search, adding targets has low overhead.
Steps
- Select the
Sprite2Dyou want to cut - Add
SpriteGroupto Groups - Ensure it is positioned to overlap with the mask shape
In the Sample
- Only
Eggis inSpriteGroup, so onlyEggis cut
5-2. Increase mask shapes (Cut with multiple masks)
Purpose
You can place multiple shapes simultaneously and “cut only the overlapping targets with each respective shape.” The Cutter processes all shapes in CutterShapeGroup in order.
Steps
- Create the shape node you want to add (e.g., another
CollisionShape2D) - Add
CutterShapeGroupto Groups - Place it so it overlaps with the cut target
In the Sample
- Only
CollisionShape2D2(Circle) is inCutterShapeGroup
5-3. Make fragments finer
Purpose
Make the cracks finer to strengthen the impression of “shattering.” This mainly affects inside fragments.
Steps
- Increase
voronoi_seed_count - Adjust bias with
voronoi_seed_density_modeandvoronoi_seed_density_poweras needed - If load becomes an issue, increase
simplify_toleranceto reduce the number of vertices in the base polygon
In the Sample
voronoi_seed_count = 20
5-4. Delete fragments faster / Keep them longer
Purpose
Balance visual effect duration and load. The sample is set to “not accumulate during verification” (10 seconds).
Steps
- Open
fragment_manager.tscn - Adjust
inside_ttl_secondsandoutside_ttl_seconds - If you want them to remain indefinitely, set
*_enable_ttl=false(Recommended to use in conjunction with limit management and freeze)
In the Sample
- Both inside and outside have
ttl_seconds = 10.0
6. Troubleshooting
| Symptom | Main Cause | Solution |
|---|---|---|
| Nothing happens when pressing Space | call_cut Input Map is missing / Key assignment is different |
Create call_cut in Input Map and assign Space |
call_cut() is called but not cutting |
Target Sprite2D is not in SpriteGroup |
Add SpriteGroup to the target sprite’s Groups |
call_cut() is called but not cutting |
Mask shape is not in CutterShapeGroup |
Add CutterShapeGroup to the shape node’s Groups |
| Not cutting / Rarely cutting | Mask and target do not overlap (AABBs do not intersect) | Review position, scale, and rotation to ensure they definitely overlap |
| Fragments keep increasing | FragmentManager is not running / Autoload name mismatch |
Set Autoload as FragmentManagerSingleton="*res://fragment_manager.tscn" |
| Fragments are heavy | voronoi_seed_count is large / Edge lines enabled / Too many fragments remaining |
Lower voronoi_seed_count, disable draw_edge_line, and shorten TTL |
| Fragments disappear immediately | TTL is too short | Increase inside_ttl_seconds / outside_ttl_seconds (Sample is 10 seconds) |
BooleanSpriteCutterWithTaggedShapes Overview
BooleanSpriteCutterWithTaggedShapes is a Node2D script that targets Sprite2D (and fragments allowed for re-cutting) in a specified group, uses “mask shape nodes” from another group to cut out the intersection area, fragments them using Voronoi splitting + Boolean operations, and generates RigidBody2D fragments.
Fragments are classified into “inside mask (inside)” and “outside mask (outside),” and force, physics, materials, etc., can be set individually for each.
Features
- Batch process target sprites via group specification (cut multiple simultaneously)
- Collect mask shapes from a separate group (sequential application of multiple masks)
- Set force (direction/strength/torque) separately for inside / outside
- Switch fragment physics settings between Manual / Sprite Inheritance / Shape Inheritance / Specified Node Inheritance
- Select fragment generation destination from Self / Specified Node / Owner Parent / Owner Child / Manager
- Supports re-cutting (recut) (Separate allow flags for inside/outside)
- Supports edge line (
Line2D) drawing and material inheritance/overwriting
Prerequisites and Requirements
| Item | Content |
|---|---|
| Required Addon | res://addons/gdDelaunay/Delaunay.gd must exist (It is preloaded) |
| Target | Sprite2D belonging to target_sprite_group (Texture required) / Fragment RigidBody2D for re-cutting |
| Mask | Shape nodes belonging to shape_node_group (See supported types below) |
| Shape Intersection | Cutting occurs only when Mask AABB intersects Target AABB AND there is polygon intersection |
| Note | The base polygon of the sprite adopts only the first element of opaque_to_polygons(). (Materials with multiple opaque areas may not match intentions) |
Setup
- Place a
Node2Din the scene and attach this script. - Add the
Sprite2Dyou want to shatter to the grouptarget_sprite_group(Default:SpriteGroup). - Add nodes to be used as masks to the group
shape_node_group(Default:CutterShapeGroup).
- Supported examples:
Polygon2D/CollisionPolygon2D/CollisionShape2D(Convex/Concave/Circle/Rectangle)
- Set necessary parameters in the Inspector (Minimum:
alpha_threshold,simplify_tolerance,voronoi_seed_count). - Call
call_cut()on the Cutter node at the desired timing.
- Examples: Input, button, collision event, animation event, etc.
Generated Node Specifications
| Generated Item | Configuration | Meta/Group | Notes |
|---|---|---|---|
| Inside Fragment | RigidBody2D (Child: Polygon2D + CollisionPolygon2D + Optional Line2D) |
META_IS_FRAGMENT=true / META_FRAGMENT_TYPE="inside" / META_FRAGMENT_SOURCE_SPRITE=OriginalSprite / Added to target_sprite_group |
If unfreeze_delay>0, temporary freeze → Unfreeze after timer + Apply force |
| Outside Fragment | Same as above | META_FRAGMENT_TYPE="outside" |
Outside-specific force, physics, and material settings are applied |
Original Sprite2D |
Hidden | META_ALREADY_CUT=true |
Prevents double cutting of the same sprite |
| Re-cut Source (Fragment) | queue_free() |
- | When re-cutting, the original fragment is replaced |
Usage Examples
| Purpose (Use Case) | Setting | Result | Notes |
|---|---|---|---|
| Fragment only the part touching the mask | Add mask shape to shape_node_group → call_cut() |
Only intersecting Sprite generates fragments | If there are multiple masks, they are applied sequentially |
| Fly inside fragments only to the right | inside_force_direction_mode=FixedVector, inside_force_fixed_vector=(1,0) |
Inside fragments fly in a fixed direction | Strength is determined by inside_force_base_strength |
| Fly radially from explosion center | *_force_direction_mode=ExplosionFromPoint, specify *_explosion_center_node |
Fragments fly from fragment center → explosion center | Explosion center can be overridden via call_cut(force_config) |
| Make larger fragments fly stronger/rotate | use_area_scaling_for_impulse=true / use_area_scaling_for_torque=true |
Force and torque scale by area ratio | Clamping is done via area_ratio_min/max |
| Organize and generate fragments on the scene | fragment_parent_mode=SpecifiedNode (Specify fragment_parent_node) |
Fragments are grouped under the specified node | Manager can also be selected |
| Want to re-cut (chase cut) | allow_recutted_inside_fragments=true (and outside if needed) |
Fragments are included in the target for the next call_cut() |
Fragments are added to target_sprite_group |
| Disable surrounding collisions after shattering | disable_related_collisions_on_cut=true |
Disable collisions around the original | Generated fragments (META_IS_FRAGMENT) are excluded |
Property List
Basic
| Property | Type / Default | Description (Behavior, Calculation, Notes) |
|---|---|---|
target_sprite_group |
String / "SpriteGroup" |
Group name to collect Sprite2D (and allowed fragments) as cut targets |
shape_node_group |
String / "CutterShapeGroup" |
Group name to collect shape nodes to be used as masks |
alpha_threshold |
float / 0.1 |
Opacity judgment threshold for BitMap.create_from_image_alpha (alpha >= threshold is opaque) |
simplify_tolerance |
float / 2.0 |
Simplification tolerance for opaque_to_polygons() (Larger is lighter but rougher) |
voronoi_seed_count |
int / 10 |
Number of Voronoi splitting seed points (More fragments, heavier load) |
density |
float / 1.0 |
Mass coefficient: mass = area_world * density |
unfreeze_delay |
float / 0.0 |
Delay in seconds to unfreeze after generation (>0 for temporary pause effect) |
circle_approx_segments |
int / 32 |
Number of divisions to approximate CircleShape2D as a polygon |
debug_log |
bool / false |
Outputs processing logs if true (False is recommended for normal use) |
Voronoi Seed Distribution
| Property | Type / Default | Description |
|---|---|---|
voronoi_seed_density_mode |
enum / Uniform |
Uniform / TowardMaskCenter / TowardSpriteCenter / TowardNodeCenter |
voronoi_seed_density_power |
float / 2.0 |
Strength of bias towards the center (pow(t, power)) |
voronoi_seed_center_node |
NodePath / Empty |
Center for TowardNodeCenter (Node2D.global_position) |
Force Settings (Inside)
| Property | Type / Default | Description |
|---|---|---|
inside_force_base_strength |
float / 1000.0 |
Base impulse strength applied to inside fragments |
inside_force_strength_jitter_ratio |
float / 0.0 |
Strength jitter (±ratio, direction is fixed) |
inside_force_direction_mode |
enum / FixedVector |
FixedVector / ExplosionFromPoint |
inside_force_fixed_vector |
Vector2 / (1,0) |
Direction for FixedVector (Normalized internally) |
inside_explosion_center_node |
NodePath / Empty |
Explosion center Node2D for ExplosionFromPoint |
inside_torque_impulse |
float / 0.0 |
Torque amount applied to inside fragments |
Force Settings (Outside)
| Property | Type / Default | Description |
|---|---|---|
outside_force_base_strength |
float / 600.0 |
Base impulse strength applied to outside fragments |
outside_force_strength_jitter_ratio |
float / 0.0 |
Strength jitter (±ratio) |
outside_force_direction_mode |
enum / FixedVector |
FixedVector / ExplosionFromPoint |
outside_force_fixed_vector |
Vector2 / (0,-1) |
Direction for FixedVector |
outside_explosion_center_node |
NodePath / Empty |
Explosion center for ExplosionFromPoint |
outside_torque_impulse |
float / 0.0 |
Torque amount applied to outside fragments |
Size Scaling
| Property | Type / Default | Description |
|---|---|---|
use_area_scaling_for_impulse |
bool / true |
Scale impulse by area ratio |
use_area_scaling_for_torque |
bool / true |
Scale torque by area ratio |
area_ratio_min |
float / 0.2 |
Lower clamp for area ratio |
area_ratio_max |
float / 3.0 |
Upper clamp for area ratio |
impulse_area_exponent |
float / 0.5 |
impulse_scale = pow(area_ratio, exponent) |
torque_area_exponent |
float / 1.0 |
torque_scale = pow(area_ratio, exponent) |
Material Settings (Common / Inside / Outside)
| Property | Type / Default | Description |
|---|---|---|
fragment_inherit_material |
bool / true |
Inherit original material (Common default) |
fragment_use_custom_material |
bool / false |
Force apply common custom material |
fragment_custom_material |
Material / null |
Common custom material |
inside_fragment_inherit_material |
bool / true |
Inside only: Inherit or not |
inside_fragment_use_custom_material |
bool / false |
Inside only: Use custom |
inside_fragment_custom_material |
Material / null |
Inside only material |
outside_fragment_inherit_material |
bool / true |
Outside only: Inherit or not |
outside_fragment_use_custom_material |
bool / false |
Outside only: Use custom |
outside_fragment_custom_material |
Material / null |
Outside only material |
Edge Line Settings
| Property | Type / Default | Description |
|---|---|---|
draw_edge_line |
bool / true |
Draw fragment edges with Line2D |
edge_line_width |
float / 2.0 |
Line width |
edge_line_color_inside |
Color / White |
Inside line color |
edge_line_color_outside |
Color / White |
Outside line color |
Re-cut Settings
| Property | Type / Default | Description |
|---|---|---|
allow_recutted_inside_fragments |
bool / false |
Include inside fragments in the next target |
allow_recutted_outside_fragments |
bool / false |
Include outside fragments in the next target |
Disable Original Collisions
| Property | Type / Default | Description |
|---|---|---|
disable_related_collisions_on_cut |
bool / false |
Scan and disable collisions around the original sprite (Excludes generated fragments) |
Fragment Generation Destination
| Property | Type / Default | Description |
|---|---|---|
fragment_parent_mode |
enum / Self |
Self / SpecifiedNode / OwnerParent / OwnerChild / Manager |
fragment_parent_node |
NodePath / Empty |
Generation destination for SpecifiedNode |
| Note | - | OwnerChild has a fallback when re-cutting (owner is a fragment) |
Fragment Physics Settings (Inside)
| Property | Type / Default | Description |
|---|---|---|
inside_fragment_physics_mode |
enum / FromSprite |
Manual / FromSprite / FromShape / FromSpecified |
inside_fragment_physics_reference_node |
NodePath / Empty |
Reference start for FromSpecified |
inside_fragment_gravity_scale_manual |
float / 1.0 |
Manual: Gravity scale |
inside_fragment_collision_layer_manual |
int(flags) / 1 |
Manual: Collision Layer |
inside_fragment_collision_mask_manual |
int(flags) / 1 |
Manual: Collision Mask |
inside_fragment_linear_damp_manual |
float / 0.0 |
Manual: Linear Damp |
inside_fragment_angular_damp_manual |
float / 0.0 |
Manual: Angular Damp |
inside_fragment_physics_material_manual |
PhysicsMaterial / null |
Manual: Friction/Bounce |
inside_fragment_lock_rotation_manual |
bool / false |
Manual: Rotation lock |
Fragment Physics Settings (Outside)
| Property | Type / Default | Description |
|---|---|---|
outside_fragment_physics_mode |
enum / FromSprite |
Manual / FromSprite / FromShape / FromSpecified |
outside_fragment_physics_reference_node |
NodePath / Empty |
Reference start for FromSpecified |
outside_fragment_gravity_scale_manual |
float / 1.0 |
Manual: Gravity scale |
outside_fragment_collision_layer_manual |
int(flags) / 1 |
Manual: Collision Layer |
outside_fragment_collision_mask_manual |
int(flags) / 1 |
Manual: Collision Mask |
outside_fragment_linear_damp_manual |
float / 0.0 |
Manual: Linear Damp |
outside_fragment_angular_damp_manual |
float / 0.0 |
Manual: Angular Damp |
outside_fragment_physics_material_manual |
PhysicsMaterial / null |
Manual: Friction/Bounce |
outside_fragment_lock_rotation_manual |
bool / false |
Manual: Rotation lock |
Manager Integration
| Property | Type / Default | Description |
|---|---|---|
manager_mode |
enum / Autoload |
None / Autoload / SpecifiedNode |
manager_autoload_name |
String / "FragmentManagerSingleton" |
Autoload name (References /root/<name>) |
manager_node |
NodePath / Empty |
Reference destination for SpecifiedNode |
| Behavior | - | When generating fragments, calls register_fragment(body) on the resolved Manager (if the method exists) |
Runtime Override (call_cut(force_config))
You can override the Inspector force settings for that single call via the force_config argument of call_cut().
| Target | Key | Example Value |
|---|---|---|
| Inside/Outside | base_strength |
1400.0 |
| Inside/Outside | strength_jitter_ratio |
0.15 |
| Inside/Outside | direction_mode |
FORCE_DIR_FIXED_VECTOR or FORCE_DIR_EXPLOSION |
| Inside/Outside | fixed_vector |
Vector2(1, 0) |
| Inside/Outside | explosion_center |
Vector2(100, 200) (World coordinates) |
| Inside/Outside | torque_impulse |
3.0 |
FragmentManager Overview
FragmentManager is a Node2D script that registers fragments RigidBody2D generated by the Cutter via register_fragment() and manages maximum count, lifespan (TTL), freeze based on settled state, and deletion for staying off-screen (optional) with separate settings for inside / outside.
Features
- Separate management policies (limits, TTL, freeze, off-screen deletion) can be set for inside / outside
- References are held via
WeakRef, and references are automatically cleaned up if fragments are removed from the tree - Collisions can be disabled (collision_layer/mask set to 0) optionally when freezing
- Off-screen judgment calculates the view rectangle from the
Viewport’sCamera2D(Skipped if not obtainable)
Prerequisites and Requirements
- Assumes Godot 4 series 2D node structure.
- The managed objects are
RigidBody2Dpassed toregister_fragment(body). bodymust haveMETA_FRAGMENT_TYPE("inside"/"outside") set on the Cutter side.- Assign
META_FRAGMENT_NO_MANAGE=trueto fragments you do not want to manage.
Setup
- Attach this script to the root node of
fragment_manager.tscn. - Register
fragment_manager.tscninProject Settings > Autoloadto make it resident under/root. - Ensure
FragmentManager.register_fragment(body)is called when generating fragments on the Cutter side.
- If the Cutter has an implementation to call
register_fragmentupon generation, match the Autoload name and reference settings.
Generated Node Specifications
- This node itself resides as a
Node2Dand internally holds fragment references in the following two lists._fragments_inside(For inside)_fragments_outside(For outside)
- Fragments
RigidBody2Dregistered viaregister_fragment()are assigned the following meta information for management._boolean_fragment(Fragment flag)_fragment_spawn_msec(Generation time ms)_fragment_last_active_msec(Last active time ms)
- If
inside_fragment_group_name/outside_fragment_group_nameis not empty, they are added to the corresponding group upon registration.
Usage Examples
| Purpose (Use Case) | Setting | Result | Notes |
|---|---|---|---|
| Prevent fragments from increasing too much | Set inside_max_fragments / outside_max_fragments |
Excess fragments are deleted in order of age | Unlimited if 0 or less |
| Natural disappearance after a certain time | Set *_enable_ttl=true, *_ttl_seconds |
Deleted when TTL expires | Generation time is recorded upon registration |
| Stop physics calculations when settled | Set *_enable_freeze_on_settled=true |
Freezes if low speed state continues | Collisions can be disabled optionally |
| Collect fragments that go off-screen | Set *_delete_when_offscreen=true |
Deleted if staying off-screen | Judgment itself is not performed if camera cannot be obtained |
| Keep only specific fragments | body.set_meta("_fragment_no_manage", true) |
Manager ignores registration and updates | Safest to assign immediately after generation |
Property List
| Property | Type / Default | Description (Behavior, Calculation, Notes) |
|---|---|---|
inside_fragment_group_name |
String / "FragmentGroupInside" |
Group name to add inside fragments upon registration. If empty string, does not add. |
inside_max_fragments |
int / 300 |
Maximum number of inside fragments. Unlimited if 0 or less. Excess fragments are queue_free() in order of age. |
inside_enable_ttl |
bool / true |
Enable TTL deletion for inside fragments. |
inside_ttl_seconds |
float / 8.0 |
Lifespan (seconds) for inside fragments. Deleted if now - spawn_msec exceeds this number of seconds. |
inside_enable_freeze_on_settled |
bool / true |
Enable settled judgment freeze for inside fragments. |
inside_settled_linear_speed |
float / 15.0 |
Linear speed threshold. If exceeded, considered “active,” and last active time is updated. |
inside_settled_angular_speed |
float / 1.5 |
Angular speed threshold. If exceeded, considered “active.” |
inside_settled_grace_seconds |
float / 0.6 |
Freeze is applied if low speed state continues for this many seconds. |
inside_disable_collision_when_frozen |
bool / true |
Sets collision_layer/mask to 0 when freezing. No recovery processing is performed. |
inside_delete_when_offscreen |
bool / false |
Enable off-screen deletion for inside fragments. |
inside_offscreen_grace_seconds |
float / 1.0 |
Deleted if off-screen continues for this many seconds. Last active time is updated if it returns on-screen. |
outside_fragment_group_name |
String / "FragmentGroupOutside" |
Group name to add outside fragments upon registration. If empty string, does not add. |
outside_max_fragments |
int / 300 |
Maximum number of outside fragments. Unlimited if 0 or less. Excess fragments are queue_free() in order of age. |
outside_enable_ttl |
bool / true |
Enable TTL deletion for outside fragments. |
outside_ttl_seconds |
float / 8.0 |
Lifespan (seconds) for outside fragments. Deleted if now - spawn_msec exceeds this number of seconds. |
outside_enable_freeze_on_settled |
bool / true |
Enable settled judgment freeze for outside fragments. |
outside_settled_linear_speed |
float / 15.0 |
Linear speed threshold for outside. |
outside_settled_angular_speed |
float / 1.5 |
Angular speed threshold for outside. |
outside_settled_grace_seconds |
float / 0.6 |
Low speed continuation grace period (seconds) for outside. |
outside_disable_collision_when_frozen |
bool / true |
Sets collision_layer/mask to 0 when freezing outside. No recovery processing is performed. |
outside_delete_when_offscreen |
bool / false |
Enable off-screen deletion for outside fragments. |
outside_offscreen_grace_seconds |
float / 1.0 |
Off-screen continuation grace period (seconds) for outside. |
debug_log |
bool / false |
If true, outputs logs for limit deletion, TTL deletion, off-screen deletion, etc. |