Code/PlayerControllerPlus/Modes/Swim.cs
using System.Linq;
namespace Sandbox.MovementPlus;
public class MoveModeSwimPlus : MoveModePlus
{
public float WaterLevel { get; private set; }
public override void UpdateRigidBody( Rigidbody body )
{
body.Gravity = false;
body.LinearDamping = 3.3f;
body.AngularDamping = 1f;
}
public override int Score( PlayerControllerPlus controller )
{
if ( WaterLevel > controller.SwimLevel ) return controller.SwimPriority;
return -100;
}
public override void OnModeBegin()
{
Controller.IsSwimming = true;
}
public override void OnModeEnd( MoveModePlus next )
{
Controller.IsSwimming = false;
if ( Input.Down( "Jump" ) )
{
Controller.Jump( Vector3.Up * 300 );
}
}
public override void FixedUpdate()
{
UpdateWaterLevel();
}
void UpdateWaterLevel()
{
if ( Controller?.Body == null )
return;
var wt = Controller.WorldTransform;
Vector3 head = wt.PointToWorld( new Vector3( 0, 0, Controller.CurrentHeight ) );
Vector3 foot = wt.Position;
float waterLevel = 0;
foreach ( var touch in Controller.Body.Touching )
{
if ( !touch.Tags.Contains( "water" ) ) continue;
var waterSurface = touch.FindClosestPoint( head );
var level = Vector3.InverseLerp( waterSurface, foot, head, true );
level = (level * 100).CeilToInt() / 100.0f;
if ( level > waterLevel )
waterLevel = level;
}
if ( WaterLevel != waterLevel )
{
WaterLevel = waterLevel;
}
}
public override Vector3 UpdateMove( Rotation eyes, Vector3 input )
{
if ( Input.Down( "jump" ) )
{
input += Vector3.Up;
}
return base.UpdateMove( eyes, input );
}
}