Sample Project and Object Structure for Joint Chain System


The sample project can be downloaded from the link below.


This project implements a rope and chain system using physics joints (PinJoint2D, GrooveJoint2D).
You can move using the up, down, left, and right arrow keys, jump with the Spacebar, and cut the chain in front of you with the Z key.
Each chain is configured to break based on its angle and stretch.

Project Structure

Directory Structure

steam_achieve/
├── scripts/              # Scripts related to joints, chains, and ropes
│   ├── 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               # Scene files
├── *.png                # Texture files
└── addons/              # Addons (gdDelaunay, godotsteam)

Explanation of Scene Files

1. testrope_2.tscn (Rope Test Object)

Purpose
An object for testing a chain consisting of 7 RigidBody2Ds connected by GrooveJoint2Ds.

Structure

Testrope2 (Area2DGameObject)
├── Node2D (Root of the chain)
│   ├── RigidBody2D (Head, not fixed)
│   │   ├── CollisionShape2D (RectangleShape2D)
│   │   ├── seg1 (Node2D, position: 0, -10)
│   │   └── seg2 (Node2D, position: 0, 10)
│   ├── RigidBody2D2 (Second link)
│   │   ├── GrooveJoint2D (Connected to previous RigidBody2D)
│   │   │   ├── node_a: ../../RigidBody2D
│   │   │   ├── node_b: ..
│   │   │   ├── position: (0, -16)
│   │   │   ├── bias: 0.2
│   │   │   ├── length: 8.0
│   │   │   └── initial_offset: 2.0
│   │   ├── CollisionShape2D
│   │   ├── seg1
│   │   └── seg2
│   ├── RigidBody2D3 to RigidBody2D7 (Similar structure)
│   └── RigidBody2D7 (End, uses CapsuleShape2D)
├── Path2D (For visualizing the chain)
├── PathRibbonMesh2D (Draws with ribbon mesh)
├── StaticBody2D (Fixes the head)
│   └── GrooveJoint2D (Connected to the head RigidBody2D)
├── StaticBody2D2 (Fixes the tail)
│   └── GrooveJoint2D (Connected to the tail 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

Joint Structure

  • GrooveJoint2D is placed as a child of each RigidBody2D.
  • Each joint references the previous RigidBody2D via node_a and itself (..) via node_b.
  • The head and tail are fixed to StaticBody2D using GrooveJoint2D.
  • All joints are uniformly set with bias=0.2, length=8.0, and initial_offset=2.0.

Configuration Features

  • BreakableJointMonitor2D is set to break if the angle exceeds 80 degrees for 0.3 seconds.
  • ChainPathBinder2D uses auto-detection mode to visualize via PathRibbonMesh2D.
  • Each RigidBody2D has damping set with linear_damp=10.0 and angular_damp=10.0.

2. testrope_ball_3.tscn (Chain Test Object with Ball)

Purpose
An object for testing two chains (UnbreakableChain and BreakableChain) and a ball (a breakable sprite).

Structure

Ball (Area2DGameObject)
├── ChainJointSetupTool (Chain auto-setup tool)
│   ├── target_parent: ../UnbreakableChain
│   └── auto_create_seg_nodes: false
├── UnbreakableChain (Node2D)
│   ├── Path2D (RopePathBinder2D script attached)
│   ├── RigidBody2D (Head, fixed with freeze=true)
│   │   ├── CollisionShape2D
│   │   ├── seg1
│   │   └── seg2
│   ├── RigidBody2D2 to RigidBody2D6 (Intermediate links)
│   │   └── GrooveJoint2D (Connected to previous RigidBody2D each)
│   │       ├── bias: 0.9
│   │       ├── length: 8.0
│   │       └── initial_offset: 1.0
│   ├── RigidBody2D7 (Tail, ball)
│   │   ├── mass: 8.0 (Heavier than others which are 3.0)
│   │   ├── CollisionShape2D (CircleShape2D)
│   │   ├── AttackArea2D (Attack hitbox)
│   │   ├── Sprite2D (ball.png)
│   │   ├── Node2D/CollisionShape2D (CutterShapeGroup, for breaking)
│   │   └── 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] (Individual settings)
│   │   │   └── joint_path: ../RigidBody2D2/GrooveJoint2D
│   │   │       └── groove_break_angle_degrees: 90.0
│   │   └── use_break_delay_frames: false
│   │   └── break_delay_frames: 10
│   └── PathRibbonMesh2D (chain.png texture)
├── BreakableChain (Node2D)
│   ├── RigidBody2D (Head, freeze=true, collision_layer=0)
│   ├── RigidBody2D2 to RigidBody2D6 (Intermediate links)
│   │   └── GrooveJoint2D
│   ├── RigidBody2D6
│   │   └── GrooveJoint2D2 (Connected to UnbreakableChain/RigidBody2D7)
│   ├── ChainPathBinder2D
│   ├── BreakableJointMonitor2D
│   └── PathRibbonMesh2D (rope.png texture)
└── BooleanSpriteCutterWithTaggedShapes (Sprite breaking system)
    ├── voronoi_seed_count: 30
    └── disable_related_collisions_on_cut: true

Joint Structure

  • UnbreakableChain: 7 RigidBody2Ds connected by GrooveJoint2Ds.

    • The head RigidBody2D is fixed with freeze=true.
    • The tail RigidBody2D7 has a mass of 8.0, making it heavy.
    • The second GrooveJoint2D has individual JointBreakParams set to break if the angle exceeds 90 degrees for 0.5 seconds.
  • BreakableChain: 6 RigidBody2Ds connected by GrooveJoint2Ds.

    • The head RigidBody2D has freeze=true and collision_layer=0, disabling collisions.
    • RigidBody2D6 has two GrooveJoint2Ds; one is within the BreakableChain, and the other connects to UnbreakableChain/RigidBody2D7 (linking the two chains).

Configuration Features

  • ChainJointSetupTool is placed, but since auto_create_seg_nodes=false, seg nodes are placed manually.
  • The RopePathBinder2D script is attached to Path2D (for UnbreakableChain).
  • Sprites can be broken using BooleanSpriteCutterWithTaggedShapes.

3. player.tscn (Player)

Purpose
The player character, featuring the ability to push RigidBody2Ds using RigidBodyPusherNatural.

Structure

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)

Configuration Features

  • With normal_direction_weight=0.0 and movement_direction_weight=1.0, it pushes only in the movement direction.
  • It pushes strongly with push_strength=2000.0.
  • It fully considers mass with mass_influence=1.0.

4. areabreaker.tscn (Area Breaker Test Object)

Purpose
An object for testing the functionality of breaking all joints within an Area2D range using AreaJointBreaker2D.

Structure

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 animation
│       └── Calls AreaJointBreaker2D.break_joints_in_target_area()
├── PathRibbonMesh2D (For breaking effect)
│   ├── path_nodes: [../Path2D]
│   ├── width: 3.0
│   └── progress_percent, start_percent are controlled by animation
└── Path2D (Path for breaking effect)

Configuration Features

  • The target_area of AreaJointBreaker2D is set to Area2D.
  • It calls break_joints_in_target_area() via animation.
  • It visualizes the breaking effect using PathRibbonMesh2D.

5. game_scene.tscn (Main Game Scene)

Purpose
The main game scene where various objects are placed.

Structure

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

Placed Objects

  • Testrope2: Rope test object (Position: -564, -17)
  • Player: Player (Position: -612, -80)
  • Ball: Chain test object with ball (Position: 121, 38)
  • Platform1, Platform2: Platforms
  • Pillar: Pillar (Belongs to SpriteGroup, breakable)

Details of Joint Usage Locations

1. Joint Structure in testrope_2.tscn

GrooveJoint2D Placement

Joint Parent node_a node_b Position Settings
StaticBody2D/PinJoint2D3 StaticBody2D .. ../../Node2D/RigidBody2D (12, 4) Head fixed
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) Tail fixed

Common Settings

  • bias: 0.2 (Softer connection with a low value)
  • length: 8.0 (Groove length)
  • initial_offset: 2.0 (Initial offset)

Monitoring Settings

  • BreakableJointMonitor2D breaks if the angle exceeds 80 degrees for 0.3 seconds.
  • ChainPathBinder2D generates paths in auto-detection mode.

2. Joint Structure in testrope_ball_3.tscn

GrooveJoint2D in UnbreakableChain

Joint Parent node_a node_b Settings
RigidBody2D2/GrooveJoint2D RigidBody2D2 ../../RigidBody2D .. bias: 0.9, length: 8.0, initial_offset: 1.0
RigidBody2D3/GrooveJoint2D RigidBody2D3 ../../RigidBody2D2 .. Same as above
RigidBody2D4/GrooveJoint2D RigidBody2D4 ../../RigidBody2D3 .. Same as above
RigidBody2D5/GrooveJoint2D RigidBody2D5 ../../RigidBody2D4 .. Same as above
RigidBody2D6/GrooveJoint2D RigidBody2D6 ../../RigidBody2D5 .. Same as above
RigidBody2D7/GrooveJoint2D RigidBody2D7 ../../RigidBody2D6 .. Same as above

GrooveJoint2D in BreakableChain

Joint Parent node_a node_b Settings
RigidBody2D2/GrooveJoint2D RigidBody2D2 ../../RigidBody2D .. bias: 0.9, length: 8.0, initial_offset: 1.0
RigidBody2D3/GrooveJoint2D RigidBody2D3 ../../RigidBody2D2 .. Same as above
RigidBody2D4/GrooveJoint2D RigidBody2D4 ../../RigidBody2D3 .. Same as above
RigidBody2D5/GrooveJoint2D RigidBody2D5 ../../RigidBody2D4 .. Same as above
RigidBody2D6/GrooveJoint2D RigidBody2D6 ../../RigidBody2D5 .. Same as above
RigidBody2D6/GrooveJoint2D2 RigidBody2D6 .. ../../../UnbreakableChain/RigidBody2D7 Same as above (Links the two chains)

Individual Settings

  • RigidBody2D2/GrooveJoint2D has JointBreakParams set to break if the angle exceeds 90 degrees for 0.5 seconds.

Monitoring Settings

  • Both UnbreakableChain and BreakableChain have BreakableJointMonitor2D and ChainPathBinder2D configured.

System Interactions

1. Chain Visualization System

testrope_2.tscn

  1. ChainPathBinder2D automatically detects RigidBody2Ds under Node2D.
  2. It uses seg1 and seg2 of each RigidBody2D as nodes.
  3. It updates the Curve2D of Path2D.
  4. PathRibbonMesh2D draws the ribbon mesh using the belt.png texture.

testrope_ball_3.tscn

  1. ChainPathBinder2D is configured for both UnbreakableChain and BreakableChain.
  2. UnbreakableChain is drawn with chain.png, and BreakableChain with rope.png.
  3. The Path2D of UnbreakableChain has the RopePathBinder2D script attached (a different visualization method).

2. Joint Breaking System

testrope_2.tscn

  • BreakableJointMonitor2D monitors all joints.
  • It breaks if the angle exceeds 80 degrees for 0.3 seconds.
  • When broken, ChainPathBinder2D automatically splits the path.

testrope_ball_3.tscn

  • BreakableJointMonitor2D for UnbreakableChain has individual settings.
  • Only RigidBody2D2/GrooveJoint2D breaks if the angle exceeds 90 degrees for 0.5 seconds.
  • Other joints use global settings (disabled).

3. Player Push System

player.tscn

  • RigidBodyPusherNatural runs after move_and_slide() of CharacterBody2D.
  • It pushes contacted RigidBody2Ds in the movement direction.
  • It pushes strongly with push_strength=2000.0.

4. Area Breaking System

areabreaker.tscn

  • AreaJointBreaker2D breaks all joints within the Area2D range at once.
  • It calls break_joints_in_target_area() via animation.
  • It visualizes the breaking effect using PathRibbonMesh2D.

Project Settings

Autoload

  • FragmentManagerSingleton: Fragment management system (fragment_manager.tscn object)

Global Groups

  • CutterShapeGroup: Mask shape group for sprite cutting.
  • SpriteGroup: Sprite cutting target group.

Input Map

  • right: Move right (Right Arrow Key)
  • left: Move left (Left Arrow Key)
  • jump: Jump (Space)
  • cut: Cut (Z)

Placement of Used Scripts

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) - As resources, 7 instances

testrope_ball_3.tscn

  • ChainJointSetupTool (scripts/chain_setup_tool.gd)
  • RopePathBinder2D (scripts/rope_solver.gd) - Attached to Path2D
  • ChainPathBinder2D (scripts/chain_path_binder.gd) - 2 instances
  • BreakableJointMonitor2D (scripts/breakable_joint_monitor_2d.gd) - 2 instances
  • JointBreakParams (scripts/joint_break_params.gd) - As resources, 1 instance
  • PathRibbonMesh2D (scripts/path_ribbon_mesh_2d.gd) - 2 instances
  • 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)

Joint Types and Usage Status

GrooveJoint2D

Usage Locations

  • testrope_2.tscn: Between 7 RigidBody2Ds + 2 StaticBody2Ds for fixing = Total 9
  • testrope_ball_3.tscn:
    • UnbreakableChain: 6 (RigidBody2D2 to RigidBody2D7)
    • BreakableChain: 6 (RigidBody2D2 to RigidBody2D6) + 1 (for connecting to UnbreakableChain) = Total 7

Setting Patterns

  1. testrope_2.tscn Pattern

    • bias: 0.2 (Soft)
    • length: 8.0
    • initial_offset: 2.0
  2. testrope_ball_3.tscn Pattern

    • bias: 0.9 (Hard)
    • length: 8.0
    • initial_offset: 1.0

PinJoint2D

Usage Locations

  • Not used in this project (all are GrooveJoint2Ds).

Chain Structure Patterns

Pattern 1: Single Chain (testrope_2.tscn)

StaticBody2D (Fixed)
    └── GrooveJoint2D
        └── RigidBody2D1
            └── GrooveJoint2D
                └── RigidBody2D2
                    └── GrooveJoint2D
                        └── ...
                            └── RigidBody2D7
                                └── GrooveJoint2D
                                    └── StaticBody2D (Fixed)

Pattern 2: Branching Chain (testrope_ball_3.tscn)

UnbreakableChain:
    RigidBody2D1 (freeze)
        └── GrooveJoint2D
            └── RigidBody2D2
                └── GrooveJoint2D
                    └── ...
                        └── RigidBody2D7 (Ball)

BreakableChain:
    RigidBody2D1 (freeze)
        └── GrooveJoint2D
            └── RigidBody2D2
                └── GrooveJoint2D
                    └── ...
                        └── RigidBody2D6
                            ├── GrooveJoint2D (Within BreakableChain)
                            └── GrooveJoint2D2 (Connected to UnbreakableChain/RigidBody2D7)

Physics Settings

RigidBody2D Settings

testrope_2.tscn

  • linear_damp: 10.0 (Linear damping)
  • angular_damp: 10.0 (Angular damping)

testrope_ball_3.tscn

  • mass: 3.0 (Normal link)
  • mass: 8.0 (RigidBody2D7, ball part)
  • freeze: true (Head RigidBody2D)
  • continuous_cd: 2 (Continuous collision detection)

Visualization System

Usage of PathRibbonMesh2D

testrope_2.tscn

  • Texture: belt.png
  • Width: 20.0

testrope_ball_3.tscn

  • UnbreakableChain: chain.png, Width: 20.0
  • BreakableChain: rope.png, Width: 20.0

areabreaker.tscn

  • Texture: GradientTexture2D (Gradient)
  • Width: 3.0 (Changes via animation)

Breaking System

BooleanSpriteCutterWithTaggedShapes

testrope_ball_3.tscn

  • voronoi_seed_count: 30 (Fineness of fragments)
  • disable_related_collisions_on_cut: true (Disables surrounding collisions upon cutting)
  • UnbreakableChain/RigidBody2D7/Node2D/CollisionShape2D belongs to CutterShapeGroup and is used as a breaking mask.

Summary

This project implements a joint, chain, and rope system with the following structure:

  1. testrope_2.tscn object: A 7-link chain connected by GrooveJoint2Ds, breakable via angle monitoring.
  2. testrope_ball_3.tscn object: Two chains (UnbreakableChain and BreakableChain) linked together, with individual settings allowing only specific parts to break.
  3. player.tscn object: Pushes RigidBody2Ds using RigidBodyPusherNatural.
  4. areabreaker.tscn object: Breaks all joints within a range using AreaJointBreaker2D.

All chains are visualized by ChainPathBinder2D and drawn as ribbon meshes by PathRibbonMesh2D.

1 Like