# Ragdoll Cleanup — Implementation Plan ## 1. Overview This plan addresses three specific issues with the stickman's ragdoll state: | # | Issue | Impact | | --- | ---------------------------- | -------------------------------------------------------------------- | | 1 | **Recovery Position Offset** | Stickman floats above the terrain when recovering from ragdoll. | | 2 | **Visual Identity Loss** | Custom colors/shapes disappear; replaced by gray bones. | | 3 | **Profile Persistence** | Joint bending doesn't respect LEFT/RIGHT/FORWARD profile in ragdoll. | Each issue has a clear fix and verification steps. --- ## 2. Issue 1: Recovery Position Offset (Floating) ### 2.1. The Problem When the stickman recovers from ragdoll, it appears floating above the terrain at the landing position, rather than standing with feet on the ground. **Root Cause:** `_reanchor_root_to_landing()` calculates the ground contact point using `_captured_ground_y = torso.center.y + RAGDOLL_TORSO_RADIUS`. This assumes the torso is lying flat on its side. If the ragdoll's torso is rotated (as it often is after a fall), the calculated ground point is incorrect. ### 2.2. The Fix Replace the torso-capsule ground calculation with a **downward raycast** from the ragdoll's center to find the actual terrain surface. **Implementation:** ```gdscript # In _start_recovery() before destroying the ragdoll: func _get_ground_y_at_position(world_pos: Vector2) -> float: var space := get_world_2d().direct_space_state var query := PhysicsRayQueryParameters2D.create( world_pos + Vector2(0, -50), # Start slightly above world_pos + Vector2(0, 2000) # Downward ) query.collision_mask = 1 # Terrain layer var result := space.intersect_ray(query) if result: return result.position.y return world_pos.y # Fallback to current Y ``` Then use this to position the standing figure's feet: ```gdscript # In _reanchor_root_to_landing(): var ground_y := _get_ground_y_at_position(_captured_landing_center) var feet := Vector2(_captured_landing_center.x, ground_y) var new_root := feet + FOOT_OFFSET global_position = new_root ``` ### 2.3. Acceptance Criteria - [ ] Stickman recovers to a standing position with feet touching the terrain surface. - [ ] Works on flat ground. - [ ] Works on slopes and uneven terrain. - [ ] Works on ramp edges. - [ ] No floating or clipping into terrain. ## 3. Issue 2: Ragdoll Visual Identity ### 3.1. The Problem When entering ragdoll mode, the stickman's custom colors and shapes are hidden, replaced by gray capsule "bone guide" visuals. Root Cause: \_enter_ragdoll() hides Body/\* visuals and spawns plain RigidBody2D bodies with default capsule colors. The gray appearance is the default capsule color. 3.2. The Fix Ragdoll bodies should inherit the visual properties (colors, shapes) from the Body/\* nodes. **Implementation:** Read the geometry and color from each Body/\* part node (Line2D or Polygon2D). Create matching visual children on each ragdoll rigidbody. The ragdoll's collision shapes remain simple capsules for physics; visual shapes are cosmetic overlays. Mapping: ``` Body Node Ragdoll Body Visual Child Body/Head Head RigidBody CircleShape2D (color from visual) Body/Body Torso RigidBody CapsuleShape2D (color from visual) Body/LeftUpperArm LeftUpperArm RigidBody CapsuleShape2D (color from visual) etc. etc. etc. ``` **Important:** The visual shapes are positioned/rotated to match the ragdoll body's orientation. They are cosmetic only — physics uses the capsule collision shapes underneath. ### 3.3. Acceptance Criteria - [ ] Ragdoll bodies match the stickman's custom colors and shapes. - [ ] No gray "bone guide" visuals appear. - [ ] Visuals transition smoothly between ANIMATED and RAGDOLL. - [ ] Visuals stay consistent when exiting ragdoll. ## 4. Issue 3: Profile Persistence in Ragdoll ### 4.1. The Problem The stickman's facing profile (LEFT/RIGHT/FORWARD) bone bending does not persist into ragdoll mode. Joints bend unrealistically when ragdolling. Root Cause: The ragdoll's PinJoint2D angular limits are set once at build time using a generic rule. They don't account for the current facing_profile. ### 4.2. The Fix The ragdoll build should read the current facing_profile and apply profile-specific joint limits. **Implementation:** When building the ragdoll (\_build_ragdoll()), pass the current facing_profile to \_apply_ragdoll_joint_limits(): **FORWARD:** Use the existing default (elbows/knees fold toward +CW). **LEFT:** Mirror the joint limits (swap the elbow/knee fold direction). **RIGHT:** Use the same as FORWARD (or mirror appropriately). **Using PROFILE_FLAGS:** The existing PROFILE_FLAGS constants already map facing profiles to per-joint flip_bend_direction flags. Use these to determine joint limit mirroring: ```` Joint FORWARD LEFT RIGHT LeftArm Normal Normal Inverted RightArm Inverted Normal Normal LeftLeg Inverted Inverted Normal RightLeg Normal Inverted Inverted `` The flip_bend_direction flag determines which way the joint naturally bends. This should be applied to the ragdoll's PinJoint2D angular limits. Example for elbow/knee joints: ```gdscript # If flipped = true, the joint bends toward -CW instead of +CW if flipped: joint.angular_limit_lower = -150.0 joint.angular_limit_upper = 5.0 else: joint.angular_limit_lower = -5.0 joint.angular_limit_upper = 150.0 ```` ### 4.3. Acceptance Criteria - [ ] LEFT profile ragdoll joints bend the correct way. - [ ] RIGHT profile ragdoll joints bend the correct way. - [ ] FORWARD profile ragdoll joints bend the correct way. - [ ] Profile persists after recovery. - [ ] Joints do not hyperextend or bend backwards. ## 5. Implementation Order | Step | Task | Dependencies | | ---- | ----------------------------------------------------------------------------------------- | ------------ | | 1 | Fix Recovery Position — Replace torso-capsule ground calculation with downward raycast. | None | | 2 | Fix Ragdoll Visuals — Ragdoll bodies inherit Body/\* geometry/color as cosmetic children. | None | | 3 | Fix Profile Persistence — Ragdoll joints respect facing_profile via PROFILE_FLAGS. | None | | 4 | Integration Test — Test all three fixes together in the Sandbox Stage. | Steps 1-3 | ## 6. File Changes Summary | File | Changes | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | scripts/stickman_rig.gd | Fix \_reanchor_root_to_landing() with raycast; \_build_ragdoll() reads facing_profile; \_apply_ragdoll_joint_limits() uses profile flags for mirroring; \_enter_ragdoll() preserves visual geometry. | ## 7. Full Acceptance Criteria ### 7.1. Recovery Position - [ ] Stickman recovers to a standing position with feet touching the terrain surface. - [ ] Works on flat ground, slopes, and uneven terrain. - [ ] No floating or clipping into terrain. ### 7.2. Ragdoll Visuals - [ ] Ragdoll bodies match the stickman's custom colors and shapes. - [ ] No gray "bone guide" visuals appear. - [ ] Visuals transition smoothly between ANIMATED and RAGDOLL. - [ ] Visuals stay consistent when exiting ragdoll. ### 7.3. Profile Persistence - [ ] LEFT profile ragdoll joints bend the correct way. - [ ] RIGHT profile ragdoll joints bend the correct way. - [ ] FORWARD profile ragdoll joints bend the correct way. - [ ] Profile persists after recovery. - [ ] Joints do not hyperextend or bend backwards. ### 7.4. Backward Compatibility - [ ] Existing ragdoll behavior remains intact. - [ ] Existing profiles work as before. - [ ] No new errors or warnings in the console.