PlayerControllerPlus/Modes/MoveModePlus.cs
using System;
namespace Sandbox.MovementPlus;
/// <summary>
/// A move mode for this character. Not a Component — owned and managed by PlayerControllerPlus.
/// </summary>
public abstract partial class MoveModePlus
{
public virtual bool AllowGrounding => false;
public virtual bool AllowFalling => false;
public virtual bool UseLateralAirControl => false;
public PlayerControllerPlus Controller { get; set; }
public virtual int Score( PlayerControllerPlus controller ) => 0;
public virtual void PrePhysicsStep() { }
public virtual void PostPhysicsStep() { }
public virtual void FixedUpdate() { }
public virtual void UpdateRigidBody( Rigidbody body )
{
bool wantsGravity = false;
if ( !Controller.IsOnGround ) wantsGravity = true;
if ( Controller.Velocity.Length > 1 ) wantsGravity = true;
if ( Controller.GroundVelocity.Length > 1 ) wantsGravity = true;
if ( Controller.GroundIsDynamic ) wantsGravity = true;
body.Gravity = wantsGravity;
bool wantsbrakes = Controller.IsOnGround && Controller.WishVelocity.Length < 1 && Controller.GroundVelocity.Length < 1;
body.LinearDamping = wantsbrakes ? (10.0f * Controller.BrakePower) : Controller.AirFriction;
body.AngularDamping = 1f;
}
public virtual void AddVelocity()
{
var body = Controller.Body;
var wish = Controller.WishVelocity;
if ( wish.IsNearZeroLength ) return;
var groundFriction = 0.25f + Controller.GroundFriction * 10;
var groundVelocity = Controller.GroundVelocity;
var z = body.Velocity.z;
var velocity = (body.Velocity - Controller.GroundVelocity);
var speed = velocity.Length;
var maxSpeed = MathF.Max( wish.Length, speed );
if ( Controller.IsOnGround )
{
var amount = 1 * groundFriction;
velocity = velocity.AddClamped( wish * amount, wish.Length * amount );
}
else
{
if ( UseLateralAirControl && Controller.ExtendedFeaturesEnabled )
{
var lateralWish = wish.WithZ( 0 );
if ( !lateralWish.IsNearZeroLength )
{
var eyes = Controller.EyeAngles.ToRotation();
var forward = eyes.Forward.WithZ( 0 ).Normal;
var right = eyes.Right.WithZ( 0 ).Normal;
var wishForward = lateralWish.Dot( forward );
var wishRight = lateralWish.Dot( right );
var forwardControl = wishForward >= 0 ? Controller.AirControlForward : Controller.AirControlBackward;
var scaledWish = forward * wishForward * MathX.Lerp( 0.05f, 1f, forwardControl )
+ right * wishRight * MathX.Lerp( 0.05f, 1f, Controller.AirControlLateral );
var lateralVel = velocity.WithZ( 0 );
lateralVel = lateralVel.AddClamped( scaledWish, scaledWish.Length );
velocity = lateralVel.WithZ( velocity.z );
}
}
else
{
var amount = 0.05f;
velocity = velocity.AddClamped( wish * amount, wish.Length );
}
}
if ( UseLateralAirControl && Controller.ExtendedFeaturesEnabled && !Controller.IsOnGround )
{
var lateral = velocity.WithZ( 0 );
var lateralMax = MathF.Max( wish.WithZ( 0 ).Length, speed );
if ( lateral.Length > lateralMax )
lateral = lateral.Normal * lateralMax;
velocity = lateral.WithZ( velocity.z );
}
else
{
if ( velocity.Length > maxSpeed )
velocity = velocity.Normal * maxSpeed;
}
velocity += groundVelocity;
if ( Controller.IsOnGround )
{
velocity.z = z;
}
body.Velocity = velocity;
}
public virtual void OnModeBegin() { }
public virtual void OnModeEnd( MoveModePlus next ) { }
protected void TrySteppingUp( float maxDistance )
{
Controller.TryStep( maxDistance );
}
protected void StickToGround( float maxDistance )
{
Controller.Reground( maxDistance );
}
public virtual bool IsStandableSurace( in SceneTraceResult result )
{
return false;
}
public virtual bool IsStandableSurface( in SceneTraceResult result )
{
return IsStandableSurace( result );
}
Vector3.SmoothDamped smoothedMovement;
public virtual Vector3 UpdateMove( Rotation eyes, Vector3 input )
{
input = input.ClampLength( 1 );
var direction = eyes * input;
bool run = Input.Down( Controller.AltMoveButton );
if ( Controller.RunByDefault ) run = !run;
var velocity = run ? Controller.RunSpeed : Controller.WalkSpeed;
if ( !run && Controller.ExtendedFeaturesEnabled && Controller.EnableSlowWalk && Input.Down( Controller.SlowWalkButton ) )
velocity = Controller.SlowWalkSpeed;
if ( Controller.IsDucking ) velocity = Controller.DuckedSpeed;
if ( direction.IsNearlyZero( 0.1f ) )
{
direction = 0;
}
else
{
smoothedMovement.Current = direction.Normal * smoothedMovement.Current.Length;
}
if ( Controller.ExtendedFeaturesEnabled && Controller._landingVelocity.HasValue )
{
smoothedMovement.Current = Controller._landingVelocity.Value;
Controller._landingVelocity = null;
}
else
{
Controller._landingVelocity = null;
}
smoothedMovement.Target = direction * velocity;
smoothedMovement.SmoothTime = smoothedMovement.Target.Length < smoothedMovement.Current.Length ? Controller.DeaccelerationTime : Controller.AccelerationTime;
smoothedMovement.Update( Time.Delta );
if ( smoothedMovement.Current.IsNearlyZero( 0.01f ) )
{
smoothedMovement.Current = 0;
}
return smoothedMovement.Current;
}
}