ジョイント・チェーンシステムのサンプルプロジェクトとオブジェクト構造


サンプルプロジェクトは以下リンクからダウンロードいただけます。


本プロジェクトは、物理ジョイント(PinJoint2D、GrooveJoint2D)を使ったロープ・チェーンシステムを実装しています。
上下左右の矢印キーで移動、スペースでジャンプ、zキーで前方の鎖を切ることができます。
各チェーンには角度や伸び率に応じて破断するような設定がされております。

プロジェクト構造

ディレクトリ構成

steam_achieve/
├── scripts/              # ジョイント・チェーン・ロープ関連スクリプト
│   ├── breakable_joint_monitor_2d.gd
│   ├── chain_path_binder.gd
│   ├── chain_setup_tool.gd
│   ├── chain_part.gd
│   ├── joint_break_params.gd
│   ├── rope_solver.gd
│   ├── rigid_body_pusher.gd
│   ├── area_joint_breaker.gd
│   ├── path_ribbon_mesh_2d.gd
│   ├── boolean_sprite_cutter_with_tagged_shapes.gd
│   └── fragment_manager.gd
├── *.tscn               # オブジェクトファイル
├── *.png                # テクスチャファイル
└── addons/              # アドオン(gdDelaunay、godotsteam)

オブジェクトファイル解説

1. testrope_2.tscn(ロープテストオブジェクト)

目的
7つのRigidBody2DをGrooveJoint2Dで接続したチェーンをテストするオブジェクトです。

構造

Testrope2 (Area2DGameObject)
├── Node2D (チェーンのルート)
│   ├── RigidBody2D (先頭、固定されていない)
│   │   ├── CollisionShape2D (RectangleShape2D)
│   │   ├── seg1 (Node2D, position: 0, -10)
│   │   └── seg2 (Node2D, position: 0, 10)
│   ├── RigidBody2D2 (2番目)
│   │   ├── GrooveJoint2D (前のRigidBody2Dに接続)
│   │   │   ├── node_a: ../../RigidBody2D
│   │   │   ├── node_b: ..
│   │   │   ├── position: (0, -16)
│   │   │   ├── bias: 0.2
│   │   │   ├── length: 8.0
│   │   │   └── initial_offset: 2.0
│   │   ├── CollisionShape2D
│   │   ├── seg1
│   │   └── seg2
│   ├── RigidBody2D3~RigidBody2D7 (同様の構造)
│   └── RigidBody2D7 (末尾、CapsuleShape2Dを使用)
├── Path2D (チェーンの可視化用)
├── PathRibbonMesh2D (リボンメッシュで描画)
├── StaticBody2D (先頭を固定)
│   └── GrooveJoint2D (先頭のRigidBody2Dに接続)
├── StaticBody2D2 (末尾を固定)
│   └── GrooveJoint2D (末尾のRigidBody2D7に接続)
├── BreakableJointMonitor2D
│   ├── search_root: ..
│   ├── break_angle_degrees: 80.0
│   ├── break_angle_duration_sec: 0.3
│   └── use_break_delay_frames: false
│   └── break_delay_frames: 3
└── ChainPathBinder2D
    ├── auto_detect_mode: true
    ├── search_root: ../Node2D
    ├── output_paths: [../Path2D]
    ├── joint_monitor: ../BreakableJointMonitor
    ├── ribbon_mesh: ../PathRibbonMesh2D
    └── enable_smooth_handles: true

ジョイント構造

  • GrooveJoint2Dが各RigidBody2Dの子として配置されています
  • 各ジョイントはnode_aで前のRigidBody2Dを、node_bで自身(..)を参照します
  • 先頭と末尾はStaticBody2DGrooveJoint2Dで固定されています
  • すべてのジョイントはbias=0.2length=8.0initial_offset=2.0で統一されています

設定の特徴

  • BreakableJointMonitor2Dは角度80度以上で0.3秒継続したら切断する設定
  • ChainPathBinder2Dは自動検出モードで、PathRibbonMesh2Dで可視化
  • 各RigidBody2Dにはlinear_damp=10.0angular_damp=10.0で減衰が設定されています

2. testrope_ball_3.tscn(ボール付きチェーンテストオブジェクト)

目的
2つのチェーン(UnbreakableChainとBreakableChain)と、ボール(破壊可能なスプライト)をテストするオブジェクトです。

構造

Ball (Area2DGameObject)
├── ChainJointSetupTool (チェーン自動セットアップツール)
│   ├── target_parent: ../UnbreakableChain
│   └── auto_create_seg_nodes: false
├── UnbreakableChain (Node2D)
│   ├── Path2D (RopePathBinder2Dスクリプトがアタッチ)
│   ├── RigidBody2D (先頭、freeze=trueで固定)
│   │   ├── CollisionShape2D
│   │   ├── seg1
│   │   └── seg2
│   ├── RigidBody2D2~RigidBody2D6 (中間リンク)
│   │   └── GrooveJoint2D (各々前のRigidBody2Dに接続)
│   │       ├── bias: 0.9
│   │       ├── length: 8.0
│   │       └── initial_offset: 1.0
│   ├── RigidBody2D7 (末尾、ボール)
│   │   ├── mass: 8.0 (他の3.0より重い)
│   │   ├── CollisionShape2D (CircleShape2D)
│   │   ├── AttackArea2D (攻撃判定)
│   │   ├── Sprite2D (ball.png)
│   │   ├── Node2D/CollisionShape2D (CutterShapeGroup、破壊用)
│   │   └── GrooveJoint2D
│   ├── ChainPathBinder2D
│   │   ├── auto_detect_mode: true
│   │   ├── search_root: ..
│   │   ├── output_paths: [../Path2D]
│   │   └── joint_monitor: ../BreakableJointMonitor2D
│   ├── BreakableJointMonitor2D
│   │   ├── search_root: ..
│   │   ├── groove_end_epsilon_pixels: 0.0
│   │   ├── joint_params: [JointBreakParams] (個別設定)
│   │   │   └── joint_path: ../RigidBody2D2/GrooveJoint2D
│   │   │       └── groove_break_angle_degrees: 90.0
│   │   └── use_break_delay_frames: false
│   │   └── break_delay_frames: 10
│   └── PathRibbonMesh2D (chain.pngテクスチャ)
├── BreakableChain (Node2D)
│   ├── RigidBody2D (先頭、freeze=true、collision_layer=0)
│   ├── RigidBody2D2~RigidBody2D6 (中間リンク)
│   │   └── GrooveJoint2D
│   ├── RigidBody2D6
│   │   └── GrooveJoint2D2 (UnbreakableChain/RigidBody2D7に接続)
│   ├── ChainPathBinder2D
│   ├── BreakableJointMonitor2D
│   └── PathRibbonMesh2D (rope.pngテクスチャ)
└── BooleanSpriteCutterWithTaggedShapes (スプライト破壊システム)
    ├── voronoi_seed_count: 30
    └── disable_related_collisions_on_cut: true

ジョイント構造

  • UnbreakableChain: 7つのRigidBody2DがGrooveJoint2Dで接続

    • 先頭のRigidBody2Dはfreeze=trueで固定
    • 末尾のRigidBody2D7は質量8.0で重い
    • 2番目のGrooveJoint2Dには個別のJointBreakParamsが設定され、角度90度以上で0.5秒継続したら切断
  • BreakableChain: 6つのRigidBody2DがGrooveJoint2Dで接続

    • 先頭のRigidBody2Dはfreeze=truecollision_layer=0で衝突無効
    • RigidBody2D6には2つのGrooveJoint2Dがあり、1つはUnbreakableChain/RigidBody2D7に接続(2つのチェーンを連結)

設定の特徴

  • ChainJointSetupToolが配置されているが、auto_create_seg_nodes=falseなので手動でsegノードを配置
  • RopePathBinder2DスクリプトがPath2Dにアタッチされている(UnbreakableChain用)
  • BooleanSpriteCutterWithTaggedShapesでスプライト破壊が可能

3. player.tscn(プレイヤー)

目的
プレイヤーキャラクターで、RigidBodyPusherNaturalを使用してRigidBody2Dを押し出す機能を持ちます。

構造

Player (GameObject / CharacterBody2D)
├── MoveAndJumpSettings
├── BaseSettings
├── CollisionShape2D (CircleShape2D, radius: 25.02)
├── AnimationPlayer
├── VariableSettings
├── Node2D (RigidBodyPusherNatural)
│   ├── script: rigid_body_pusher.gd
│   ├── min_owner_position_delta_pixels: 1.0
│   ├── min_owner_real_speed: 1.0
│   ├── push_strength: 2000.0
│   ├── min_push_force: 100.0
│   ├── max_force: 2000.0
│   ├── max_impulse: 2000.0
│   ├── mass_influence: 1.0
│   ├── normal_direction_weight: 0.0
│   └── movement_direction_weight: 1.0
├── Connector
└── Sprite2D (mech.png)

設定の特徴

  • normal_direction_weight=0.0movement_direction_weight=1.0で、移動方向のみで押し出します
  • push_strength=2000.0で強く押し出します
  • mass_influence=1.0で質量を完全に考慮します

4. areabreaker.tscn(エリアブレーカーテストオブジェクト)

目的
AreaJointBreaker2Dを使用して、Area2D範囲内のジョイントを一括切断する機能をテストするオブジェクトです。

構造

Areabreaker (Area2DGameObject)
├── AreaJointBreaker2D (Node2D)
│   ├── script: area_joint_breaker.gd
│   ├── target_area: Area2D
│   └── rotation: 0.952787
│   └── Area2D
│       └── CollisionShape2D (RectangleShape2D, size: 155x35)
├── BaseSettings
├── CollisionShape2D (disabled)
├── AnimationTree (AnimationPlayer)
│   └── cut アニメーション
│       └── AreaJointBreaker2D.break_joints_in_target_area() を呼ぶ
├── PathRibbonMesh2D (切断エフェクト用)
│   ├── path_nodes: [../Path2D]
│   ├── width: 3.0
│   └── progress_percent, start_percent がアニメーションで制御
└── Path2D (切断エフェクトのパス)

設定の特徴

  • AreaJointBreaker2Dtarget_areaArea2Dが設定されています
  • アニメーションでbreak_joints_in_target_area()を呼び出します
  • PathRibbonMesh2Dで切断エフェクトを可視化します

5. game_scene.tscn(メインゲームシーン)

目的
メインのゲームシーンで、各種オブジェクトを配置します。

構造

GameScene
├── SceneLayer
│   ├── DistantView (Parallax2D)
│   ├── MiddleView (Parallax2D)
│   ├── NearView (Parallax2D)
│   ├── WallLayer (Parallax2D)
│   │   ├── Wall (TileMapLayer)
│   │   └── WallDecoration (TileMapLayer)
│   └── BaseLayer (Parallax2D)
│       └── Base (TileMapLayer)
│           ├── Testrope2 (testrope_2.tscnのインスタンス)
│           │   └── position: (-564, -17)
│           │   └── rotation: 0.0794073
│           ├── StaticBody2D (床)
│           ├── Player (player.tscnのインスタンス)
│           │   └── position: (-612, -80)
│           ├── Ball (testrope_ball_3.tscnのインスタンス)
│           │   └── position: (121, 38)
│           ├── Platform1, Platform2 (platform_1.tscnのインスタンス)
│           └── Pillar (pillar.tscnのインスタンス)
│               └── position: (186, 118)
├── PostEffectLayer (CanvasLayer)
└── UI (CanvasLayer)

配置されているオブジェクト

  • Testrope2: ロープテストオブジェクト(位置: -564, -17)
  • Player: プレイヤー(位置: -612, -80)
  • Ball: ボール付きチェーンテストオブジェクト(位置: 121, 38)
  • Platform1, Platform2: プラットフォーム
  • Pillar: 柱(SpriteGroupに属し、破壊可能)

ジョイント使用箇所の詳細

1. testrope_2.tscn のジョイント構造

GrooveJoint2Dの配置

ジョイント node_a node_b 位置 設定
StaticBody2D/PinJoint2D3 StaticBody2D .. ../../Node2D/RigidBody2D (12, 4) 先頭固定
RigidBody2D2/PinJoint2D2 RigidBody2D2 ../../RigidBody2D .. (0, -16) RigidBody2D → RigidBody2D2
RigidBody2D3/PinJoint2D2 RigidBody2D3 ../../RigidBody2D2 .. (0, -16) RigidBody2D2 → RigidBody2D3
RigidBody2D4/PinJoint2D2 RigidBody2D4 ../../RigidBody2D3 .. (0, -16) RigidBody2D3 → RigidBody2D4
RigidBody2D5/PinJoint2D2 RigidBody2D5 ../../RigidBody2D4 .. (0, -16) RigidBody2D4 → RigidBody2D5
RigidBody2D6/PinJoint2D2 RigidBody2D6 ../../RigidBody2D5 .. (0, -16) RigidBody2D5 → RigidBody2D6
RigidBody2D7/PinJoint2D2 RigidBody2D7 ../../RigidBody2D6 .. (0, -16) RigidBody2D6 → RigidBody2D7
StaticBody2D2/PinJoint2D2 StaticBody2D2 ../../Node2D/RigidBody2D7 .. (-13, 6) 末尾固定

共通設定

  • bias: 0.2(低めの値で柔らかい接続)
  • length: 8.0(溝の長さ)
  • initial_offset: 2.0(初期オフセット)

監視設定

  • BreakableJointMonitor2Dが角度80度以上で0.3秒継続したら切断
  • ChainPathBinder2Dが自動検出モードでパスを生成

2. testrope_ball_3.tscn のジョイント構造

UnbreakableChain の GrooveJoint2D

ジョイント node_a node_b 設定
RigidBody2D2/GrooveJoint2D RigidBody2D2 ../../RigidBody2D .. bias: 0.9, length: 8.0, initial_offset: 1.0
RigidBody2D3/GrooveJoint2D RigidBody2D3 ../../RigidBody2D2 .. 同上
RigidBody2D4/GrooveJoint2D RigidBody2D4 ../../RigidBody2D3 .. 同上
RigidBody2D5/GrooveJoint2D RigidBody2D5 ../../RigidBody2D4 .. 同上
RigidBody2D6/GrooveJoint2D RigidBody2D6 ../../RigidBody2D5 .. 同上
RigidBody2D7/GrooveJoint2D RigidBody2D7 ../../RigidBody2D6 .. 同上

BreakableChain の GrooveJoint2D

ジョイント node_a node_b 設定
RigidBody2D2/GrooveJoint2D RigidBody2D2 ../../RigidBody2D .. bias: 0.9, length: 8.0, initial_offset: 1.0
RigidBody2D3/GrooveJoint2D RigidBody2D3 ../../RigidBody2D2 .. 同上
RigidBody2D4/GrooveJoint2D RigidBody2D4 ../../RigidBody2D3 .. 同上
RigidBody2D5/GrooveJoint2D RigidBody2D5 ../../RigidBody2D4 .. 同上
RigidBody2D6/GrooveJoint2D RigidBody2D6 ../../RigidBody2D5 .. 同上
RigidBody2D6/GrooveJoint2D2 RigidBody2D6 .. ../../../UnbreakableChain/RigidBody2D7 同上(2つのチェーンを連結)

個別設定

  • RigidBody2D2/GrooveJoint2DにはJointBreakParamsが設定され、角度90度以上で0.5秒継続したら切断

監視設定

  • UnbreakableChainBreakableChainそれぞれにBreakableJointMonitor2DChainPathBinder2Dが設定されています

システム連携

1. チェーン可視化システム

testrope_2.tscn

  1. ChainPathBinder2DNode2D配下のRigidBody2Dを自動検出
  2. 各RigidBody2Dのseg1seg2を節点として使用
  3. Path2DCurve2Dを更新
  4. PathRibbonMesh2Dbelt.pngテクスチャでリボンメッシュを描画

testrope_ball_3.tscn

  1. UnbreakableChainBreakableChainそれぞれにChainPathBinder2Dが設定
  2. UnbreakableChainchain.pngBreakableChainrope.pngで描画
  3. UnbreakableChainPath2DにはRopePathBinder2Dスクリプトがアタッチ(別の可視化方法)

2. ジョイント切断システム

testrope_2.tscn

  • BreakableJointMonitor2Dが全ジョイントを監視
  • 角度80度以上で0.3秒継続したら切断
  • 切断時にChainPathBinder2Dが自動でパスを分割

testrope_ball_3.tscn

  • UnbreakableChainBreakableJointMonitor2Dは個別設定あり
  • RigidBody2D2/GrooveJoint2Dのみ角度90度以上で0.5秒継続したら切断
  • 他のジョイントはグローバル設定(無効)を使用

3. プレイヤー押し出しシステム

player.tscn

  • RigidBodyPusherNaturalCharacterBody2Dmove_and_slide()後に実行
  • 接触したRigidBody2Dを移動方向に押し出します
  • push_strength=2000.0で強く押し出します

4. エリア切断システム

areabreaker.tscn

  • AreaJointBreaker2DArea2D範囲内のジョイントを一括切断
  • アニメーションでbreak_joints_in_target_area()を呼び出します
  • PathRibbonMesh2Dで切断エフェクトを可視化

プロジェクト設定

Autoload

  • FragmentManagerSingleton: 破片管理システム(fragment_manager.tscnオブジェクト)

グローバルグループ

  • CutterShapeGroup: スプライト切断用のマスク形状グループ
  • SpriteGroup: スプライト切断対象グループ

Input Map

  • right: 右移動(右矢印キー)
  • left: 左移動(左矢印キー)
  • jump: ジャンプ(Space)
  • cut: 切断(Z)

使用されているスクリプトの配置

testrope_2.tscn

  • BreakableJointMonitor2D (scripts/breakable_joint_monitor_2d.gd)
  • ChainPathBinder2D (scripts/chain_path_binder.gd)
  • PathRibbonMesh2D (scripts/path_ribbon_mesh_2d.gd)
  • ChainPartResource (scripts/chain_part.gd) - リソースとして7つ

testrope_ball_3.tscn

  • ChainJointSetupTool (scripts/chain_setup_tool.gd)
  • RopePathBinder2D (scripts/rope_solver.gd) - Path2Dにアタッチ
  • ChainPathBinder2D (scripts/chain_path_binder.gd) - 2つ
  • BreakableJointMonitor2D (scripts/breakable_joint_monitor_2d.gd) - 2つ
  • JointBreakParams (scripts/joint_break_params.gd) - リソースとして1つ
  • PathRibbonMesh2D (scripts/path_ribbon_mesh_2d.gd) - 2つ
  • BooleanSpriteCutterWithTaggedShapes (scripts/boolean_sprite_cutter_with_tagged_shapes.gd)

player.tscn

  • RigidBodyPusherNatural (scripts/rigid_body_pusher.gd)

areabreaker.tscn

  • AreaJointBreaker2D (scripts/area_joint_breaker.gd)
  • PathRibbonMesh2D (scripts/path_ribbon_mesh_2d.gd)

ジョイントの種類と使用状況

GrooveJoint2D

使用箇所

  • testrope_2.tscn: 7つのRigidBody2D間 + 2つのStaticBody2D固定用 = 合計9個
  • testrope_ball_3.tscn:
    • UnbreakableChain: 6個(RigidBody2D2~RigidBody2D7)
    • BreakableChain: 6個(RigidBody2D2~RigidBody2D6)+ 1個(UnbreakableChain連結用)= 合計7個

設定パターン

  1. testrope_2.tscn パターン

    • bias: 0.2(柔らかい)
    • length: 8.0
    • initial_offset: 2.0
  2. testrope_ball_3.tscn パターン

    • bias: 0.9(硬い)
    • length: 8.0
    • initial_offset: 1.0

PinJoint2D

使用箇所

  • 本プロジェクトでは使用されていません(すべてGrooveJoint2D)

チェーンの構造パターン

パターン1: 単一チェーン(testrope_2.tscn)

StaticBody2D (固定)
    └── GrooveJoint2D
        └── RigidBody2D1
            └── GrooveJoint2D
                └── RigidBody2D2
                    └── GrooveJoint2D
                        └── ...
                            └── RigidBody2D7
                                └── GrooveJoint2D
                                    └── StaticBody2D (固定)

パターン2: 分岐チェーン(testrope_ball_3.tscn)

UnbreakableChain:
    RigidBody2D1 (freeze)
        └── GrooveJoint2D
            └── RigidBody2D2
                └── GrooveJoint2D
                    └── ...
                        └── RigidBody2D7 (ボール)

BreakableChain:
    RigidBody2D1 (freeze)
        └── GrooveJoint2D
            └── RigidBody2D2
                └── GrooveJoint2D
                    └── ...
                        └── RigidBody2D6
                            ├── GrooveJoint2D (BreakableChain内)
                            └── GrooveJoint2D2 (UnbreakableChain/RigidBody2D7に接続)

物理設定

RigidBody2D の設定

testrope_2.tscn

  • linear_damp: 10.0(線形減衰)
  • angular_damp: 10.0(角減衰)

testrope_ball_3.tscn

  • mass: 3.0(通常のリンク)
  • mass: 8.0(RigidBody2D7、ボール部分)
  • freeze: true(先頭のRigidBody2D)
  • continuous_cd: 2(連続衝突検出)

可視化システム

PathRibbonMesh2D の使用

testrope_2.tscn

  • テクスチャ: belt.png
  • 幅: 20.0

testrope_ball_3.tscn

  • UnbreakableChain: chain.png、幅: 20.0
  • BreakableChain: rope.png、幅: 20.0

areabreaker.tscn

  • テクスチャ: GradientTexture2D(グラデーション)
  • 幅: 3.0(アニメーションで変化)

破壊システム

BooleanSpriteCutterWithTaggedShapes

testrope_ball_3.tscn

  • voronoi_seed_count: 30(破片の細かさ)
  • disable_related_collisions_on_cut: true(切断時に周辺コリジョンを無効化)
  • UnbreakableChain/RigidBody2D7/Node2D/CollisionShape2DCutterShapeGroupに属し、破壊用マスクとして使用

まとめ

本プロジェクトでは、以下のような構造でジョイント・チェーン・ロープシステムが実装されています:

  1. testrope_2.tscnオブジェクト: 7リンクのチェーンをGrooveJoint2Dで接続、角度監視で切断可能
  2. testrope_ball_3.tscnオブジェクト: 2つのチェーン(UnbreakableChainとBreakableChain)を連結、個別設定で一部のみ切断可能
  3. player.tscnオブジェクト: RigidBodyPusherNaturalでRigidBody2Dを押し出し
  4. areabreaker.tscnオブジェクト: AreaJointBreaker2Dで範囲内のジョイントを一括切断

すべてのチェーンはChainPathBinder2Dで可視化され、PathRibbonMesh2Dでリボンメッシュとして描画されます。

「いいね!」 1