- Updated `DEBUG_RECOVERY` to false for production. - Introduced `RAGDOLL_JOINT_BAND_LIMITS` for customizable joint bend limits based on facing profile. - Added `RECOVERY_LEG_SIDE_FORCE` for manual control of leg IK bend direction during recovery. - Implemented `RECOVERY_JOINT_PATH` to allow optional tween path overrides for elbow/knee recovery. - Removed debug print statements related to recovery visuals to clean up output. - Adjusted `_apply_ragdoll_joint_limits` to utilize new bend limits configuration. - Enhanced documentation in `ragdoll-cleanup.md` to reflect changes in the recovery pipeline and tuning tables.
8.1 KiB
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.
I
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:
# 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:
# 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.