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:
1 parent
2aff2b61da
commit
6006c5de98
8 files changed
+352
-81
No files matched your search
+19
-25
@@ -33,9 +33,9 @@ public partial class PlayerRig : Node
|
||||
private bool _haveLastOrigin;
|
||||
private Vector3 _moveVelocity;
|
||||
private bool _snapArmed = true;
|
||||
private readonly Vector3[] _ctrlPrev = new Vector3[2];
|
||||
private readonly MeshInstance3D[] _ghosts = new MeshInstance3D[2];
|
||||
private bool _rebuild = true;
|
||||
private RagdollDriver _driver;
|
||||
|
||||
public PlayerRagdoll Ragdoll => _ragdoll;
|
||||
public static bool Spectator { get; private set; }
|
||||
@@ -84,6 +84,7 @@ public partial class PlayerRig : Node
|
||||
// frame); the body is simulated, so it interpolates.
|
||||
_ragdoll = new PlayerRagdoll { Name = "Ragdoll", PhysicsInterpolationMode = PhysicsInterpolationModeEnum.On };
|
||||
AddChild(_ragdoll);
|
||||
_driver = new RagdollDriver { Solver = Solver, Ragdoll = _ragdoll };
|
||||
BodyProfile.Changed += _ => _rebuild = true;
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
@@ -121,30 +122,16 @@ public partial class PlayerRig : Node
|
||||
if (_haveLastOrigin && _ragdoll.Built && IsJump(_lastOrigin, origin))
|
||||
Carry(origin * _lastOrigin.AffineInverse());
|
||||
|
||||
if (_ragdoll.Built && !_rebuild)
|
||||
{
|
||||
// 2. Stick locomotion, 3. reconciliation.
|
||||
// 2. Stick locomotion.
|
||||
if (_ragdoll.Built && !_driver.RebuildRequested)
|
||||
Locomote(dt);
|
||||
Vector3 correction = _ragdoll.OriginCorrection(_camera.GlobalPosition, _origin.GlobalPosition.Y, dt);
|
||||
if (correction != Vector3.Zero)
|
||||
_origin.GlobalPosition += correction;
|
||||
}
|
||||
|
||||
// 4. Pose + muscles.
|
||||
Transform3D head = _camera.GlobalTransform;
|
||||
Transform3D left = _left.GlobalTransform, right = _right.GlobalTransform;
|
||||
Solver.Solve(profile, head, left, right, _origin.GlobalPosition.Y, dt);
|
||||
if (_rebuild || !_ragdoll.Built)
|
||||
{
|
||||
_ragdoll.Build(profile, Solver, left, right);
|
||||
_rebuild = false;
|
||||
_ctrlPrev[0] = left.Origin;
|
||||
_ctrlPrev[1] = right.Origin;
|
||||
}
|
||||
Vector3 lv = (left.Origin - _ctrlPrev[0]) / dt, rv = (right.Origin - _ctrlPrev[1]) / dt;
|
||||
_ctrlPrev[0] = left.Origin;
|
||||
_ctrlPrev[1] = right.Origin;
|
||||
_ragdoll.Step(Solver, left, right, lv, rv, _origin.GlobalPosition.Y, dt);
|
||||
// 3. Filtered tracking → play-space correction → True Body → muscles (shared with RagdollSpike).
|
||||
_driver.RebuildRequested |= _rebuild;
|
||||
_rebuild = false;
|
||||
Transform3D o = _origin.GlobalTransform;
|
||||
_driver.Tick(profile, ref o, _camera.Transform, _left.Transform, _right.Transform, _moveVelocity, dt);
|
||||
_origin.GlobalTransform = o;
|
||||
_lastOrigin = _origin.GlobalTransform;
|
||||
_haveLastOrigin = true;
|
||||
}
|
||||
@@ -162,6 +149,14 @@ public partial class PlayerRig : Node
|
||||
}
|
||||
}
|
||||
|
||||
// The body is held back (hips against a table, a wall the head clears): stop the stick from
|
||||
// carrying the view further that way.
|
||||
public static Vector3 HoldBack(Vector3 velocity, Vector3 heldBack)
|
||||
{
|
||||
float into = velocity.Dot(heldBack);
|
||||
return into > 0f ? velocity - heldBack * into : velocity;
|
||||
}
|
||||
|
||||
private static bool IsJump(Transform3D a, Transform3D b) =>
|
||||
a.Origin.DistanceTo(b.Origin) > JumpDistance ||
|
||||
BodyMath.RotationError(b.Basis.GetRotationQuaternion(), a.Basis.GetRotationQuaternion()).Length() > JumpAngle;
|
||||
@@ -170,8 +165,6 @@ public partial class PlayerRig : Node
|
||||
{
|
||||
_ragdoll.TeleportBy(delta);
|
||||
Solver.Shift(delta);
|
||||
_ctrlPrev[0] = delta * _ctrlPrev[0];
|
||||
_ctrlPrev[1] = delta * _ctrlPrev[1];
|
||||
}
|
||||
|
||||
private void Locomote(float dt)
|
||||
@@ -195,6 +188,7 @@ public partial class PlayerRig : Node
|
||||
if (!_ragdoll.Grounded)
|
||||
desired = _moveVelocity; // no air control
|
||||
_moveVelocity = _moveVelocity.MoveToward(desired, MoveAcceleration * dt);
|
||||
_moveVelocity = HoldBack(_moveVelocity, _ragdoll.HeldBack);
|
||||
if (_moveVelocity != Vector3.Zero)
|
||||
_origin.GlobalPosition += _moveVelocity * dt;
|
||||
|
||||
|
||||
Reference in new issue
Block a user