using Sandbox; using System.Collections.Generic; namespace VeloX; public partial class VeloXWheel { [ConCmd( "clear_skids" )] public static void ClearSkids() { while ( SkidMarks.Count > 1 ) SkidMarks.Dequeue()?.DestroyGameObject(); } [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 static readonly Queue SkidMarks = []; private LineRenderer _skidMark; private void ResetSkid() { _skidMark = null; } private void CreateSkid() { GameObject go = new() { WorldPosition = ContactPosition + Vehicle.WorldRotation.Down * (Radius.MeterToInch() - 0.01f), WorldRotation = Rotation.LookAt( hitSidewaysDirection ) }; _skidMark = go.AddComponent(); _skidMark.Face = SceneLineObject.FaceMode.Normal; _skidMark.Points = [go]; _skidMark.Color = Color.Black.WithAlpha( 0.5f ); _skidMark.Opaque = false; _skidMark.CastShadows = false; _skidMark.Width = Width.MeterToInch() / 2; _skidMark.AutoCalculateNormals = false; _skidMark.SplineInterpolation = 4; go.Flags = go.Flags.WithFlag( GameObjectFlags.Hidden, true ); go.Flags = go.Flags.WithFlag( GameObjectFlags.NotNetworked, true ); SkidMarks.Enqueue( _skidMark ); } protected void UpdateSkid() { if ( IsProxy ) return; while ( SkidMarks.Count > MaxSkid ) { SkidMarks.Dequeue()?.DestroyGameObject(); } if ( !IsOnGround ) { ResetSkid(); return; } var slideAmount = NormalizedSlip; if ( slideAmount < MinSlide * 2 ) { ResetSkid(); return; } if ( !_skidMark.IsValid() ) { CreateSkid(); } GameObject go = new() { Parent = _skidMark.GameObject, WorldPosition = ContactPosition + Vehicle.WorldRotation.Down * Radius.MeterToInch(), WorldRotation = Rotation.LookAt( ContactNormal.RotateAround( Vector3.Zero, Rotation.FromRoll( 90 ) ) ) }; go.Flags = go.Flags.WithFlag( GameObjectFlags.Hidden, true ); go.Flags = go.Flags.WithFlag( GameObjectFlags.NotNetworked, true ); _skidMark.Points.Add( go ); } }