Grab buffer (squeeze early, catch on contact), elbow can't fold inward when the controller turns out

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
FoxyzandClaude Opus 5.5 committed 2026-10-02 21:31:14 +03:00
1 parent ca60df3d75
commit b8365ee95f
4 files changed
+48 -5

No files matched your search

+23 -1
View File
@@ -84,6 +84,7 @@ public partial class RagdollSpike : Node3D
_phases.Add(("hinge sign", SetupHinge, TickHinge, 0.3f, FinishHinge));
_phases.Add(("pose filter: render-timed tracking moves evenly (no 18 Hz beat)", Rest, _ => { }, 0.05f, FinishPoseFilter));
_phases.Add(("elbow: a controller turned outward doesn't fold the elbow inward", Rest, _ => { }, 0.05f, FinishElbowOut));
_phases.Add(("stands still, head on the camera, hands on the controllers", Rest, _ => { }, 4f, FinishStand));
_phases.Add(("reaches forward, out and overhead", Rest, TickReach, 4.5f, FinishReach));
_phases.Add(("fast arm swings stay attached", Rest, TickSwing, 3f, FinishSwing));
@@ -234,6 +235,26 @@ public partial class RagdollSpike : Node3D
private int NewSnaps => _ragdoll.Snaps - _snapsAtStart;
// Right arm reaching forward-down, controller yawed 0..90° outward: the elbow must stay on the
// outer side of the shoulder→wrist line (toward +X), never toward the other arm.
private static bool FinishElbowOut()
{
float worst = float.MaxValue;
for (int deg = 0; deg <= 90; deg += 15)
{
ArmSolver arm = new();
Vector3 shoulder = new(0.2f, 1.45f, 0f), target = new(0.25f, 1.05f, -0.4f);
Basis hand = new Basis(Vector3.Up, -Mathf.DegToRad(deg)) * new Basis(Vector3.Right, -0.6f);
for (int i = 0; i < 200; i++)
arm.Solve(shoulder, target, Basis.Identity, Vector3.Right, hand, 0.3f, 0.27f, 1f / 144f);
Vector3 dir = (arm.Wrist - shoulder).Normalized();
Vector3 mid = shoulder + dir * (arm.Elbow - shoulder).Dot(dir);
worst = Mathf.Min(worst, arm.Elbow.X - mid.X); // < 0 = elbow toward the midline
}
GD.Print($"RAGDOLL: elbow vs the arm line with the controller turned 0..90° outward: most inward {worst:F3} m (limit -0.04)");
return worst > -0.04f;
}
// A controller moving at 1 m/s, sampled once per 90 Hz frame (predicted for that frame's render
// time), read by 144 Hz ticks. Per-tick output steps should all be 1/144 m: timestamped by
// arrival they alternate (1 or 2 ticks late), timestamped by render time they don't.
@@ -1117,7 +1138,8 @@ public partial class RagdollSpike : Node3D
{
float t = _t;
// Walk up to a waist-high ledge (stop before its far end); a chest-high one starts within reach.
_stickVelocity = (t < 1f && _ledgeTop < 1f) || (t > 4.5f && t < 5.5f) ? new Vector3(0f, 0f, -0.8f) : Vector3.Zero;
// (A 70 cm box is too small to walk on after climbing it.)
_stickVelocity = (t < 1f && _ledgeTop < 1f) || (t > 4.5f && t < 5.5f && _ledgeBox == null) ? new Vector3(0f, 0f, -0.8f) : Vector3.Zero;
// Crouch to load the legs for a waist-high ledge; at a chest-high one you reach up instead.
float crouch = Mathf.SmoothStep(0f, 1f, Mathf.Clamp((t - 1f) / 0.8f, 0f, 1f)) * (_ledgeTop < 1f ? 1f : 0f);
float rise = Mathf.SmoothStep(0f, 1f, Mathf.Clamp((t - 2.2f) / 1.6f, 0f, 1f));