ground sliding under stuff

This commit is contained in:
2026-01-14 15:26:41 +01:00
parent c6559d593a
commit ca77579168
7 changed files with 263 additions and 265 deletions

View File

@@ -40,17 +40,13 @@ public partial class CapsuleCollider : CollisionShape3D
return Mathf.IsEqualApprox(_shape.Height, CapsuleCrouchHeight);
}
public void Crouch(float delta, float crouchTransitionSpeed)
public void Crouch()
{
_shape.Height -= delta * crouchTransitionSpeed;
_shape.Height = Mathf.Clamp(_shape.Height, CapsuleCrouchHeight, CapsuleDefaultHeight);
_shape.Height = CapsuleCrouchHeight;
}
public void UndoCrouching(float delta, float crouchTransitionSpeed)
public void Uncrouch()
{
_shape.Height += delta * crouchTransitionSpeed;
_shape.Height = Mathf.Clamp(_shape.Height, CapsuleCrouchHeight, CapsuleDefaultHeight);
_shape.Height = CapsuleDefaultHeight;
}
}

View File

@@ -37,7 +37,8 @@ public partial class PlayerController : CharacterBody3D
public StairsSystem StairsSystem;
public MantleSystem MantleSystem;
public DashSystem DashSystem;
public CapsuleCollider CapsuleCollider;
public CollisionShape3D StandingCollider;
public CollisionShape3D SlideCollider;
public Node3D WeaponRoot;
public WeaponSystem WeaponSystem;
public WallHugSystem WallHugSystem;
@@ -49,6 +50,7 @@ public partial class PlayerController : CharacterBody3D
public CylinderMesh DashIndicatorMeshCylinder;
public RayCast3D WallRunSnapper;
public ShapeCast3D GroundDetector;
public ShapeCast3D CeilingDetector;
public RayCast3D DirectGroundDetector;
// Inspector stuff
@@ -330,12 +332,14 @@ public partial class PlayerController : CharacterBody3D
WeaponRoot = GetNode<Node3D>("WeaponRoot");
WeaponSystem = GetNode<WeaponSystem>("WeaponRoot/WeaponSystem");
MantleSystem = GetNode<MantleSystem>("HeadSystem/MantleSystem");
CapsuleCollider = GetNode<CapsuleCollider>("CapsuleCollider");
StandingCollider = GetNode<CollisionShape3D>("StandingCollider");
SlideCollider = GetNode<CollisionShape3D>("SlideCollider");
DashSystem = GetNode<DashSystem>("DashSystem");
StairsSystem = GetNode<StairsSystem>("StairsSystem");
WallHugSystem = GetNode<WallHugSystem>("WallHugSystem");
WallRunSnapper = GetNode<RayCast3D>("%WallRunSnapper");
GroundDetector = GetNode<ShapeCast3D>("GroundDetector");
CeilingDetector = GetNode<ShapeCast3D>("CeilingDetector");
DirectGroundDetector = GetNode<RayCast3D>("DirectGroundDetector");
RayCast3D stairsBelowRayCast3D = GetNode<RayCast3D>("StairsBelowRayCast3D");
RayCast3D stairsAheadRayCast3D = GetNode<RayCast3D>("StairsAheadRayCast3D");
@@ -346,7 +350,7 @@ public partial class PlayerController : CharacterBody3D
"HeadCollisionDetectors/HeadCollisionDetector" + i);
}
var playerShape = CapsuleCollider.GetShape() as CapsuleShape3D;
var playerShape = StandingCollider.GetShape() as CapsuleShape3D;
_playerHeight = playerShape!.Height;
_playerRadius = playerShape.Radius;
@@ -598,9 +602,9 @@ public partial class PlayerController : CharacterBody3D
StairsSystem.UpStairsCheckParams upStairsCheckParams = new StairsSystem.UpStairsCheckParams
{
IsOnFloorCustom = isOnFloorCustom(),
IsCapsuleHeightLessThanNormal = CapsuleCollider.IsCapsuleHeightLessThanNormal(),
IsCapsuleHeightLessThanNormal = false,
CurrentSpeedGreaterThanWalkSpeed = false,
IsCrouchingHeight = CapsuleCollider.IsCrouchingHeight(),
IsCrouchingHeight = false,
Delta = delta,
FloorMaxAngle = FloorMaxAngle,
GlobalPositionFromDriver = GlobalPosition,
@@ -621,10 +625,10 @@ public partial class PlayerController : CharacterBody3D
StairsSystem.DownStairsCheckParams downStairsCheckParams = new StairsSystem.DownStairsCheckParams
{
IsOnFloor = IsOnFloor(),
IsCrouchingHeight = CapsuleCollider.IsCrouchingHeight(),
IsCrouchingHeight = false,
LastFrameWasOnFloor = _lastFrameWasOnFloor,
CapsuleDefaultHeight = CapsuleCollider.GetDefaultHeight(),
CurrentCapsuleHeight = CapsuleCollider.GetCurrentHeight(),
CapsuleDefaultHeight = _playerHeight,
CurrentCapsuleHeight = _playerHeight,
FloorMaxAngle = FloorMaxAngle,
VelocityY = Velocity.Y,
GlobalTransformFromDriver = GlobalTransform,
@@ -642,9 +646,9 @@ public partial class PlayerController : CharacterBody3D
StairsSystem.SlideCameraParams slideCameraParams = new StairsSystem.SlideCameraParams
{
IsCapsuleHeightLessThanNormal = CapsuleCollider.IsCapsuleHeightLessThanNormal(),
IsCapsuleHeightLessThanNormal = false,
CurrentSpeedGreaterThanWalkSpeed = false,
BetweenCrouchingAndNormalHeight = CapsuleCollider.IsBetweenCrouchingAndNormalHeight(),
BetweenCrouchingAndNormalHeight = false,
Delta = delta
};
StairsSystem.SlideCameraSmoothBackToOrigin(slideCameraParams);
@@ -812,7 +816,7 @@ public partial class PlayerController : CharacterBody3D
FieldOfView.FovParameters fovParams = new FieldOfView.FovParameters
{
IsCrouchingHeight = CapsuleCollider.IsCrouchingHeight(),
IsCrouchingHeight = false,
Delta = delta,
SprintSpeed = WalkSpeed,
Velocity = Velocity,
@@ -943,7 +947,8 @@ public partial class PlayerController : CharacterBody3D
if (!_canDash)
{
_playerState.SendEvent("dash_finished");
var dashEvent = isOnFloorCustom() ? "grounded" : "dash_finished";
_playerState.SendEvent(dashEvent);
return;
}
_canDash = false;
@@ -961,7 +966,8 @@ public partial class PlayerController : CharacterBody3D
public void SimpleDashFinished()
{
_playerState.SendEvent("dash_finished");
var dashEvent = isOnFloorCustom() ? "grounded" : "dash_finished";
_playerState.SendEvent(dashEvent);
}
///////////////////////////
@@ -1256,13 +1262,18 @@ public partial class PlayerController : CharacterBody3D
///////////////////////////
// Slide management //
///////////////////////////
private bool _isSlideInputDown = false;
public void OnInputSlideStarted()
{
_isSlideInputDown = true;
_playerState.SendEvent("slide");
}
public void OnInputSlideEnded()
{
_playerState.SendEvent("slide_released");
_isSlideInputDown = false;
if (_airGliding.Active || CanStandUpFromSlide())
_playerState.SendEvent("slide_released");
}
public record SlopeRecord(
@@ -1288,19 +1299,49 @@ public partial class PlayerController : CharacterBody3D
var direction = normal.Cross(vectorInPlane).Normalized();
return new SlopeRecord(position, normal, direction, angle);
}
public void SetupSlideCollision()
{
StandingCollider.Disabled = true;
SlideCollider.Disabled = false;
CeilingDetector.Enabled = true;
}
public void SetupStandingCollision()
{
StandingCollider.Disabled = false;
SlideCollider.Disabled = true;
CeilingDetector.Enabled = false;
}
public void SlideStarted()
{
_targetSpeed = Velocity.Length();
SetupSlideCollision();
}
public bool CanStandUpFromSlide()
{
return !CeilingDetector.IsColliding();
}
public bool CanCancelSlide()
{
return DirectGroundDetector.IsColliding()
&& Velocity.Length() < WalkSpeed / 2f
&& CanStandUpFromSlide();
}
public void SlideOnGround(float delta)
{
// Store current velocity
var currentVelocity = Velocity.Length();
var finalSpeed = currentVelocity * FlatGroundSlideSpeedLossRate;
// We prevent automatically losing speed when sliding under something
var speedLossRate = CanStandUpFromSlide() ? FlatGroundSlideSpeedLossRate : 1.0f;
// We force a minimum of speed when sliding under something
var minimumVelocity = CanStandUpFromSlide() ? 0f : WalkSpeed;
var finalSpeed = Mathf.Max(currentVelocity * speedLossRate, minimumVelocity);
// Going down slope?
var (position, normal, slopeDirection, slopeAngleRadians) = GetSlope();
// Going down a slope?
var (position, _, slopeDirection, slopeAngleRadians) = GetSlope();
// Change velocity based on Input
var horizontalVelocity = ComputeHVelocity(delta, AccelerationGroundSlide, DecelerationGroundSlide);
@@ -1324,9 +1365,10 @@ public partial class PlayerController : CharacterBody3D
// redirectedVelocity = new Vector3(redirectedVelocity.X, redirectedVVelocity, redirectedVelocity.Z);
// Moving upslope and not enough speed
if (velocitySlopeAlignment < 0 && DirectGroundDetector.IsColliding() && Velocity.Length() < WalkSpeed / 2f) _playerState.SendEvent("slide_canceled");
if (velocitySlopeAlignment < 0 && CanCancelSlide())
_playerState.SendEvent("slide_canceled");
}
else if (DirectGroundDetector.IsColliding() && Velocity.Length() < WalkSpeed / 2f)
else if (CanCancelSlide())
{
// Moving on flat ground and not enough speed
_playerState.SendEvent("slide_canceled");
@@ -1340,9 +1382,9 @@ public partial class PlayerController : CharacterBody3D
GlobalPosition = new Vector3(GlobalPosition.X, position.Y, GlobalPosition.Z);
}
}
public void OnSlideCanceled()
{
SetupStandingCollision();
_targetSpeed = WalkSpeed;
}
public void HandleSlideCanceled(float delta)
@@ -1352,9 +1394,10 @@ public partial class PlayerController : CharacterBody3D
public void HandleGroundSlide(float delta)
{
SlideOnGround(delta);
if (MantleSystem.IsMantlePossible && IsPlayerInputtingForward()) _playerState.SendEvent("mantle");
if (!isOnFloorCustom() && !DirectGroundDetector.IsColliding())
_playerState.SendEvent("start_falling");
if (!isOnFloorCustom() && !DirectGroundDetector.IsColliding()) _playerState.SendEvent("start_falling");
if (CanStandUpFromSlide() && !_isSlideInputDown) _playerState.SendEvent("slide_released");
}
public void GlideInAir(float delta)
@@ -1386,13 +1429,14 @@ public partial class PlayerController : CharacterBody3D
public void HandleAirGlide(float delta)
{
GlideInAir(delta);
if (MantleSystem.IsMantlePossible && IsPlayerInputtingForward()) _playerState.SendEvent("mantle");
if (MantleSystem.IsMantlePossible && IsPlayerInputtingForward()) _playerState.SendEvent("mantle");
if (isOnFloorCustom())
_playerState.SendEvent("grounded");
}
public void SlideEnded()
{
SetupStandingCollision();
_targetSpeed = WalkSpeed;
}
@@ -1572,7 +1616,8 @@ public partial class PlayerController : CharacterBody3D
}
public void AimedDashTweenEnded()
{
_playerState.SendEvent("dash_finished");
var dashEvent = isOnFloorCustom() ? "grounded" : "dash_finished";
_playerState.SendEvent(dashEvent);
}
public void OnAimedDashFinished()
{