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
@@ -11,7 +11,7 @@ public partial class PropGrabber : Node
|
||||
private const float BreakTime = 0.25f;
|
||||
private const float BreakDistanceBoth = 0.4f;
|
||||
private const float GripRipDistance = 0.8f;
|
||||
private const float WorldGrabRadius = 0.05f; // palm sphere for grabbing static world (ledges, bars, holds)
|
||||
private const float WorldGrabRadius = 0.07f; // palm sphere for grabbing static world (ledges, bars, holds)
|
||||
public const string NoGrabGroup = "no_grab"; // static bodies that can't be grabbed (the floor)
|
||||
|
||||
private static PropGrabber _instance;
|
||||
@@ -197,7 +197,7 @@ public partial class PropGrabber : Node
|
||||
_breakTimer[hand] = 0f;
|
||||
}
|
||||
|
||||
private static Vector3 PalmPoint(RigidBody3D handBody, int hand) =>
|
||||
public static Vector3 PalmPoint(RigidBody3D handBody, int hand) =>
|
||||
handBody.GlobalPosition + handBody.GlobalTransform.Basis * new Vector3(PalmOffset(hand), 0f, 0f);
|
||||
|
||||
private static float PalmOffset(int hand) => hand == 0 ? PalmGrabOffset : -PalmGrabOffset;
|
||||
@@ -214,11 +214,12 @@ public partial class PropGrabber : Node
|
||||
nearest = NearestProp(handBody.GlobalPosition, CenterGrabRadius);
|
||||
if (nearest != null)
|
||||
return nearest;
|
||||
return WorldUnderPalm(palm, handBody.GetWorld3D());
|
||||
return WorldUnderPalm(palm, handBody.GetWorld3D()) ?? WorldUnderPalm(handBody.GlobalPosition, handBody.GetWorld3D());
|
||||
}
|
||||
|
||||
// Climbing: any static body touching the palm (except the "no_grab" group) can be held.
|
||||
private static StaticBody3D WorldUnderPalm(Vector3 palm, World3D world)
|
||||
// Climbing: any static body near the palm (except the "no_grab" group) can be held.
|
||||
// NOTE (Box3D wrapper): shape-query results carry a null "collider" — resolve "collider_id".
|
||||
public static StaticBody3D WorldUnderPalm(Vector3 palm, World3D world)
|
||||
{
|
||||
PhysicsShapeQueryParameters3D query = new()
|
||||
{
|
||||
@@ -228,7 +229,7 @@ public partial class PropGrabber : Node
|
||||
};
|
||||
foreach (Godot.Collections.Dictionary hit in world.DirectSpaceState.IntersectShape(query, 8))
|
||||
{
|
||||
if (hit["collider"].AsGodotObject() is StaticBody3D body && !body.IsInGroup(NoGrabGroup))
|
||||
if (GodotObject.InstanceFromId((ulong)hit["collider_id"]) is StaticBody3D body && !body.IsInGroup(NoGrabGroup))
|
||||
return body;
|
||||
}
|
||||
return null;
|
||||
|
||||
Reference in new issue
Block a user