Spike: decoupled hands chase the controller (issue #42) #43
Loading…
Reference in a new issue
No description provided.
Delete branch "muse-lantern/da-game:hand-ik-rework"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spike: decoupled hands chase the controller
This is a spike to feel, not a decision. It tries the direction from #42 (comments 918, 920, 960): decouple the hands from the controllers, tracking hands to the controllers the same way grabbed objects are tracked, so when a grabbed gun drifts because it is caught on physics, the hand sticks with the gun. The H6 pivot split waits on what this shows — it is NOT built here.
What it tries
HandFollower(modules/deadair/src/player/hand_follower.gd, Node3D, child ofPlayerRig— NOT under the controller) chases its grip controller's pose with an exponential spring/damper in_physics_process(priority 10, likeGrabbable._follow): positionalpha = 1 - exp(-stiffness * delta), rotationBasis.slerp. Tunable:stiffness20.0/s,angular_stiffness20.0/s (~50 ms time constant),stick_radius0.05 m.PlayerRig._readyreparents eachHandViewonto its follower (follower pre-placed at the grip transform, so the glove does not jump).HandInteractor.grip_node()returns the follower (fallback to the grip controller when there is none);HandColliderfollows the follower; thehand_collidermeta is set on both the follower and the grip (the flat controller still grabs with the grip directly, dev-only path). The laser pointer stays on the controller; the grip rings insandbox_gizmos.gdstay controller-anchored, so drift is visible.Grabbable.follow_blockedis true, the follower's desired position clamps to withinstick_radiusof the held item's grip point. A clamp, not a park — pulling the controller back moves the clamped target back too, so the pair unblocks. Rotation is never leashed.enter_sandboxteleports the grips 5.5 m and the followers chase for a second while the held gun's snaptis driven by the chase.da_trigger_primary_analog/da_grip_primary_analogeach frame;HandViewreads them from the follower. No per-grip poses, no per-finger API, no H5 calibration change.What it measures
grab_stategains ahand_followsection per hand fromHandFollower.follow_snapshot(): hand + controller transforms, drift vector +drift_m,angular_drift_deg,leashed, and the tuning values.set_hand_follow(sideboth/L/R; optionalstiffness,angular_stiffness,stick_radius) for live tuning without rebuilding.tests/hand_follow_check.gd(29 checks, in CI): structure (followers exist, HandViews reparented,grip_node()is the follower, collider follows the follower), lag + convergence (position and rotation — the hand does not teleport, drift < 0.005 after settling), leash (pistol held, wall in front, grip driven past it: gun blocked, follower leashed, hand stays 0.050 m from the stuck gun's grip point, hand-to-controller drift 0.332 m, gun does not pass the wall), release (converges again, leash clears).What it does NOT decide
Test-drive adaptation (same behaviour, new hand model)
tests/mag_rail_check.gddrove the grip in 5 cm/frame steps, which a rigid hand absorbed 1:1. With a follower, that drive leaves the hand far behind the grip: when the snap fires and the grip stops, the follower's residual travel along the 5 cm rail drivestto 1 and the mag clicks in during the aim. The aim now drives at 0.3 m/s (time-based, frame-rate independent; ~1.5 cm follower lag) with the aim budgets at 3.0 s, and the point-rail mag spawns beside/below the gun so the approach comes up into the magwell instead of crossing the scene into the gun's side face (where the leashed hand sticks with the blocked mag). Assertions unchanged. Measured on main for comparison: the old drive only passed phase 8 because the rigid hand dragged the mag along the gun's face, popped it off the corner, and flung it 2 m up before it fell back onto the magwell — the follower does not do that, and should not.Verification (lantern-vm, Godot 4.6.3 pin)
--importafter a.godotwipe: 0 ERROR both passes.python3 tools/check.py: 6/6.hand_follow_check, 29 ok;mag_rail_check63 ok).add_childon null — one each infirearm_checkandmag_filo_check— plus 1x nonexistentis_trigger_downinfirearm_check; same three as on main).test_e2e.pyunder xvfb): PASS, 140 ok.How to feel-test it
In-headset, sandbox, grab the generic pistol in R (and a mag in L):
set_hand_followwith stiffness 40 (tighter) or 10 (looser) and compare.grab_state'shand_follow.drift_m.hand_follow.leashedreads true while it holds.Commits:
c90942b(spike) +1a7e304(mag_rail drive adaptation). Base: maina583800(PR #41 merge).1a7e304aa1d47c6be6c8