Code/Vehicle/VehicleController.Brakes.cs
using Sandbox;
namespace Bugges.VehicleController;
partial class VehicleController : Component
{
private const string BRAKES = "Brakes";
[Order( -6 )]
[Property( Title = "Strength" ), Feature( BRAKES )]
private float Brake_Strength { get; set; } = 40.0f;
[Property, Feature( BRAKES )]
private float Brakes_RollingFriction { get; set; } = 4.0f;
[Property( Title = "Max Grip" ), Feature( BRAKES )]
private float Brakes_SlidingFriction { get; set; } = 0.7f;
private void ApplyBrake( Wheel wheel, SceneTraceResult trace )
{
if ( !wheel.IsBrake ) return;
bool shouldApplyBrakes = BrakeInput || Gear_Current == Gears.Park;
wheel.IsBraking = shouldApplyBrakes;
if ( !shouldApplyBrakes ) return;
if ( !trace.Hit ) return;
Vector3 contactPoint = GetWheelContactPoint( wheel, trace );
Vector3 brakeDir = wheel.Forward;
Vector3 tireWorldVel = Body.GetVelocityAtPoint( contactPoint );
float brakeVel = Vector3.Dot( brakeDir, tireWorldVel );
float desiredVelChange = -brakeVel * wheel.Grip;
float desiredAccel = desiredVelChange / Time.Delta;
Body.ApplyForceAt( contactPoint, Brake_Strength * desiredAccel * brakeDir );
}
public bool IsBraking()
{
if ( BrakeInput ) return true;
if ( Gear_Current == Gears.Park ) return true;
return false;
}
private void ApplyRollingFriction( Wheel wheel, SceneTraceResult trace )
{
if ( !trace.Hit ) return;
float absAccelerateInput = float.Abs( AccelerateInput );
if ( absAccelerateInput > 0.1f ) return;
Vector3 contactPoint = GetWheelContactPoint( wheel, trace );
Vector3 frictionDir = wheel.Forward;
Vector3 tireWorldVel = Body.GetVelocityAtPoint( contactPoint );
float frictionVel = Vector3.Dot( frictionDir, tireWorldVel );
float desiredVelChange = -frictionVel * wheel.Grip;
float desiredAccel = desiredVelChange / Time.Delta;
Body.ApplyForceAt( contactPoint, Brakes_RollingFriction * desiredAccel * frictionDir );
}
private void ApplyAntiSlip( Wheel wheel, SceneTraceResult trace )
{
if ( !trace.Hit ) return;
Vector3 contactPoint = GetWheelContactPoint( wheel, trace );
Vector3 steeringDir = wheel.Outwards;
Vector3 forwardDir = wheel.Forward;
Vector3 tireWorldVel = Body.GetVelocityAtPoint( contactPoint );
float sidewaysVelocity = Vector3.Dot( steeringDir, tireWorldVel );
float forwardVelocity = Vector3.Dot( forwardDir, tireWorldVel );
float desiredVelChange = -sidewaysVelocity * wheel.Grip;
float desiredAccel = desiredVelChange / Time.Delta;
float restingMass = Body.Mass / Wheels.Length;
float idealForceToStop = restingMass * desiredAccel;
float slipAngle = float.Abs( float.Atan2( sidewaysVelocity, float.Abs( forwardVelocity ) + 0.1f ) );
float gripCurve = CalculateSlipCurve( slipAngle );
float baselineGravity = restingMass * 9.81f;
float normalForce = baselineGravity + wheel.CurrentDownforce;
float maxLateralGrip = normalForce * wheel.Grip * gripCurve;
float lateralForce = float.Clamp( idealForceToStop, -maxLateralGrip, maxLateralGrip );
Body.ApplyForceAt( contactPoint, steeringDir * lateralForce );
}
private float CalculateSlipCurve( float slipAngle )
{
float peakAngle = 0.2f;
if ( slipAngle < peakAngle )
return slipAngle / peakAngle;
return float.Max( Brakes_SlidingFriction, 1.0f - (slipAngle - peakAngle) * 0.5f );
}
}