Skip to content

fix: rig bodies are top_level — moving character roots froze the rig - #96

Merged
blugart-dev merged 1 commit into
mainfrom
fix/top-level-rig-bodies
Aug 12, 2026
Merged

blugart-dev merged 1 commit into
mainfrom
fix/top-level-rig-bodies

Conversation

@blugart-dev

Copy link
Copy Markdown
Owner

Summary

A character root that writes its transform every physics frame (CharacterBody3D.move_and_slide(), nav-driven NPCs) re-teleported every rig body to parent_xform * local each frame, silently discarding that frame's physics integration. The visible result: the rig froze solid while the character moved — no animation showing through PhysicsRigSync, no visible hit reactions — while the springs pumped clamp-level velocities into the locked bodies, which then released all at once the moment the root stopped moving (e.g. on death), as an explosive ragdoll.

Fix: rig bodies are top_level = true (world-space, immune to ancestor transform writes), for both runtime-built and RigBaker-baked rigs. Position springs already carry the rig along with the character — their targets move with the skeleton — so parent transform inheritance was never load-bearing.

Measured on the FPS integration that found it (walking nav zombie, LeftUpperLeg orientation travel over 240 physics frames):

metric before after
animation target travel 10.3 rad 10.3 rad
rendered pose travel 0.012 rad 9.8 rad
commanded angular velocity pegged at 20 rad/s clamp ~2.6 rad/s
death-ragdoll peak body velocity 10.1 m/s (clamp, released at once) 3.5 m/s

Related Issue

None — found during integration.

Type

  • Bug fix
  • Tests

Checklist

  • Tests pass (godot --headless --path . --script addons/gut/gut_cmdln.gd -- -gdir=res://test/ -gexit) — 143/143, including new regression test test_rig_survives_moving_character_root (measures ~0.000 rad body travel pre-fix)
  • No new warnings in Godot console
  • Documentation updated (if public API changed) — no API change; CHANGELOG Unreleased entry added
  • Demo scenes work with changes — animated_npc (the moving-root demo) is the in-repo case this fixes
  • No breaking changes to existing API (or documented in PR)

🤖 Generated with Claude Code

A character root that writes its transform every physics frame
(CharacterBody3D.move_and_slide, nav-driven NPCs) re-teleported every rig
body to parent_xform * local each frame, silently discarding that frame's
physics integration. The rig froze solid while the character moved (no
animation showing through, no visible hit reactions) and the springs
pumped clamp-level velocities into the locked bodies, which released all
at once when the root stopped (e.g. on death) as an explosive ragdoll.

Position springs already carry the rig along with the character (their
targets move with the skeleton), so parent transform inheritance was
never load-bearing. top_level applies to runtime-built and baked rigs.

Numbers from the FPS integration that found it (walking nav zombie,
LeftUpperLeg travel over 240 physics frames): animation 10.3 rad, rendered
0.012 rad before / 9.8 rad after; death-ragdoll peak body velocity
10.1 m/s (the clamp, released) before / 3.5 m/s after.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@blugart-dev
blugart-dev merged commit 71c3210 into main Aug 12, 2026
1 check passed
@blugart-dev
blugart-dev deleted the fix/top-level-rig-bodies branch August 12, 2026 12:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant