Code/Vehicle/VehicleController.cs
using System;
using Sandbox;
namespace Bugges.VehicleController;
[Icon( "directions_car" )]
public sealed partial class VehicleController : Component
{
// Events
public event Action<int> OnGearChanged;
public event Action<bool> OnEngineStateChanged;
public event Action OnEngineStart;
public event Action OnEngineStop;
[RequireComponent]
private Rigidbody Body { get; set; }
protected override void OnAwake()
{
InitAudio();
Body = GetComponent<Rigidbody>();
}
protected override void OnUpdate()
{
UpdateEngine();
SwitchGear();
foreach ( var wheel in Wheels )
{
var trace = Trace( wheel );
wheel.IsGrounded = trace.Hit;
UpdateWheelSpin( wheel, trace );
UpdateTireMarks( wheel, trace );
UpdateSkidAudio( wheel, trace );
Visualize( wheel, trace );
}
UpdateGears();
UpdateEngineAudio();
}
protected override void OnFixedUpdate()
{
foreach ( var wheel in Wheels )
{
var trace = Trace( wheel );
wheel.IsGrounded = trace.Hit;
ApplyTurn( wheel );
ApplySpring( wheel, trace );
ApplyAntiSlip( wheel, trace );
ApplyAcceleration( wheel, trace );
ApplyRollingFriction( wheel, trace );
ApplyBrake( wheel, trace );
}
}
private void Visualize( Wheel wheel, SceneTraceResult trace )
{
float wheelAngleAdd = float.RadiansToDegrees( wheel.SpinSpeed ) * Time.Delta;
wheel.WheelAngle += wheel.IsRotationReversed ? -wheelAngleAdd : wheelAngleAdd;
GameObject visual = wheel.Visual;
visual.WorldRotation = wheel.Rotation;
Vector3 springDown = wheel.Down;
Vector3 springPos = wheel.Spring.WorldPosition;
if ( Wheel_VisualizeTrace )
DebugOverlay.Trace( trace, overlay: true );
if ( trace.Hit )
{
float traceDistance = GetTraceDistance( wheel, trace );
float visualDistance = float.Max( traceDistance, Spring_MinDistance );
visual.WorldPosition = springPos + springDown * visualDistance;
return;
}
visual.WorldPosition = springPos + springDown * Spring_MaxDistance;
}
}