Body step 2.2: fix the 2.1 headset instabilities

Spike now runs real input (90 Hz sample-and-hold tracking + jitter under 144 Hz
physics), which reproduced the playtest. Root causes fixed:
- PoseFilter/RagdollDriver: timestamped extrapolation of tracking, one tick
  pipeline shared by PlayerRig and the spike
- low-pass all feed-forwards (ground control amplified jitter by body mass)
- arm muscles back to local targets (physical-frame aim fed chest rotation back)
- structural hand strength only when braced or holding
- no free-path view chasing while grounded (8 m crouch slide); stick hold-back
- explicit inertia for the Legs body (shape-less tuck tumbled the pelvis)
- world grab: Box3D shape queries return a null collider, use collider_id
- new crouch-hold phases; world-grab detection asserted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
FoxyzandClaude Opus 5.5 committed 2026-10-02 08:37:56 +03:00
1 parent 2aff2b61da
commit 6006c5de98
8 files changed
+352 -81

No files matched your search

+39
View File
@@ -92,3 +92,42 @@ Changes and the measured reasons:
Ground steeper than `MaxSlopeDegrees` 35° gives no support, so the 40° ramp can't be walked up; the 18° one can.
Still open: the shoulder cone limit (needs a fork addition). `tools/playground_shots.tscn` renders overview PNGs for
layout checks.
## Step 2.2 — the 2.1 playtest was unstable; root causes (2026-10-02)
The owner reported everything "all over the place":
- Mantling swung the chest out of control and the hands "wobbled more and more".
- Crouching made the body slide around and spin.
- Nothing static was grabbable.
- The steep ramp slipped the body out from under them.
RagdollSpike passed all of it, because its input was IDEAL: smooth poses every 144 Hz tick, no jitter. Fixes:
1. **The spike now runs on REAL input by default**: tracking sample-and-hold at 90 Hz under 144 Hz physics, plus
0.5 mm / 0.1° jitter per sample (`-- ideal` / `nonoise` / `nohold` isolate the factors). Lesson: a body-physics
test with perfect input proves nothing about the headset.
2. **`PoseFilter` + `RagdollDriver`** (`scripts/RagdollDriver.cs`). Tracked poses are timestamped per new sample
and extrapolated between samples in play-space-local coordinates. One driver runs the tick pipeline for
both `PlayerRig` and the spike, so the test runs the game's code path.
3. **Low-pass every feed-forward**: muscles/elbow τ 0.05 s, ground control τ 0.12 s. Ground control's velocity
term multiplies by the whole body mass, so 1.5 mm of jitter became hundreds of newtons of buzz (pelvis
0.27 → 0.04 m/s at rest).
4. **Arm muscles stay LOCAL to the chest's target pose.** 2.1 aimed them in the physical chest frame, which closes a
rotation feedback loop: the chest turns, the world-fixed arm targets push back on the chest, and the chest turns
further. Jitter excited it into a slow twist (eye drifting 15 cm): the mantle "chest slipping". Only a
horizontal translation of the reach is kept (body held back from the camera).
5. **Structural hand strength only when the hand pushes on or holds something.** A hand reaching past its arm's
length into free air pulled the whole body down by up to 400 N (crouch: eye 11 cm off).
6. **No free-path view chasing while grounded.** Any eye/camera mismatch (crouch poses can't match exactly) moved
the view, the pose target followed, the body followed, and so on: an 8 m slide while holding a crouch. The view
is now only pushed back when geometry blocks the head. Instead, the stick stops pushing in the direction the
body is held back (`PlayerRagdoll.HeldBack`, `PlayerRig.HoldBack`).
7. **Explicit inertia on the `Legs` body.** Disabling its only collision shape (tuck) left it with no rotational
inertia; its 400 N·m drive then tumbled the pelvis forward, which flipped the "yaw". This was the crouch spin.
Rule: a body whose shapes can all be disabled needs explicit `Inertia`.
8. **World grabs: the Box3D wrapper returns a null `collider` from `IntersectShape`**, only `collider_id`. Resolve it
with `GodotObject.InstanceFromId`. The grab sphere is now 7 cm, checked at the palm and then the hand centre.
The spike asserts the game's own `PropGrabber.WorldUnderPalm` finds the bar.
New spike phases: hold a crouch (eyes 1.0 m) and a deep crouch (0.7 m) without drift (< 5 cm) or spin (< 5°),
eye on camera (< 5 cm). 29 phases total, all on real input.