Refactor stickman rig and ragdoll mechanics; enhance pose restoration and stability

- Disabled constraints for the stickman rig's head bone to allow for smoother animations.
- Improved mode transitions in the sandbox stage to preserve stickman poses between EDIT and DIRECT modes.
- Added side profile stabilization for knee bends in the ragdoll component to prevent unnatural poses during physics interactions.
- Enhanced the snap-to-standing functionality to restore the stickman's original pose accurately.
- Introduced new tests for validating pose preservation during mode transitions and ragdoll behavior during walking animations.
- Created a new scene for testing stickman bending and ragdoll transitions.
This commit is contained in:
2026-09-18 22:44:48 -04:00
parent db4ff8d939
commit fbce638bc5
12 changed files with 692 additions and 39 deletions
+19 -11
View File
@@ -644,6 +644,7 @@ func _viewport_to_world(viewport_pos: Vector2) -> Vector2:
func set_mode(mode: StageMode) -> void:
if mode == current_mode:
return
var previous_mode: StageMode = current_mode
if mode == StageMode.PLAY and not _cli_startup:
if not _save_scene_to_path(AUTOSAVE_PATH, true):
push_warning("SandboxStage: autosave before Play failed.")
@@ -652,9 +653,9 @@ func set_mode(mode: StageMode) -> void:
_cancel_palette_drag()
match mode:
StageMode.EDIT:
_enter_edit_mode()
_enter_edit_mode(previous_mode)
StageMode.DIRECT:
_enter_direct_mode()
_enter_direct_mode(previous_mode)
StageMode.PLAY:
_enter_play_mode()
_sync_mode_buttons()
@@ -667,8 +668,8 @@ func set_mode(mode: StageMode) -> void:
func _enter_edit_shared() -> void:
# Snap stickmen straight back to their standing pose/position (no stand-up
# tween glide), stopping any director queue first.
# Restore stickmen to their authored spawn/ghost pose (no stand-up tween
# glide), stopping any director queue first.
for node: Node2D in _world_children_selectable():
if node is STICKMAN_RIG:
var rig := node as STICKMAN_RIG
@@ -697,8 +698,11 @@ func _enter_edit_shared() -> void:
_collision_pairs.clear()
func _enter_edit_mode() -> void:
_enter_edit_shared()
func _enter_edit_mode(previous_mode: StageMode) -> void:
# EDIT and DIRECT share the same frozen world. PLAY still needs the complete
# simulation cleanup and authored-pose restore before editing resumes.
if previous_mode != StageMode.DIRECT:
_enter_edit_shared()
_clear_director_pending()
_set_edit_controls_visible(true)
_set_direct_controls_visible(false)
@@ -730,11 +734,15 @@ func _clear_director_pending() -> void:
_director_visuals.clear_edit_waypoint()
## Direct is internally an "edit-with-direct" state: same freeze/stand/gizmo
## side effects, but with the spawner/grid controls hidden, the director hint
## shown, and any placement/selection/pending-target cleared.
func _enter_direct_mode() -> void:
_enter_edit_shared()
## Direct is internally an "edit-with-direct" state: the same frozen world,
## but with the spawner/grid controls hidden, the director hint shown, and any
## placement/selection/pending-target cleared.
func _enter_direct_mode(previous_mode: StageMode) -> void:
# EDIT and DIRECT share the same non-simulating world. Preserve the exact
# placed stickman pose between them; a transition from PLAY still needs the
# full cleanup and authored-pose restore.
if previous_mode != StageMode.EDIT:
_enter_edit_shared()
set_placement_mode("")
_selection.clear_selection()
_clear_director_pending()