Body step 2.4: landing, movable ground, playground fixes
- legs brake landings at 4.5 g; vertical support is a rate-limited servo (no launch when stepping onto a mantled ledge) - ground control pushes back on movable ground (seesaw tips under the player) - playground hinges use absolute paths (joint paths resolve from the joint) - big props grabbable via surface query; Reset props keeps playground pieces - spike: landing, seesaw, playground joints/grab, person-like wall climb Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b5f598aae9
commit
0b8f2131c1
6 files changed
+208
-42
No files matched your search
@@ -52,10 +52,11 @@ public partial class PlayerRagdoll : Node3D
|
||||
// Ground control (world-space support on the pelvis, only while grounded).
|
||||
public const float GroundFrequency = 4f; // Hz
|
||||
public const float GroundDamping = 1f;
|
||||
public const float LegStrength = 2f; // max support, × body weight
|
||||
public const float LegStrength = 4.5f; // max support, × body weight (real legs brake a landing at 3–5 g; 2× sank ~0.4 m)
|
||||
public const float GroundFriction = 1f; // horizontal force ≤ this × support
|
||||
public const float GroundProbeExtra = 0.3f; // ground counts while within hip height + this
|
||||
public const float MaxStepHeight = 0.35f;
|
||||
public const float MaxRiseSpeed = 1.2f; // m/s the legs lift the body toward its stance
|
||||
public const float MaxSlopeDegrees = 35f; // steeper ground gives no support (Nimso: "slopes beyond an angle can't be run up") // higher ground under the hips isn't stood on unless the body got up there
|
||||
public const float BracedAirControl = 150f; // N of horizontal hip carry while airborne but braced on the hands (mantling)
|
||||
public const float CrawlCarry = 300f;
|
||||
@@ -166,6 +167,8 @@ public partial class PlayerRagdoll : Node3D
|
||||
private readonly Vector3[] _girdle = new Vector3[2]; // True Body shoulder offset, chest frame
|
||||
private float _footY;
|
||||
private float _supportGoalY;
|
||||
private RigidBody3D _groundBody;
|
||||
private Vector3 _groundPoint;
|
||||
private float _tuckFree, _dt;
|
||||
private PhysicsShapeQueryParameters3D _legsQuery;
|
||||
|
||||
@@ -752,10 +755,13 @@ public partial class PlayerRagdoll : Node3D
|
||||
Godot.Collections.Dictionary hit = GetWorld3D().DirectSpaceState.IntersectRay(query);
|
||||
bool wasGrounded = Grounded;
|
||||
Grounded = false;
|
||||
_groundBody = null;
|
||||
if (hit.Count > 0)
|
||||
{
|
||||
Vector3 point = (Vector3)hit["position"];
|
||||
Vector3 normal = (Vector3)hit["normal"];
|
||||
_groundBody = GodotObject.InstanceFromId((ulong)hit["collider_id"]) as RigidBody3D; // Box3D: "collider" is null
|
||||
_groundPoint = point;
|
||||
bool inReach = pos.Y - point.Y < hipAboveFloor + GroundProbeExtra;
|
||||
bool steep = normal.Y <= Mathf.Cos(Mathf.DegToRad(MaxSlopeDegrees));
|
||||
if (inReach && steep && wasGrounded && point.Y <= _footY + MaxStepHeight)
|
||||
@@ -806,7 +812,12 @@ public partial class PlayerRagdoll : Node3D
|
||||
float w = Mathf.Tau * GroundFrequency;
|
||||
Vector3 accel = (goal - pos) * (w * w) + (targetVelocity - Pelvis.LinearVelocity) * (2f * GroundDamping * w);
|
||||
Vector3 force = accel * BodyMass;
|
||||
float support = Mathf.Clamp(force.Y + weight, 0f, LegStrength * weight);
|
||||
// Vertical as a rate-limited velocity servo: full leg strength brakes a landing, but
|
||||
// the legs raise the body at most MaxRiseSpeed — they can push, not pull, so a hard push
|
||||
// toward a higher stance (onto a ledge) would otherwise overshoot into a jump.
|
||||
float riseVelocity = Mathf.Clamp((goal.Y - pos.Y) * w, -3f, MaxRiseSpeed) + targetVelocity.Y;
|
||||
float verticalAccel = (riseVelocity - Pelvis.LinearVelocity.Y) * (2f * GroundDamping * w);
|
||||
float support = Mathf.Clamp(verticalAccel * BodyMass + weight, 0f, LegStrength * weight);
|
||||
float carry = Mathf.Max(GroundFriction * support, _legsSolid ? 0f : CrawlCarry);
|
||||
// Hips held back by an obstacle: lean on it, don't bulldoze — full leg force tipped the
|
||||
// body over knee-high boxes and steep slopes (and the riding view tipped with it).
|
||||
@@ -814,6 +825,10 @@ public partial class PlayerRagdoll : Node3D
|
||||
carry = Mathf.Min(carry, BlockedPush);
|
||||
Vector3 horizontal = new Vector3(force.X, 0f, force.Z).LimitLength(carry);
|
||||
Pelvis.ApplyCentralForce(horizontal + Vector3.Up * support);
|
||||
// Newton's third law: standing on something movable (seesaw, plank, crate) pushes it
|
||||
// down — the feet aren't physical, so the reaction is applied where the ground ray hit.
|
||||
if (_groundBody != null && IsInstanceValid(_groundBody))
|
||||
_groundBody.ApplyForce(-(horizontal + Vector3.Up * support), _groundPoint - _groundBody.GlobalPosition);
|
||||
}
|
||||
else if (Braced)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user