このトピックでは、BooleanSpriteCutterWithTaggedShapes スクリプト / Fragment Manager スクリプトについて説明します。
注意: パート1はこちら BooleanSpriteCutterWithTaggedShapes / FragmentManager English Manual Part 1(About Sample Project)
BooleanSpriteCutterWithTaggedShapes の概要
BooleanSpriteCutterWithTaggedShapes は、指定されたグループ内の Sprite2D ノード(およびオプションで再切断可能な断片)を対象とし、別のグループから「マスク形状ノード」を取得して交差する領域を切り取り、ボロノイ分割とブール演算によって断片化し、RigidBody2D 断片を生成する Node2D スクリプトです。
断片は内側(マスク内)と外側(残りの部分)に分類され、それぞれに対して力、物理挙動、マテリアルなどを個別に設定できます。
機能
- グループ経由での複数ターゲットスプライトのバッチ処理(一度に複数切断)
- 別のグループからマスク形状を取得(複数のマスクを順次処理)
- 内側/外側それぞれの**力(方向/強度/トルク)**の個別設定
- 断片の物理設定モード: 手動 / スプライトから継承 / 形状から継承 / 指定ノードから継承
- 断片の親ノード設定モード: 自分自身 / 指定ノード / 所有者の親 / 所有者の子 / マネージャー
- 再切断(再断片化)対応。内側/外側それぞれに許可フラグあり
- 縁線(
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 の参照先 |
| 動作 |
- |
断片生成時、解決されたマネージャーに対して 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 は、Cutter によって生成された RigidBody2D 断片を管理する Node2D スクリプトです。断片は 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 のまま維持され、内部で2つのリストを管理します:
_fragments_inside
_fragments_outside
- 登録された断片にはメタデータが付与されます:
_boolean_fragment(断片フラグ)
_fragment_spawn_msec(生成時刻 ms)
_fragment_last_active_msec(最終アクティブ時刻 ms)
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
これは画面の視覚的な表現力を高める非常に良い方法のように感じます。
「いいね!」 1