- Introduced `PHASE_3a_CORE_DIRECTOR.md` detailing the core functionality for directors, including navigation, action queue, UI, waypoint visualization, and action execution. - Implemented `StageDirectorVisuals` for drawing stickman action queues in edit mode, including waypoints and action badges. - Created `SpeechBubble` class for displaying speech bubbles above stickmen, with customizable text and styling.
13 KiB
13 KiB
Technical Debt & Optimization Log
Overview
This document tracks known technical debt, optimization opportunities, and minor improvements for the Stickman Studio project. Items are prioritized by impact and effort. Update this log as issues are identified, resolved, or deprioritized.
Current Observations
| # | Issue | Priority | Status | Notes |
|---|---|---|---|---|
| 1 | Neck Joint Free Rotation — The head can spin 360° during violent ragdoll tumbles, which looks unnatural. | Medium | Open | Consider adding angular_limit_enabled = true with ±45° limits and low stiffness to allow natural lolling while preventing full rotations. |
| 2 | Torso Capsule Origin — The torso capsule's local origin should be at its midpoint for natural rotation. Currently derived from bone distance; verify alignment. | Low | Open | Test by rotating the torso body in ragdoll mode — it should spin about its center, not its top. Adjust position offset if needed. |
| 3 | Collision Layers Separation — Bodies and terrain share layer 1/mask 1. This may cause self‑collision issues (limbs clipping through each other) under high stress. | Low | Open | Future enhancement: assign ragdoll limbs to layer 2, terrain to layer 1, and use masks to allow limb‑limb collision only where desired. |
| 4 | Performance (Ragdoll Pooling) — Spawning 10 bodies + 9 joints procedurally is fine for a single rig. If the scene ever contains dozens of ragdolls, consider a pooling system to avoid allocation spikes. | Low | Open | Not needed now, but worth noting if scaling to large crowds. |
| 5 | Line2D ↔ Capsule Radius Match — Limbs use Line2D width 16, ragdoll capsules radius 8. These align visually. |
Low | ✅ Resolved | Verified during implementation. No action needed. |
| 6 | Recovery Animation Starting Pose — The stand_up animation must work from any captured ragdoll pose. Currently uses a fixed start frame. |
High | ✅ Resolved | Phase 11: _start_recovery() captures the 10 bodies' rig‑local pose, snap‑solves the skeleton via the 6 IK targets, then _play_stand_up() tweens the markers directly from the captured values to STAND_POSE (STAND_UP_DURATION, sine ease‑in‑out) — the baked stand_up animation is not played (a fixed first keyframe can never match an arbitrary rest pose; the earlier bridge‑into‑the‑animation approach caused a visible jump and was removed). Revision: the snap now derives the hip (pos − dir·half) and wrist/ankle (pos + dir·half) from the capsule ends and subtracts the Torso bone's bone_angle for the marker rotation, so recovery starts from the ragdoll's exact final pose (e.g. sitting stays sitting). (2026‑08‑27) |
| 7 | Transition Visual Pop — The crossfade between kinematic and ragdoll currently uses a simple modulate.a lerp. This may cause ghosting if the kinematic and ragdoll poses are misaligned. |
Medium | ✅ Resolved | Phase 11: the entry is now an instant handoff — the ragdoll is built from the current solved bone positions (AnimationPlayer.stop(true) keeps the pose), then Body/* is hidden and the IK stack disabled in the same call. The earlier opacity crossfade + pin‑softness ramp was removed on director feedback (it read as ghosting, since both poses are identical). Recovery snap‑solves the kinematic skeleton to the captured ragdoll pose before re‑showing Body/*, eliminating the pop on both directions. (2026‑08‑27) |
| 8 | Rest Timeout UI — The director can adjust rest_timeout via inspector, but there is no in‑world UI in the physics harness yet. |
Low | ✅ Resolved | Phase 11: added a Rest SpinBox (0.1–10 s, step 0.1) to the harness UI that writes _rig.rest_timeout (runtime‑only), plus a "Recover Now" button → _rig.request_recovery(). (2026‑08‑27) |
| 9 | Animation Generation DRY — create_walk.gd is a standalone script. It should be merged into a unified create_animations.gd that also generates stand_up and idle animations. |
Medium | ✅ Resolved | Phase 11: create_walk.gd deleted; new scripts/create_animations.gd (@tool extends EditorScript) bakes walk_left/walk_right (same keyframes) and a one‑shot stand_up into the scene's AnimationLibrary (the baked stand_up is an authored reference only — runtime recovery tweens the IK targets directly). (2026‑08‑27) |
| 10 | Rig Collision Proxy Re‑addition — The proxy is re‑added on ragdoll exit, but may cause a brief visual pop if it appears while the kinematic rig is visible. | Low | Open | Phase 11 still re‑adds the proxy as soon as RECOVERING begins (state_changed handler), while Body/* is already visible — the static box can pop in around the standing figure before the stand‑up completes. Consider delaying re‑addition until after recovery finishes (ANIMATED). (2026‑08‑27) |
| 11 | Stage Freeze Abstraction — Sandbox Stage EDIT‑mode freezing is type‑specific: RigidBody2D.freeze_mode = FREEZE_MODE_KINEMATIC for props, StickmanRig.set_ragdoll(false) for stickmen, nothing for StaticBody2D terrain. There is no unified "freeze" abstraction over the mixed physics population. |
Low | Open | A future physics type (e.g. Area2D‑based sensors) will need another case in scripts/sandbox_stage.gd _enter_edit_mode() / _enter_play_mode(). Consider a duck‑typed set_simulating(bool) interface once more physical object kinds appear. (2026‑08‑27) |
| 12 | Stage AABB Selection Precision — StageSelection.get_world_aabb uses conservative world‑space AABBs (polygon point union / fixed rig rect), not point‑in‑polygon. |
Low | Open | Clicks in the bounding‑box corners of large or rotated terrain may select a block even outside its polygon, and overlapping blocks can mis‑select. Refine with Geometry2D.is_point_in_polygon() for TerrainBlock/PropBlock polygons (and circle distance for ball props) once selection precision matters. (2026‑08‑27) |
| 13 | Slope-aware walking physics & dynamic obstacle avoidance (deferred) — Phase 3a bakes a real navigation mesh (per-TerrainBlock polygon decomposition into a code-built NavigationRegion2D) and walk_to follows NavigationAgent2D paths, but the figure walks the path with an upright pose (no tilt to the slope, no physics sliding) and avoidance_enabled = false, so it can path through props and other stickmen. |
Medium | Open | A stickman crossing a ramp/stair follows the sloped footprint but looks flat-footed, and does not avoid moving props or each other. Future: tilt/rotate the figure to the path slope and enable RVO avoidance (avoidance_enabled, avoidance layers, velocity handling) once props/other stickmen are registered as obstacles. (2026‑08‑29) |
Suggested Future Improvements (Beyond Current Scope)
| Improvement | Description | Status / Priority |
|---|---|---|
| Soft Transition Blending | Add physical blending (joint stiffness ramp) to complement visual crossfade. | ✅ Done, then removed — implemented with Phase 11, but the whole crossfade was removed on director feedback (ghosting); entry is now an instant handoff. |
| Ragdoll Recovery Interruptibility | Allow the director to force a mode switch mid‑recovery (e.g., if they want the character to ragdoll again immediately). | ✅ Done |
| Multiple Rig Support | Ensure all state variables are instance‑specific (already true) and that the harness can manage multiple rigs. | Future |
| Animation Blending (IK vs. Physics) | Blend between the animation‑driven pose and the ragdoll pose during transition to prevent snapping. | Future |
| Save/Load for Ragdoll State | Save the current ragdoll pose to .stk (e.g., for storyboarding a fall). |
Future |
How to Use This Log
- New Issues: Add a row with
#, description,Priority(Low/Medium/High),Status(Open/In Progress/Resolved/Deprecated), andNotes. - Resolving Issues: Change
StatustoResolvedand add a note with the date and fix details. - Deprioritizing: If an issue is no longer relevant, mark it
Deprecatedwith a brief reason. - Quarterly Review: Revisit this log every major milestone to reassess priorities.
Change Log
| Date | Change |
|---|---|
| 2026-08-26 | Initial creation — migrated observations from Phase 10 review. |
| 2026-08-27 | Phase 11 resolved #6 (recovery starting pose), #7 (transition visual pop), #8 (rest timeout UI), #9 (animation generation DRY); #10 (proxy re‑addition) remains open with updated scope. Later revision: stand‑up recovery switched from bridge‑into‑baked‑animation to a direct marker tween (captured pose → STAND_POSE), fixing a visible jump; baked stand_up kept as authored reference only. Second revision: ragdoll entry builds from the current solved bone positions (IK disabled only after the blend completes) and the recovery snap derives joint ends from capsule half‑heights with Torso bone_angle compensation, fixing the entry pose‑pop and the "recovery starts lying" bugs. Third revision: the entire crossfade/blend (transition_duration, BlendDirection, opacity fade, softness ramp) was removed on director feedback — entry is now an instant handoff (build at current pose → hide Body/* → disable IK in one call), since the ragdoll spawns at the identical pose and a fade only read as ghosting. |
| 2026-08-27 | Sandbox Stage Builder (Phase 2) added scripts/sandbox_stage.gd + stage_spawner.gd / stage_selection.gd / stage_gizmos.gd + scenes/sandbox_stage.tscn. Logged #11 (no unified freeze abstraction over the mixed StaticBody2D / RigidBody2D / Node2D population) and #12 (selection hit‑testing uses world‑space AABBs rather than point‑in‑polygon). |
| 2026-08-29 | Phase 3a (Core Director Functionality) spec written (docs/phase_3a_spec.md). Logged #13 (slope-aware walking physics + dynamic obstacle avoidance deferred — the nav mesh itself is built in 3a). Notable non-debt decisions recorded in the spec: Play mode now runs the director script instead of auto-ragdolling stickmen; walk_to(target) treats target as a feet/ground destination via FOOT_OFFSET, with the NavigationAgent2D child placed at the feet (0,+385) so it paths on the ground-level nav mesh. |
| 2026-08-29 | walk_to stops-after-a-few-px bug fixed. _update_walking (Phase 3a) now defers nav reads until NavigationServer2D.map_get_iteration_id(...) != 0 (map-sync guard) and forces the path query via get_next_path_position() before any empty-path/finished check. Follow-up (same day): the initial "warn + finish in place" unreachable-target policy was itself reported as "stickman stands still with a waypoint" and was replaced by hybrid nav/direct steering — an on-mesh target follows the nav path (_walk_mode = "nav"), an off-mesh/unreachable target walks straight to the clicked waypoint (_walk_mode = "direct", root target = waypoint + FOOT_OFFSET), with no push_warning; _walk_path_grace removed (map-sync guard + forced path query replace it); the debug trace now carries `mode=nav |
End of Log