Code/WheelSkidMark.cs
using Meteor.VehicleTool.Util;
using Meteor.VehicleTool.Vehicle.Wheel;
using Sandbox;
using System;
using System.Collections.Generic;
/// <summary>
/// Creates skid marks when a vehicle's wheels lose traction
/// </summary>
public class WheelSkidMarkComponent : Component
{
[ConVar( "skidmark_max_skid" )]
public static float MaxSkid { get; set; } = 50.0f;
[ConVar( "skidmark_min_slide" )]
public static float MinSlide { get; set; } = 0.1f;
private WheelCollider wheel;
private readonly List<LineRenderer> SkidMarks = [];
private LineRenderer _skidMark;
protected override void OnStart()
{
ResetSkid();
wheel ??= Components.Get<WheelCollider>( FindMode.InSelf );
}
private void ResetSkid()
{
_skidMark = null;
}
private void CreateSkid()
{
var go = Scene.CreateObject();
go.WorldPosition = wheel.ContactPoint;
go.WorldRotation = Rotation.LookAt( wheel.ContactRight );
_skidMark = go.AddComponent<LineRenderer>();
_skidMark.Face = SceneLineObject.FaceMode.Normal;
_skidMark.Points = [go];
_skidMark.Color = Color.Black.WithAlpha( 0.5f );
_skidMark.Opaque = false;
_skidMark.CastShadows = false;
go.Flags = go.Flags.WithFlag( GameObjectFlags.Hidden, true );
SkidMarks.Add( _skidMark );
}
protected override void OnUpdate()
{
while ( SkidMarks.Count > MaxSkid )
{
SkidMarks[0].DestroyGameObject();
SkidMarks.RemoveAt( 0 );
}
if ( !wheel.IsGrounded )
{
ResetSkid();
return;
}
var slideAmount = wheel.NormalizedSlip;
if ( slideAmount < MinSlide )
{
ResetSkid();
return;
}
if ( !_skidMark.IsValid() )
{
CreateSkid();
}
var go = Scene.CreateObject();
go.WorldPosition = wheel.ContactPoint;
go.WorldRotation = Rotation.LookAt( wheel.ContactRight );
go.Flags = go.Flags.WithFlag( GameObjectFlags.Hidden, true );
_skidMark.Points.Add( go );
}
}