Ground under the body: sphere footprint, clamber by pressure (Nimso), physics objects climbable, arms keep colliding
- Ground = centre ray + stance-wide sphere cast (face normal from a ray inside the contact): planks and lips keep support. - Higher ground is stood on when the hips are over it and the body presses onto it (hands braced, a just-finished press, legs tucked over it, or airborne) - no hips-well-above rule. - Bracing counts heavy/frozen physics objects (>= 15 kg), not what the hand carries. - Knee up: braced + hips held back tucks the legs collider. - Support goal capped at straight legs (tiptoe/over-tall head floated the body). - Arms never get collision exceptions with held objects (they disabled whole crag rocks). - Spike: heavy-box mantle, 15 cm plank, chest-high ledge two hands yes / one hand no. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3e300c7f04
commit
2d986d08ac
2 files changed
+172
-52
No files matched your search
+75
-10
@@ -100,7 +100,10 @@ public partial class RagdollSpike : Node3D
|
||||
_phases.Add(("a table can't be walked over", SetupTableObstacle, _ => _stickVelocity = new Vector3(0f, 0f, -1.5f), 3f, FinishBlockedLow));
|
||||
_phases.Add(("walks up a 0.25 m step", () => SetupObstacle(0.25f, 8f), _ => _stickVelocity = new Vector3(0f, 0f, -1.2f), 3f, FinishStep));
|
||||
_phases.Add(("two-handed mantle onto a 0.9 m ledge (crouch, hands on the edge, stand and press)", () => SetupObstacle(0.9f), _ => TickHumanMantle(both: true), 7f, () => FinishMantle(true)));
|
||||
_phases.Add(("one hand can't mantle", () => SetupObstacle(0.9f), _ => TickHumanMantle(both: false), 7f, () => FinishMantle(false)));
|
||||
_phases.Add(("two-handed mantle onto a chest-high 1.2 m ledge", () => SetupObstacle(1.2f), _ => TickHumanMantle(both: true), 7f, () => FinishMantle(true)));
|
||||
_phases.Add(("one hand can't mantle the 1.2 m ledge (the hips must be lifted)", () => SetupObstacle(1.2f), _ => TickHumanMantle(both: false), 7f, () => FinishMantle(false)));
|
||||
_phases.Add(("mantles onto the playground's heavy box (25 kg physics object, 0.7 m)", SetupCrateLedge, _ => TickHumanMantle(both: true), 8.5f, FinishCrateMantle));
|
||||
_phases.Add(("walks a 15 cm plank swaying the hips without falling off", SetupPlank, TickPlank, 6f, FinishPlank));
|
||||
_phases.Add(("two-handed pull-up on a grabbed bar", () => SetupBarHang(), t => TickPullUp(both: true), 3.5f, () => FinishPullUp(true)));
|
||||
_phases.Add(("one-handed pull-up is weaker", () => SetupBarHang(), t => TickPullUp(both: false), 3.5f, () => FinishPullUp(false)));
|
||||
_phases.Add(("crawls through a 0.6 m tunnel", SetupTunnel, TickCrawl, 7f, FinishCrawl));
|
||||
@@ -531,9 +534,59 @@ public partial class RagdollSpike : Node3D
|
||||
private void SetupObstacle(float height, float depth = 2f)
|
||||
{
|
||||
Rest();
|
||||
_ledgeBox = null;
|
||||
_ledgeTop = height;
|
||||
if (height >= 1f)
|
||||
_origin = new Transform3D(Basis.Identity, new Vector3(0f, 0f, ObstacleFront + 0.4f));
|
||||
_stage.AddChild(MakeStatic(new Vector3(3f, height, depth), new Vector3(0f, height * 0.5f, ObstacleFront - depth * 0.5f), 29));
|
||||
}
|
||||
|
||||
// Playground.HeavyBox (25 kg, 0.7 m cube) as the ledge, same human mantle as onto the static ledge.
|
||||
private void SetupCrateLedge()
|
||||
{
|
||||
Rest();
|
||||
_ledgeBox = MakeBox(Vector3.One * 0.7f, 25f, new Vector3(0f, 0.35f, ObstacleFront - 0.35f));
|
||||
_ledgeTop = 0.7f;
|
||||
}
|
||||
|
||||
private RigidBody3D _ledgeBox;
|
||||
private float _ledgeTop = 0.9f;
|
||||
|
||||
private bool FinishCrateMantle()
|
||||
{
|
||||
GD.Print($"RAGDOLL: crate mantle: pelvis rose up to {_maxPelvisRise:F3} m, feet y {_ragdoll.GroundY:F3}, origin y {_origin.Origin.Y:F3}, snaps {NewSnaps}");
|
||||
_maxPelvisRise = 0f;
|
||||
return _finite && NewSnaps == 0 && _ragdoll.GroundY > 0.6f && _origin.Origin.Y > 0.55f;
|
||||
}
|
||||
|
||||
private const float PlankY = 0.3f;
|
||||
private float _plankMinFoot;
|
||||
|
||||
private void SetupPlank()
|
||||
{
|
||||
Rest();
|
||||
_origin = new Transform3D(Basis.Identity, new Vector3(0f, PlankY, 0f));
|
||||
_stage.AddChild(MakeStatic(new Vector3(0.15f, PlankY, 8f), new Vector3(0f, PlankY * 0.5f, -3f), 29));
|
||||
_plankMinFoot = float.MaxValue;
|
||||
}
|
||||
|
||||
// Walk along it with the head (and so the hips) swaying ±9 cm side to side.
|
||||
private void TickPlank(float dt)
|
||||
{
|
||||
float sway = _t > 1f ? 0.09f * Mathf.Sin(Mathf.Tau * 0.7f * (_t - 1f)) : 0f;
|
||||
_headLocal = new Transform3D(Basis.Identity, new Vector3(sway, EyeHeight, 0f));
|
||||
_stickVelocity = _t > 1f && _t < 5f ? new Vector3(0f, 0f, -0.6f) : Vector3.Zero;
|
||||
_measureFrom = float.MaxValue;
|
||||
if (_ragdoll.Built && !_needBuild && _t > 0.5f)
|
||||
_plankMinFoot = Mathf.Min(_plankMinFoot, _ragdoll.Grounded ? _ragdoll.GroundY : -1f);
|
||||
}
|
||||
|
||||
private bool FinishPlank()
|
||||
{
|
||||
GD.Print($"RAGDOLL: plank: lowest supported foot level {_plankMinFoot:F3} (plank top {PlankY}), pelvis {_ragdoll.Pelvis.GlobalPosition}, eye error {_ragdoll.Eye.DistanceTo(Camera.Origin):F3}, snaps {NewSnaps}");
|
||||
return _finite && NewSnaps == 0 && _plankMinFoot > PlankY - 0.03f && _ragdoll.Pelvis.GlobalPosition.Z < -1.8f;
|
||||
}
|
||||
|
||||
private void SetupTableObstacle()
|
||||
{
|
||||
Rest();
|
||||
@@ -562,7 +615,7 @@ public partial class RagdollSpike : Node3D
|
||||
private bool FinishMantle(bool both)
|
||||
{
|
||||
GD.Print($"RAGDOLL: mantle ({(both ? "two hands" : "one hand")}): pelvis rose up to {_maxPelvisRise:F3} m, feet y {_ragdoll.GroundY:F3}, origin y {_origin.Origin.Y:F3}, snaps {NewSnaps}");
|
||||
bool onTop = _ragdoll.GroundY > 0.85f && _origin.Origin.Y > 0.8f;
|
||||
bool onTop = _ragdoll.GroundY > _ledgeTop - 0.05f && _origin.Origin.Y > _ledgeTop - 0.1f;
|
||||
_lastRise = _maxPelvisRise;
|
||||
_maxPelvisRise = 0f;
|
||||
return _finite && NewSnaps == 0 && (both ? onTop : !onTop); // standing tall also lifts the hips; one hand never gets you up
|
||||
@@ -949,20 +1002,32 @@ public partial class RagdollSpike : Node3D
|
||||
private void TickHumanMantle(bool both)
|
||||
{
|
||||
float t = _t;
|
||||
_stickVelocity = t < 1f || (t > 4.5f && t < 5.5f) ? new Vector3(0f, 0f, -0.8f) : Vector3.Zero; // stop before the ledge's far end
|
||||
float crouch = Mathf.SmoothStep(0f, 1f, Mathf.Clamp((t - 1f) / 0.8f, 0f, 1f));
|
||||
// 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;
|
||||
// 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));
|
||||
float eye = EyeHeight - 0.25f * crouch + 0.35f * rise;
|
||||
float lean = 0.25f * rise;
|
||||
float lean = (_ledgeTop < 1f ? 0.25f : 0.55f) * rise; // over a chest-high edge you put your head well over it
|
||||
_headLocal = new Transform3D(new Basis(Vector3.Right, -0.3f * crouch), new Vector3(0f, eye, -lean));
|
||||
float handZ = ObstacleFront - 0.08f - _origin.Origin.Z;
|
||||
float handY = t < 1f ? 1.0f : Mathf.Lerp(0.95f, 0.55f, rise) - 0.05f * crouch;
|
||||
// Hands on the top just past the near edge (of the box itself when it's a movable one).
|
||||
float front = _ledgeBox != null ? _ledgeBox.GlobalPosition.Z + 0.35f : ObstacleFront;
|
||||
float handZ = front - 0.08f - _origin.Origin.Z;
|
||||
float handY = t < 1f ? 1.0f : Mathf.Lerp(_ledgeTop + 0.05f, _ledgeTop - 0.35f, rise) - 0.05f * crouch - _origin.Origin.Y;
|
||||
Basis down = Aim(Vector3.Down + Vector3.Forward * 0.3f);
|
||||
_leftLocal = both ? new Transform3D(down, new Vector3(-0.2f, handY, handZ)) : new Transform3D(Basis.Identity, new Vector3(-0.2f, 1.0f, -0.3f));
|
||||
_rightLocal = new Transform3D(down, new Vector3(0.2f, handY, handZ));
|
||||
// Walking up, the hands are down at the sides; then they go up over the edge onto the top.
|
||||
float reach = Mathf.Clamp((t - 0.8f) / 0.4f, 0f, 1f);
|
||||
Vector3 rest = new(0.2f, 1.0f, -0.3f), onTop = new(0.2f, Mathf.Max(handY, _ledgeTop + 0.08f - _origin.Origin.Y), handZ);
|
||||
Vector3 r = reach < 1f ? rest.Lerp(new Vector3(0.2f, _ledgeTop + 0.12f - _origin.Origin.Y, -0.3f), reach) : new Vector3(0.2f, handY, handZ);
|
||||
if (reach >= 1f && t < 1.4f)
|
||||
r = onTop;
|
||||
_leftLocal = both ? new Transform3D(down, new Vector3(-r.X, r.Y, r.Z)) : new Transform3D(Basis.Identity, new Vector3(-0.2f, 1.0f, -0.3f));
|
||||
_rightLocal = new Transform3D(down, r);
|
||||
if (_ragdoll.Built && !_needBuild)
|
||||
_maxPelvisRise = Mathf.Max(_maxPelvisRise, _ragdoll.Pelvis.GlobalPosition.Y - 0.99f);
|
||||
if (t > 4.5f)
|
||||
if (OS.HasEnvironment("MANTLETRACE") && _ragdoll.Built && ((int)(t * 144f)) % 14 == 0)
|
||||
GD.Print($"MT t {t:F2} pelvis {_ragdoll.Pelvis.GlobalPosition} v {_ragdoll.Pelvis.LinearVelocity.Y:F2} o {_origin.Origin.Y:F2} j {_ragdoll.Jumping} braced {_ragdoll.Braced} lifted {_ragdoll.Lifted} legs {_ragdoll.LegsSolid} g {_ragdoll.Grounded} foot {_ragdoll.GroundY:F2} hands {_ragdoll.Hand(0).GlobalPosition.Y:F2}/{_ragdoll.Hand(1).GlobalPosition.Y:F2} {(_stage.GetChildCount() > 0 && _stage.GetChild(0) is RigidBody3D rb ? rb.GlobalPosition.ToString() : "")}");
|
||||
if (t > (_ledgeTop < 1f ? 4.5f : 5.5f))
|
||||
{
|
||||
_leftLocal = new Transform3D(Basis.Identity, new Vector3(-0.2f, 1.0f, -0.3f));
|
||||
_rightLocal = new Transform3D(Basis.Identity, new Vector3(0.2f, 1.0f, -0.3f));
|
||||
|
||||
Reference in new issue
Block a user