From 964b46e1c5397a574371edeb06b45b7067b72efa Mon Sep 17 00:00:00 2001 From: Valera <108022376+kekobka@users.noreply.github.com> Date: Fri, 13 Jun 2025 21:16:20 +0700 Subject: [PATCH] =?UTF-8?q?new=20powertrain=20=D1=81=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D1=82=D1=8C=20=D1=87=D1=83=D1=80=D0=BA=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Code/Base/Powertrain/Clutch.cs | 49 ++ .../Differential/BaseDifferential.cs | 79 ++ .../Differential/OpenDifferential.cs | 13 + Code/Base/Powertrain/Engine.cs | 101 +++ Code/Base/Powertrain/Gearbox/BaseGearbox.cs | 45 ++ Code/Base/Powertrain/Gearbox/ManualGearbox.cs | 52 ++ Code/Base/Powertrain/PowerWheel.cs | 29 + Code/Base/Powertrain/PowertrainComponent.cs | 100 +++ Code/Base/VeloXBase.Phys.cs | 11 +- .../Wheel/{WheelFriction.cs => TirePreset.cs} | 2 +- Code/Base/Wheel/VeloXWheel.cs | 55 +- Code/Car/VeloXCar.Engine.cs | 689 +++++++++--------- Code/Car/VeloXCar.Steering.cs | 2 +- Code/Car/VeloXCar.Wheel.cs | 26 +- Code/Car/VeloXCar.cs | 31 +- 15 files changed, 868 insertions(+), 416 deletions(-) create mode 100644 Code/Base/Powertrain/Clutch.cs create mode 100644 Code/Base/Powertrain/Differential/BaseDifferential.cs create mode 100644 Code/Base/Powertrain/Differential/OpenDifferential.cs create mode 100644 Code/Base/Powertrain/Engine.cs create mode 100644 Code/Base/Powertrain/Gearbox/BaseGearbox.cs create mode 100644 Code/Base/Powertrain/Gearbox/ManualGearbox.cs create mode 100644 Code/Base/Powertrain/PowerWheel.cs create mode 100644 Code/Base/Powertrain/PowertrainComponent.cs rename Code/Base/Wheel/{WheelFriction.cs => TirePreset.cs} (87%) diff --git a/Code/Base/Powertrain/Clutch.cs b/Code/Base/Powertrain/Clutch.cs new file mode 100644 index 0000000..600a847 --- /dev/null +++ b/Code/Base/Powertrain/Clutch.cs @@ -0,0 +1,49 @@ +using Sandbox; +using System; + +namespace VeloX.Powertrain; + +public class Clutch : PowertrainComponent +{ + [Property] public override float Inertia { get; set; } = 0.002f; + [Property] public float SlipTorque { get; set; } = 1000f; + + public float Pressing { get; set; } = 1; // todo + + public override float QueryInertia() + { + if ( !HasOutput ) + return Inertia; + + return Inertia + Output.QueryInertia() * Pressing; + } + + public override float QueryAngularVelocity( float angularVelocity ) + { + this.angularVelocity = angularVelocity; + + if ( !HasOutput ) + return angularVelocity; + + + float outputW = Output.QueryAngularVelocity( angularVelocity ) * Pressing; + float inputW = angularVelocity * (1 - Pressing); + + return outputW + inputW; + } + + + public override float ForwardStep( float torque, float inertia ) + { + if ( !HasOutput ) + return torque; + + Torque = Math.Clamp( torque, -SlipTorque, SlipTorque ); + + Torque = torque * (1 - (1 - MathF.Pow( Pressing, 0.3f ))); + + float returnTorque = Output.ForwardStep( Torque, inertia * Pressing + Inertia ) * Pressing; + + return Math.Clamp( returnTorque, -SlipTorque, SlipTorque ); + } +} diff --git a/Code/Base/Powertrain/Differential/BaseDifferential.cs b/Code/Base/Powertrain/Differential/BaseDifferential.cs new file mode 100644 index 0000000..1eaa75c --- /dev/null +++ b/Code/Base/Powertrain/Differential/BaseDifferential.cs @@ -0,0 +1,79 @@ +using Sandbox; +using System; + +namespace VeloX.Powertrain; + +[Category( "VeloX/Powertrain/Gearbox" )] +public abstract class BaseDifferential : PowertrainComponent +{ + [Property] public float FinalDrive { get; set; } = 3.392f; + [Property] public override float Inertia { get; set; } = 0.01f; + //[Property] public float CoastRamp { get; set; } = 1f; + //[Property] public float PowerRamp { get; set; } = 1f; + //[Property] public float Stiffness { get; set; } = 0.1f; + //[Property] public float SlipTorque { get; set; } = 0f; + //[Property] public float SteerLock { get; set; } = 45f; + + + /// + /// The PowertrainComponent this component will output to. + /// + [Property] + public PowertrainComponent OutputB + { + get => _outputb; + set + { + if ( value == this ) + { + _outputb = null; + return; + } + + _outputb = value; + if ( _outputb != null ) + _outputb.Input = this; + } + + } + private PowertrainComponent _outputb; + + public override bool HasOutput => Output.IsValid() && OutputB.IsValid(); + + public override float QueryAngularVelocity( float angularVelocity ) + { + this.angularVelocity = angularVelocity; + + if ( !HasOutput ) + return angularVelocity; + + float aW = Output.QueryAngularVelocity( angularVelocity ); + float bW = OutputB.QueryAngularVelocity( angularVelocity ); + + return (aW + bW) * FinalDrive * 0.5f; + } + + public abstract void SplitTorque( float aW, float bW, float aI, float bI, out float tqA, out float tqB ); + + public override float ForwardStep( float torque, float inertia ) + { + if ( !HasOutput ) + return torque; + + float aW = Output.QueryAngularVelocity( angularVelocity ); + float bW = OutputB.QueryAngularVelocity( angularVelocity ); + + float aI = Output.QueryInertia(); + float bI = OutputB.QueryInertia(); + + Torque = torque * FinalDrive; + + SplitTorque( aW, bW, aI, bI, out float tqA, out float tqB ); + + tqA = Output.ForwardStep( tqA, inertia * 0.5f * MathF.Pow( FinalDrive, 2 ) + aI ); + tqB = OutputB.ForwardStep( tqB, inertia * 0.5f * MathF.Pow( FinalDrive, 2 ) + bI ); + + return tqA + tqB; + } + +} diff --git a/Code/Base/Powertrain/Differential/OpenDifferential.cs b/Code/Base/Powertrain/Differential/OpenDifferential.cs new file mode 100644 index 0000000..15a0065 --- /dev/null +++ b/Code/Base/Powertrain/Differential/OpenDifferential.cs @@ -0,0 +1,13 @@ +using Sandbox; + +namespace VeloX.Powertrain; + +public class OpenDifferential : BaseDifferential +{ + [Property] public float BiasAB { get; set; } = 0.5f; + public override void SplitTorque( float aW, float bW, float aI, float bI, out float tqA, out float tqB ) + { + tqA = Torque * (1 - BiasAB); + tqB = Torque * BiasAB; + } +} diff --git a/Code/Base/Powertrain/Engine.cs b/Code/Base/Powertrain/Engine.cs new file mode 100644 index 0000000..5c95861 --- /dev/null +++ b/Code/Base/Powertrain/Engine.cs @@ -0,0 +1,101 @@ +using Sandbox; +using System; + +namespace VeloX.Powertrain; + +public class Engine : PowertrainComponent +{ + [Property, Group( "Settings" )] public float IdleRPM { get; set; } = 900f; + [Property, Group( "Settings" )] public float MaxRPM { get; set; } = 7000f; + [Property, Group( "Settings" )] public override float Inertia { get; set; } = 0.151f; + [Property, Group( "Settings" )] public float StartFriction { get; set; } = 50f; + [Property, Group( "Settings" )] public float FrictionCoeff { get; set; } = 0.02f; + [Property, Group( "Settings" )] public float LimiterDuration { get; set; } = 0.05f; + [Property, Group( "Settings" )] public Curve TorqueMap { get; set; } + [Property, Group( "Settings" )] public EngineStream Stream { get; set; } + + [Sync] public float Throttle { get; internal set; } + + [Property] public bool IsRedlining => !limiterTimer; + [Property] public float RPMPercent => Math.Clamp( (RPM - IdleRPM) / (MaxRPM - IdleRPM), 0, 1 ); + + private float masterThrottle; + private TimeUntil limiterTimer; + private float finalTorque; + + private EngineStreamPlayer StreamPlayer; + + protected override void OnStart() + { + base.OnStart(); + + StreamPlayer = new( Stream ); + } + + private float GenerateTorque() + { + float throttle = Throttle; + float rpm = RPM; + float friction = StartFriction - rpm * FrictionCoeff; + float maxInitialTorque = TorqueMap.Evaluate( RPMPercent ) - friction; + float idleFadeStart = Math.Clamp( MathX.Remap( rpm, IdleRPM - 300, IdleRPM, 1, 0 ), 0, 1 ); + float idleFadeEnd = Math.Clamp( MathX.Remap( rpm, IdleRPM, IdleRPM + 600, 1, 0 ), 0, 1 ); + float additionalEnergySupply = idleFadeEnd * (-friction / maxInitialTorque) + idleFadeStart; + + + if ( rpm > MaxRPM ) + { + throttle = 0; + limiterTimer = LimiterDuration; + } + else if ( !limiterTimer ) + throttle = 0; + + masterThrottle = Math.Clamp( additionalEnergySupply + throttle, 0, 1 ); + + float realInitialTorque = maxInitialTorque * masterThrottle; + Torque = realInitialTorque + friction; + + return Torque; + } + + public override float ForwardStep( float _, float __ ) + { + if ( !HasOutput ) + { + angularVelocity += GenerateTorque() / Inertia * Time.Delta; + angularVelocity = Math.Max( angularVelocity, 0 ); + return 0; + } + float outputInertia = Output.QueryInertia(); + float inertiaSum = Inertia + outputInertia; + float outputW = Output.QueryAngularVelocity( angularVelocity ); + float targetW = Inertia / inertiaSum * angularVelocity + outputInertia / inertiaSum * outputW; + float generatedTorque = GenerateTorque(); + float reactTorque = (targetW - angularVelocity) * Inertia / Time.Delta; + float returnedTorque = Output.ForwardStep( generatedTorque - reactTorque, Inertia ); + + finalTorque = generatedTorque + reactTorque + returnedTorque; + angularVelocity += finalTorque / inertiaSum * Time.Delta; + angularVelocity = Math.Max( angularVelocity, 0 ); + + UpdateStream(); + + return finalTorque; + } + + private void UpdateStream() + { + if ( StreamPlayer is null ) + return; + + StreamPlayer.Throttle = Throttle; + StreamPlayer.RPMPercent = RPMPercent; + StreamPlayer.EngineState = EngineState.Running; + StreamPlayer.IsRedlining = IsRedlining; + + StreamPlayer.Update( Time.Delta, WorldPosition ); + + } + +} diff --git a/Code/Base/Powertrain/Gearbox/BaseGearbox.cs b/Code/Base/Powertrain/Gearbox/BaseGearbox.cs new file mode 100644 index 0000000..8a68516 --- /dev/null +++ b/Code/Base/Powertrain/Gearbox/BaseGearbox.cs @@ -0,0 +1,45 @@ +using Sandbox; +using System; + +namespace VeloX.Powertrain; + +[Category( "VeloX/Powertrain/Gearbox" )] +public abstract class BaseGearbox : PowertrainComponent +{ + [Property] public override float Inertia { get; set; } = 0.01f; + + protected float ratio; + + public override float QueryInertia() + { + if ( !HasOutput || ratio == 0 ) + return Inertia; + + return Inertia + Output.QueryInertia() / MathF.Pow( ratio, 2 ); + } + + public override float QueryAngularVelocity( float angularVelocity ) + { + this.angularVelocity = angularVelocity; + if ( !HasOutput || ratio == 0 ) + return angularVelocity; + + return Output.QueryAngularVelocity( angularVelocity ) * ratio; + } + + public override float ForwardStep( float torque, float inertia ) + { + Torque = torque * ratio; + + if ( !HasOutput ) + return torque; + + if ( ratio == 0 ) + { + Output.ForwardStep( 0, Inertia * 0.5f ); + return torque; + } + + return Output.ForwardStep( Torque, (inertia + Inertia) * MathF.Pow( ratio, 2 ) ) / ratio; + } +} diff --git a/Code/Base/Powertrain/Gearbox/ManualGearbox.cs b/Code/Base/Powertrain/Gearbox/ManualGearbox.cs new file mode 100644 index 0000000..d0c6a65 --- /dev/null +++ b/Code/Base/Powertrain/Gearbox/ManualGearbox.cs @@ -0,0 +1,52 @@ +using Sandbox; + +namespace VeloX.Powertrain; + +public class ManualGearbox : BaseGearbox +{ + [Property] public float[] Ratios { get; set; } = [3.626f, 2.200f, 1.541f, 1.213f, 1.000f, 0.767f]; + [Property] public float Reverse { get; set; } = 3.4f; + [Property, InputAction] public string ForwardAction { get; set; } = "Attack1"; + [Property, InputAction] public string BackwardAction { get; set; } = "Attack2"; + + private int gear; + + protected void SetGear( int gear ) + { + if ( gear < -1 || gear >= Ratios.Length ) + return; + this.gear = gear; + + RecalcRatio(); + } + + private void RecalcRatio() + { + if ( gear == -1 ) + ratio = -Reverse; + else if ( gear == 0 ) + ratio = 0; + else + ratio = Ratios[gear - 1]; + } + + public void Shift( int dir ) + { + SetGear( gear + dir ); + } + + private void InputResolve() + { + if ( Sandbox.Input.Pressed( ForwardAction ) ) + Shift( 1 ); + else if ( Sandbox.Input.Pressed( BackwardAction ) ) + Shift( -1 ); + } + + public override float ForwardStep( float torque, float inertia ) + { + InputResolve(); + + return base.ForwardStep( torque, inertia ); + } +} diff --git a/Code/Base/Powertrain/PowerWheel.cs b/Code/Base/Powertrain/PowerWheel.cs new file mode 100644 index 0000000..fa9d1e2 --- /dev/null +++ b/Code/Base/Powertrain/PowerWheel.cs @@ -0,0 +1,29 @@ +using Sandbox; +using System; + +namespace VeloX.Powertrain; + +public class PowerWheel : PowertrainComponent +{ + [Property] public VeloXWheel Wheel { get; set; } + + public override float QueryInertia() => Wheel.Inertia; + + public override float QueryAngularVelocity( float angularVelocity ) + { + return Wheel.AngularVelocity; + } + + public override float ForwardStep( float torque, float inertia ) + { + Wheel.AutoPhysics = false; + Wheel.Torque = torque; + Wheel.Brake = Vehicle.Brake; + + Wheel.DoPhysics( Vehicle ); + + angularVelocity = Wheel.AngularVelocity; + + return Wheel.CounterTorque; + } +} diff --git a/Code/Base/Powertrain/PowertrainComponent.cs b/Code/Base/Powertrain/PowertrainComponent.cs new file mode 100644 index 0000000..1997852 --- /dev/null +++ b/Code/Base/Powertrain/PowertrainComponent.cs @@ -0,0 +1,100 @@ +using Sandbox; +using System; + +namespace VeloX.Powertrain; + +public abstract class PowertrainComponent : Component +{ + + protected override void OnAwake() + { + Vehicle ??= Components.Get( FindMode.EverythingInSelfAndAncestors ); + } + + public const float RAD_TO_RPM = 60f / MathF.Tau; + public const float RPM_TO_RAD = 1 / (60 / MathF.Tau); + public const float UNITS_PER_METER = 39.37f; + public const float UNITS_TO_METERS = 0.01905f; + public const float KG_TO_N = 9.80665f; + public const float KG_TO_KN = 0.00980665f; + + [Property] public VeloXBase Vehicle { get; set; } + [Property] public virtual float Inertia { get; set; } = 0.02f; + + + /// + /// Input component. Set automatically. + /// + [Property] + public PowertrainComponent Input + { + get => _input; + set + { + if ( value == null || value == this ) + { + _input = null; + return; + } + + _input = value; + } + } + + private PowertrainComponent _input; + public int InputNameHash; + + /// + /// The PowertrainComponent this component will output to. + /// + [Property] + public PowertrainComponent Output + { + get => _output; + set + { + if ( value == this ) + { + _output = null; + return; + } + + _output = value; + if ( _output != null ) + _output.Input = this; + } + + } + private PowertrainComponent _output; + + public float RPM => angularVelocity * RAD_TO_RPM; + + protected float angularVelocity; + protected float Torque; + + public virtual bool HasOutput => Output.IsValid(); + + public virtual float QueryInertia() + { + if ( !HasOutput ) + return Inertia; + + return Inertia + Output.QueryInertia(); + } + + public virtual float QueryAngularVelocity( float angularVelocity ) + { + if ( !HasOutput ) + return angularVelocity; + + return Output.QueryAngularVelocity( angularVelocity ); + } + + public virtual float ForwardStep( float torque, float inertia ) + { + if ( !HasOutput ) + return Torque; + + return Output.ForwardStep( Torque, inertia + Inertia ); + } +} diff --git a/Code/Base/VeloXBase.Phys.cs b/Code/Base/VeloXBase.Phys.cs index b89cff8..8c52b3f 100644 --- a/Code/Base/VeloXBase.Phys.cs +++ b/Code/Base/VeloXBase.Phys.cs @@ -1,6 +1,4 @@ -using Sandbox; - -namespace VeloX; +namespace VeloX; public abstract partial class VeloXBase { @@ -17,14 +15,9 @@ public abstract partial class VeloXBase angForce.y = angVel.y * drag.y * mass; angForce.z = angVel.z * drag.z * mass; - if ( Wheels.Count > 0 ) - { - - var dt = Time.Delta; foreach ( var v in Wheels ) - v.DoPhysics( this, in dt ); - } + if ( v.AutoPhysics ) v.DoPhysics( this ); Body.ApplyTorque( angForce ); } diff --git a/Code/Base/Wheel/WheelFriction.cs b/Code/Base/Wheel/TirePreset.cs similarity index 87% rename from Code/Base/Wheel/WheelFriction.cs rename to Code/Base/Wheel/TirePreset.cs index d2925b9..59e7013 100644 --- a/Code/Base/Wheel/WheelFriction.cs +++ b/Code/Base/Wheel/TirePreset.cs @@ -4,7 +4,7 @@ namespace VeloX; [GameResource( "Wheel Friction", "whfric", "Wheel Friction", Category = "VeloX", Icon = "radio_button_checked" )] -public class WheelFriction : GameResource +public class TirePreset : GameResource { public FrictionPreset Longitudinal { get; set; } public FrictionPreset Lateral { get; set; } diff --git a/Code/Base/Wheel/VeloXWheel.cs b/Code/Base/Wheel/VeloXWheel.cs index 24850c2..d0a00ed 100644 --- a/Code/Base/Wheel/VeloXWheel.cs +++ b/Code/Base/Wheel/VeloXWheel.cs @@ -1,11 +1,6 @@ using Sandbox; -using Sandbox.UI; using System; -using System.Buffers.Text; -using System.Numerics; -using System.Runtime.Intrinsics.Arm; using System.Text.RegularExpressions; -using System.Threading; namespace VeloX; @@ -23,13 +18,10 @@ public partial class VeloXWheel : Component public FrictionPreset LateralFrictionPreset => WheelFriction.Lateral; public FrictionPreset AligningFrictionPreset => WheelFriction.Aligning; - [Property] public WheelFriction WheelFriction { get; set; } - - + [Property] public TirePreset WheelFriction { get; set; } [Property] public float Width { get; set; } = 6; [Sync] public float SideSlip { get; private set; } [Sync] public float ForwardSlip { get; private set; } - [Sync, Range( 0, 1 )] public float BrakePower { get; set; } [Sync] public float Torque { get; set; } [Sync, Range( 0, 1 )] public float Brake { get; set; } [Property] float BrakePowerMax { get; set; } = 3000; @@ -43,9 +35,13 @@ public partial class VeloXWheel : Component [Property, Group( "Suspension" )] float SpringStrength { get; set; } = 800; [Property, Group( "Suspension" )] float SpringDamper { get; set; } = 3000; + [Property] public bool AutoPhysics { get; set; } = true; + public float Spin { get; private set; } public float RPM { get => angularVelocity * 60f / MathF.Tau; set => angularVelocity = value / (60 / MathF.Tau); } + public float AngularVelocity => angularVelocity; + internal float DistributionFactor { get; set; } private Vector3 StartPos { get; set; } @@ -69,9 +65,11 @@ public partial class VeloXWheel : Component private Friction forwardFriction; private Friction sideFriction; private Vector3 force; + public float CounterTorque { get; private set; } private float BaseInertia => 0.5f * Mass * MathF.Pow( Radius.InchToMeter(), 2 ); - private float Inertia => BaseInertia; + public float Inertia => BaseInertia; + protected override void OnAwake() { @@ -118,7 +116,7 @@ public partial class VeloXWheel : Component } - private (float, float, float, float) StepLongitudinal( float Vx, float Lc, float kFx, float kSx, float dt ) + private (float, float, float, float) StepLongitudinal( float Vx, float Lc, float kFx, float kSx) { float Tm = Torque; float Tb = Brake * BrakePowerMax + RollingResistance; @@ -138,35 +136,35 @@ public partial class VeloXWheel : Component Sx = Math.Clamp( Sx * kSx, -1, 1 ); - W += Tm / I * dt; + W += Tm / I * Time.Delta; Tb *= W > 0 ? -1 : 1; - float TbCap = MathF.Abs( W ) * I / dt; + float TbCap = MathF.Abs( W ) * I / Time.Delta; float Tbr = MathF.Abs( Tb ) - MathF.Abs( TbCap ); Tbr = MathF.Max( Tbr, 0 ); Tb = Math.Clamp( Tb, -TbCap, TbCap ); - W += Tb / I * dt; + W += Tb / I * Time.Delta; float maxTorque = LongitudinalFrictionPreset.Evaluate( Sx ) * Lc * kFx; - float errorTorque = (W - Vx / R) * I / dt; + float errorTorque = (W - Vx / R) * I / Time.Delta; float surfaceTorque = MathX.Clamp( errorTorque, -maxTorque, maxTorque ); - W -= surfaceTorque / I * dt; + W -= surfaceTorque / I * Time.Delta; float Fx = surfaceTorque / R; Tbr *= W > 0 ? -1 : 1; - float TbCap2 = MathF.Abs( W ) * I / dt; + float TbCap2 = MathF.Abs( W ) * I / Time.Delta; float Tb2 = Math.Clamp( Tbr, -TbCap2, TbCap2 ); - W += Tb2 / I * dt; + W += Tb2 / I * Time.Delta; - float deltaOmegaTorque = (W - Winit) * I / dt; + float deltaOmegaTorque = (W - Winit) * I / Time.Delta; float Tcnt = -surfaceTorque + Tb + Tb2 - deltaOmegaTorque; if ( Lc < 0.001f ) @@ -175,7 +173,7 @@ public partial class VeloXWheel : Component return (W, Sx, Fx, Tcnt); } - private (float, float) StepLateral( float Vx, float Vy, float Lc, float kFy, float kSy, float dt ) + private (float, float) StepLateral( float Vx, float Vy, float Lc, float kFy, float kSy) { float VxAbs = MathF.Abs( Vx ); float Sy; @@ -183,7 +181,7 @@ public partial class VeloXWheel : Component if ( VxAbs > 0.1f ) Sy = MathF.Atan( Vy / VxAbs ).RadianToDegree() * 0.01111f; else - Sy = Vy * (0.003f / dt); + Sy = Vy * (0.003f / Time.Delta); Sy *= kSy * 0.95f; @@ -224,7 +222,7 @@ public partial class VeloXWheel : Component private static float GetLongitudinalLoadCoefficient( float load ) => 11000 * (1 - MathF.Exp( -0.00014f * load )); private static float GetLateralLoadCoefficient( float load ) => 18000 * (1 - MathF.Exp( -0.0001f * load )); - public void DoPhysics( VeloXBase vehicle, in float dt ) + public void DoPhysics( VeloXBase vehicle ) { var pos = vehicle.WorldTransform.PointToWorld( StartPos ); @@ -274,7 +272,7 @@ public partial class VeloXWheel : Component var springForce = (offset * SpringStrength); var damperForce = (lastSpringOffset - offset) * SpringDamper; lastSpringOffset = offset; - force = (springForce - damperForce) * MathF.Max( 0, up.Dot( normal ) ) * normal / dt; + force = (springForce - damperForce) * MathF.Max( 0, up.Dot( normal ) ) * normal / Time.Delta; // Vector3.CalculateVelocityOffset is broken (need fix) //var velU = normal.Dot( vel ).MeterToInch(); @@ -301,13 +299,11 @@ public partial class VeloXWheel : Component forwardSpeed = vel.Dot( forward ); sideSpeed = vel.Dot( right ); } - - (float W, float Sx, float Fx, float _) = StepLongitudinal( + (float W, float Sx, float Fx, float Tcnt) = StepLongitudinal( forwardSpeed, longitudinalLoadCoefficient, 0.95f, - 0.9f, - dt + 0.9f ); (float Sy, float Fy) = StepLateral( @@ -315,12 +311,13 @@ public partial class VeloXWheel : Component sideSpeed, lateralLoadCoefficient, 0.95f, - 0.9f, - dt + 0.9f ); SlipCircle( Sx, Sy, Fx, ref Fy ); + angularVelocity = W; + CounterTorque = Tcnt; forwardFriction = new Friction() { diff --git a/Code/Car/VeloXCar.Engine.cs b/Code/Car/VeloXCar.Engine.cs index c6e47ee..b6748ae 100644 --- a/Code/Car/VeloXCar.Engine.cs +++ b/Code/Car/VeloXCar.Engine.cs @@ -1,354 +1,365 @@ using Sandbox; using System; using System.Collections.Generic; +using VeloX.Powertrain; namespace VeloX; public partial class VeloXCar { - [Property, Feature( "Engine" ), Sync] public EngineState EngineState { get; set; } - [Property, Feature( "Engine" )] public EngineStream Stream { get; set; } - public EngineStreamPlayer StreamPlayer { get; set; } - [Property, Feature( "Engine" )] public float MinRPM { get; set; } = 800; - [Property, Feature( "Engine" )] public float MaxRPM { get; set; } = 7000; - [Property, Feature( "Engine" ), Range( -1, 1 )] - public float PowerDistribution - { - get => powerDistribution; set - { - powerDistribution = value; - UpdatePowerDistribution(); - } - } - [Property, Feature( "Engine" )] public float FlyWheelMass { get; set; } = 80f; - [Property, Feature( "Engine" )] public float FlyWheelRadius { get; set; } = 0.5f; - [Property, Feature( "Engine" )] public float FlywheelFriction { get; set; } = -6000; - [Property, Feature( "Engine" )] public float FlywheelTorque { get; set; } = 20000; - [Property, Feature( "Engine" )] public float EngineBrakeTorque { get; set; } = 2000; - [Property, Feature( "Engine" )] - public Dictionary Gears { get; set; } = new() - { - [-1] = 2.5f, - [0] = 0f, - [1] = 2.8f, - [2] = 1.7f, - [3] = 1.2f, - [4] = 0.9f, - [5] = 0.75f, - [6] = 0.7f - }; - [Property, Feature( "Engine" )] public float DifferentialRatio { get; set; } = 1f; - [Property, Feature( "Engine" ), Range( 0, 1 )] public float TransmissionEfficiency { get; set; } = 0.8f; - [Property, Feature( "Engine" )] private float MinRPMTorque { get; set; } = 5000f; - [Property, Feature( "Engine" )] private float MaxRPMTorque { get; set; } = 8000f; - [Sync] public int Gear { get; set; } = 0; - [Sync] public float Clutch { get; set; } = 1; - [Sync( SyncFlags.Interpolate )] public float EngineRPM { get; set; } - public float RPMPercent => (EngineRPM - MinRPM) / MaxRPM; - - private const float TAU = MathF.Tau; - - private int MinGear { get; set; } - private int MaxGear { get; set; } - - [Sync] public bool IsRedlining { get; private set; } - - private float flywheelVelocity; - private TimeUntil switchCD = 0; - private float groundedCount; - private float burnout; - - private float frontBrake; - private float rearBrake; - - private float availableFrontTorque; - private float availableRearTorque; - - private float avgSideSlip; - private float avgPoweredRPM; - private float avgForwardSlip; - - private float inputThrottle, inputBrake; - private bool inputHandbrake; - private float transmissionRPM; - private float powerDistribution; - - public float FlywheelRPM - { - get => flywheelVelocity * 60 / TAU; - set - { - flywheelVelocity = value * TAU / 60; EngineRPM = value; - } - } - private void UpdateGearList() - { - int minGear = 0; - int maxGear = 0; - - foreach ( var (gear, ratio) in Gears ) - { - - if ( gear < minGear ) - minGear = gear; - - if ( gear > maxGear ) - maxGear = gear; - - if ( minGear != 0 || maxGear != 0 ) - { - SwitchGear( 0, false ); - } - } - - MinGear = minGear; - MaxGear = maxGear; - - } - - - public void SwitchGear( int index, bool cooldown = true ) - { - if ( Gear == index ) return; - index = Math.Clamp( index, MinGear, MaxGear ); - - if ( index == 0 || !cooldown ) - switchCD = 0; - else - switchCD = 0.3f; - Clutch = 1; - Gear = index; - } - - public float TransmissionToEngineRPM( int gear ) => avgPoweredRPM * Gears[gear] * DifferentialRatio * 60 / TAU; - public float GetTransmissionMaxRPM( int gear ) => FlywheelRPM / Gears[gear] / DifferentialRatio; - - private void UpdatePowerDistribution() - { - if ( Wheels is null ) return; - int frontCount = 0, rearCount = 0; - - foreach ( var wheel in Wheels ) - { - if ( wheel.IsFront ) - frontCount++; - else - rearCount++; - - } - - float frontDistribution = 0.5f + PowerDistribution * 0.5f; - - float rearDistribution = 1 - frontDistribution; - - frontDistribution /= frontCount; - rearDistribution /= rearCount; - - foreach ( var wheel in Wheels ) - if ( wheel.IsFront ) - wheel.DistributionFactor = frontDistribution; - else - wheel.DistributionFactor = rearDistribution; - } - - private void EngineAccelerate( float torque, float dt ) - { - var inertia = 0.5f * FlyWheelMass * FlyWheelRadius * FlyWheelRadius; - var angularAcceleration = torque / inertia; - - flywheelVelocity += angularAcceleration * dt; - } - - private float GetTransmissionTorque( int gear, float minTorque, float maxTorque ) - { - var torque = FlywheelRPM.Remap( MinRPM, MaxRPM, minTorque, maxTorque, true ); - torque *= (1 - Clutch); - torque = torque * Gears[gear] * DifferentialRatio * TransmissionEfficiency; - - return gear == -1 ? -torque : torque; - } - - private void AutoGearSwitch() - { - if ( ForwardSpeed < 100 && Input.Down( "Backward" ) ) - { - SwitchGear( -1, false ); - return; - } - - var currentGear = Gear; - - if ( currentGear < 0 && ForwardSpeed < -100 ) - return; - - if ( Math.Abs( avgForwardSlip ) > 10 ) - return; - - var gear = Math.Clamp( currentGear, 1, MaxGear ); - - float minRPM = MinRPM, maxRPM = MaxRPM; - - - maxRPM *= 0.98f; - - float gearRPM; - - - for ( int i = 1; i <= MaxGear; i++ ) - { - gearRPM = TransmissionToEngineRPM( i ); - - if ( (i == 1 && gearRPM < minRPM) || (gearRPM > minRPM && gearRPM < maxRPM) ) - { - gear = i; - break; - } - } - - var threshold = minRPM + (maxRPM - minRPM) * (0.5 - Throttle * 0.3); - if ( gear < currentGear && gear > currentGear - 2 && EngineRPM > threshold ) - return; - - SwitchGear( gear ); - } - - private float EngineClutch( float dt ) - { - if ( !switchCD ) - { - inputThrottle = 0; - - return 0; - } - - if ( inputHandbrake ) - return 1; - - var absForwardSpeed = Math.Abs( ForwardSpeed ); - - if ( groundedCount < 1 && absForwardSpeed > 30 ) - return 1; - - if ( ForwardSpeed < -50 && inputBrake > 0 && Gear < 0 ) - return 1; - - if ( absForwardSpeed > 200 ) - return 0; - - return inputThrottle > 0.1f ? 0 : 1; - } + [Property, Feature( "Engine" )] Engine Engine { get; set; } private void EngineThink( float dt ) { - inputThrottle = Input.Down( "Forward" ) ? 1 : 0; - inputBrake = Input.Down( "Backward" ) ? 1 : 0; - inputHandbrake = Input.Down( "Jump" ); - if ( burnout > 0 ) - { - SwitchGear( 1, false ); - if ( inputThrottle < 0.1f || inputBrake < 0.1f ) - burnout = 0; - } - else - AutoGearSwitch(); - - if ( Gear < 0 ) - (inputBrake, inputThrottle) = (inputThrottle, inputBrake); - - var rpm = FlywheelRPM; - - var clutch = EngineClutch( dt ); - - if ( inputThrottle > 0.1 && inputBrake > 0.1 && Math.Abs( ForwardSpeed ) < 50 ) - { - burnout = MathX.Approach( burnout, 1, dt * 2 ); - Clutch = 0; - - } - else if ( inputHandbrake ) - { - frontBrake = 0f; - rearBrake = 0.5f; - Clutch = 1; - clutch = 1; - } - else - { - if ( (Gear == -1 || Gear == 1) && inputThrottle < 0.05f && inputBrake < 0.1f && groundedCount > 1 && rpm < MinRPM * 1.2f ) - inputBrake = 0.2f; - - frontBrake = inputBrake * 0.5f; - rearBrake = inputBrake * 0.5f; - } - - clutch = MathX.Approach( Clutch, clutch, dt * ((Gear < 2 && inputThrottle > 0.1f) ? 6 : 2) ); - - Clutch = clutch; - - var isRedlining = false; - transmissionRPM = 0; - - if ( Gear != 0 ) - { - transmissionRPM = TransmissionToEngineRPM( Gear ); - transmissionRPM = Gear < 0 ? -transmissionRPM : transmissionRPM; - rpm = (rpm * clutch) + (MathF.Max( 0, transmissionRPM ) * (1 - clutch)); - } - var throttle = Throttle; - - var gearTorque = GetTransmissionTorque( Gear, MinRPMTorque, MaxRPMTorque ); - - var availableTorque = gearTorque * throttle; - - if ( transmissionRPM < 0 ) - { - availableTorque += gearTorque * 2; - } - else - { - var engineBrakeTorque = GetTransmissionTorque( Gear, EngineBrakeTorque, EngineBrakeTorque ); - - availableTorque -= engineBrakeTorque * (1 - throttle) * 0.5f; - } - - var maxRPM = MaxRPM; - - if ( rpm < MinRPM ) - { - rpm = MinRPM; - } - else if ( rpm > maxRPM ) - { - - if ( rpm > maxRPM * 1.2f ) - availableTorque = 0; - - rpm = maxRPM; - - if ( Gear != MaxGear || groundedCount < Wheels.Count ) - isRedlining = true; - } - - FlywheelRPM = Math.Clamp( rpm, 0, maxRPM ); - - if ( burnout > 0 ) - availableTorque += availableTorque * burnout * 0.1f; - - var front = 0.5f + PowerDistribution * 0.5f; - var rear = 1 - front; - - availableFrontTorque = availableTorque * front; - availableRearTorque = availableTorque * rear; - - throttle = MathX.Approach( throttle, inputThrottle, dt * 4 ); - - - EngineAccelerate( FlywheelFriction + FlywheelTorque * throttle, dt ); - - Throttle = throttle; - - IsRedlining = (isRedlining && inputThrottle > 0); + Engine.Throttle = Input.Down( "Forward" ) ? 1 : 0; + Engine.ForwardStep( 0, 0 ); } + + //[Property, Feature( "Engine" ), Sync] public EngineState EngineState { get; set; } + //[Property, Feature( "Engine" )] public EngineStream Stream { get; set; } + //public EngineStreamPlayer StreamPlayer { get; set; } + + //[Property, Feature( "Engine" )] public float MinRPM { get; set; } = 800; + //[Property, Feature( "Engine" )] public float MaxRPM { get; set; } = 7000; + //[Property, Feature( "Engine" ), Range( -1, 1 )] + //public float PowerDistribution + //{ + // get => powerDistribution; set + // { + // powerDistribution = value; + // UpdatePowerDistribution(); + // } + //} + //[Property, Feature( "Engine" )] public float FlyWheelMass { get; set; } = 80f; + //[Property, Feature( "Engine" )] public float FlyWheelRadius { get; set; } = 0.5f; + //[Property, Feature( "Engine" )] public float FlywheelFriction { get; set; } = -6000; + //[Property, Feature( "Engine" )] public float FlywheelTorque { get; set; } = 20000; + //[Property, Feature( "Engine" )] public float EngineBrakeTorque { get; set; } = 2000; + //[Property, Feature( "Engine" )] + //public Dictionary Gears { get; set; } = new() + //{ + // [-1] = 2.5f, + // [0] = 0f, + // [1] = 2.8f, + // [2] = 1.7f, + // [3] = 1.2f, + // [4] = 0.9f, + // [5] = 0.75f, + // [6] = 0.7f + //}; + //[Property, Feature( "Engine" )] public float DifferentialRatio { get; set; } = 1f; + //[Property, Feature( "Engine" ), Range( 0, 1 )] public float TransmissionEfficiency { get; set; } = 0.8f; + //[Property, Feature( "Engine" )] private float MinRPMTorque { get; set; } = 5000f; + //[Property, Feature( "Engine" )] private float MaxRPMTorque { get; set; } = 8000f; + //[Sync] public int Gear { get; set; } = 0; + //[Sync] public float Clutch { get; set; } = 1; + //[Sync( SyncFlags.Interpolate )] public float EngineRPM { get; set; } + //public float RPMPercent => (EngineRPM - MinRPM) / MaxRPM; + + //private const float TAU = MathF.Tau; + + //private int MinGear { get; set; } + //private int MaxGear { get; set; } + + //[Sync] public bool IsRedlining { get; private set; } + + //private float flywheelVelocity; + //private TimeUntil switchCD = 0; + //private float groundedCount; + //private float burnout; + + //private float frontBrake; + //private float rearBrake; + + //private float availableFrontTorque; + //private float availableRearTorque; + + //private float avgSideSlip; + //private float avgPoweredRPM; + //private float avgForwardSlip; + + //private float inputThrottle, inputBrake; + //private bool inputHandbrake; + //private float transmissionRPM; + //private float powerDistribution; + + //public float FlywheelRPM + //{ + // get => flywheelVelocity * 60 / TAU; + // set + // { + // flywheelVelocity = value * TAU / 60; EngineRPM = value; + // } + //} + //private void UpdateGearList() + //{ + // int minGear = 0; + // int maxGear = 0; + + // foreach ( var (gear, ratio) in Gears ) + // { + + // if ( gear < minGear ) + // minGear = gear; + + // if ( gear > maxGear ) + // maxGear = gear; + + // if ( minGear != 0 || maxGear != 0 ) + // { + // SwitchGear( 0, false ); + // } + // } + + // MinGear = minGear; + // MaxGear = maxGear; + + //} + + + //public void SwitchGear( int index, bool cooldown = true ) + //{ + // if ( Gear == index ) return; + // index = Math.Clamp( index, MinGear, MaxGear ); + + // if ( index == 0 || !cooldown ) + // switchCD = 0; + // else + // switchCD = 0.3f; + // Clutch = 1; + // Gear = index; + //} + + //public float TransmissionToEngineRPM( int gear ) => avgPoweredRPM * Gears[gear] * DifferentialRatio * 60 / TAU; + //public float GetTransmissionMaxRPM( int gear ) => FlywheelRPM / Gears[gear] / DifferentialRatio; + + //private void UpdatePowerDistribution() + //{ + // if ( Wheels is null ) return; + // int frontCount = 0, rearCount = 0; + + // foreach ( var wheel in Wheels ) + // { + // if ( wheel.IsFront ) + // frontCount++; + // else + // rearCount++; + + // } + + // float frontDistribution = 0.5f + PowerDistribution * 0.5f; + + // float rearDistribution = 1 - frontDistribution; + + // frontDistribution /= frontCount; + // rearDistribution /= rearCount; + + // foreach ( var wheel in Wheels ) + // if ( wheel.IsFront ) + // wheel.DistributionFactor = frontDistribution; + // else + // wheel.DistributionFactor = rearDistribution; + //} + + //private void EngineAccelerate( float torque, float dt ) + //{ + // var inertia = 0.5f * FlyWheelMass * FlyWheelRadius * FlyWheelRadius; + // var angularAcceleration = torque / inertia; + + // flywheelVelocity += angularAcceleration * dt; + //} + + //private float GetTransmissionTorque( int gear, float minTorque, float maxTorque ) + //{ + // var torque = FlywheelRPM.Remap( MinRPM, MaxRPM, minTorque, maxTorque, true ); + // torque *= (1 - Clutch); + // torque = torque * Gears[gear] * DifferentialRatio * TransmissionEfficiency; + + // return gear == -1 ? -torque : torque; + //} + + //private void AutoGearSwitch() + //{ + // if ( ForwardSpeed < 100 && Input.Down( "Backward" ) ) + // { + // SwitchGear( -1, false ); + // return; + // } + + // var currentGear = Gear; + + // if ( currentGear < 0 && ForwardSpeed < -100 ) + // return; + + // if ( Math.Abs( avgForwardSlip ) > 10 ) + // return; + + // var gear = Math.Clamp( currentGear, 1, MaxGear ); + + // float minRPM = MinRPM, maxRPM = MaxRPM; + + + // maxRPM *= 0.98f; + + // float gearRPM; + + + // for ( int i = 1; i <= MaxGear; i++ ) + // { + // gearRPM = TransmissionToEngineRPM( i ); + + // if ( (i == 1 && gearRPM < minRPM) || (gearRPM > minRPM && gearRPM < maxRPM) ) + // { + // gear = i; + // break; + // } + // } + + // var threshold = minRPM + (maxRPM - minRPM) * (0.5 - Throttle * 0.3); + // if ( gear < currentGear && gear > currentGear - 2 && EngineRPM > threshold ) + // return; + + // SwitchGear( gear ); + //} + + //private float EngineClutch( float dt ) + //{ + // if ( !switchCD ) + // { + // inputThrottle = 0; + + // return 0; + // } + + // if ( inputHandbrake ) + // return 1; + + // var absForwardSpeed = Math.Abs( ForwardSpeed ); + + // if ( groundedCount < 1 && absForwardSpeed > 30 ) + // return 1; + + // if ( ForwardSpeed < -50 && inputBrake > 0 && Gear < 0 ) + // return 1; + + // if ( absForwardSpeed > 200 ) + // return 0; + + // return inputThrottle > 0.1f ? 0 : 1; + //} + + //private void EngineThink( float dt ) + //{ + // inputThrottle = Input.Down( "Forward" ) ? 1 : 0; + // inputBrake = Input.Down( "Backward" ) ? 1 : 0; + // inputHandbrake = Input.Down( "Jump" ); + // if ( burnout > 0 ) + // { + // SwitchGear( 1, false ); + // if ( inputThrottle < 0.1f || inputBrake < 0.1f ) + // burnout = 0; + // } + // else + // AutoGearSwitch(); + + // if ( Gear < 0 ) + // (inputBrake, inputThrottle) = (inputThrottle, inputBrake); + + // var rpm = FlywheelRPM; + + // var clutch = EngineClutch( dt ); + + // if ( inputThrottle > 0.1 && inputBrake > 0.1 && Math.Abs( ForwardSpeed ) < 50 ) + // { + // burnout = MathX.Approach( burnout, 1, dt * 2 ); + // Clutch = 0; + + // } + // else if ( inputHandbrake ) + // { + // frontBrake = 0f; + // rearBrake = 0.5f; + // Clutch = 1; + // clutch = 1; + // } + // else + // { + // if ( (Gear == -1 || Gear == 1) && inputThrottle < 0.05f && inputBrake < 0.1f && groundedCount > 1 && rpm < MinRPM * 1.2f ) + // inputBrake = 0.2f; + + // frontBrake = inputBrake * 0.5f; + // rearBrake = inputBrake * 0.5f; + // } + + // clutch = MathX.Approach( Clutch, clutch, dt * ((Gear < 2 && inputThrottle > 0.1f) ? 6 : 2) ); + + // Clutch = clutch; + + // var isRedlining = false; + // transmissionRPM = 0; + + // if ( Gear != 0 ) + // { + // transmissionRPM = TransmissionToEngineRPM( Gear ); + // transmissionRPM = Gear < 0 ? -transmissionRPM : transmissionRPM; + // rpm = (rpm * clutch) + (MathF.Max( 0, transmissionRPM ) * (1 - clutch)); + // } + // var throttle = Throttle; + + // var gearTorque = GetTransmissionTorque( Gear, MinRPMTorque, MaxRPMTorque ); + + // var availableTorque = gearTorque * throttle; + + // if ( transmissionRPM < 0 ) + // { + // availableTorque += gearTorque * 2; + // } + // else + // { + // var engineBrakeTorque = GetTransmissionTorque( Gear, EngineBrakeTorque, EngineBrakeTorque ); + + // availableTorque -= engineBrakeTorque * (1 - throttle) * 0.5f; + // } + + // var maxRPM = MaxRPM; + + // if ( rpm < MinRPM ) + // { + // rpm = MinRPM; + // } + // else if ( rpm > maxRPM ) + // { + + // if ( rpm > maxRPM * 1.2f ) + // availableTorque = 0; + + // rpm = maxRPM; + + // if ( Gear != MaxGear || groundedCount < Wheels.Count ) + // isRedlining = true; + // } + + // FlywheelRPM = Math.Clamp( rpm, 0, maxRPM ); + + // if ( burnout > 0 ) + // availableTorque += availableTorque * burnout * 0.1f; + + // var front = 0.5f + PowerDistribution * 0.5f; + // var rear = 1 - front; + + // availableFrontTorque = availableTorque * front; + // availableRearTorque = availableTorque * rear; + + // throttle = MathX.Approach( throttle, inputThrottle, dt * 4 ); + + + // EngineAccelerate( FlywheelFriction + FlywheelTorque * throttle, dt ); + + // Throttle = throttle; + + // IsRedlining = (isRedlining && inputThrottle > 0); + //} + } diff --git a/Code/Car/VeloXCar.Steering.cs b/Code/Car/VeloXCar.Steering.cs index 818c588..2088a0a 100644 --- a/Code/Car/VeloXCar.Steering.cs +++ b/Code/Car/VeloXCar.Steering.cs @@ -22,7 +22,7 @@ public partial class VeloXCar var inputSteer = Input.AnalogMove.y; var absInputSteer = Math.Abs( inputSteer ); - var sideSlip = Math.Clamp( avgSideSlip, -1, 1 ); + var sideSlip = Math.Clamp( 0, -1, 1 ); var steerConeFactor = Math.Clamp( TotalSpeed / SteerConeMaxSpeed, 0, 1 ); var steerCone = 1 - steerConeFactor * (1 - SteerConeMaxAngle); diff --git a/Code/Car/VeloXCar.Wheel.cs b/Code/Car/VeloXCar.Wheel.cs index 5b9f403..a54f8aa 100644 --- a/Code/Car/VeloXCar.Wheel.cs +++ b/Code/Car/VeloXCar.Wheel.cs @@ -2,17 +2,11 @@ public partial class VeloXCar { - + private float avgSideSlip; + private float avgPoweredRPM; + private float avgForwardSlip; private void WheelThink( in float dt ) { - var maxRPM = GetTransmissionMaxRPM( Gear ); - - - var frontTorque = availableFrontTorque; - var rearTorque = availableRearTorque; - - - groundedCount = 0; float avgRPM = 0, totalSideSlip = 0, totalForwardSlip = 0; foreach ( var w in Wheels ) @@ -24,20 +18,8 @@ public partial class VeloXCar var rpm = w.RPM; avgRPM += rpm * w.DistributionFactor; - - w.Torque = w.DistributionFactor * (w.IsFront ? frontTorque : rearTorque); - w.Brake = w.IsFront ? frontBrake : rearBrake; - - if ( inputHandbrake && !w.IsFront ) - w.RPM = 0; - - if ( rpm > maxRPM ) - w.RPM = maxRPM; - - if ( w.IsOnGround ) - groundedCount++; - } + avgPoweredRPM = avgRPM; avgSideSlip = totalSideSlip / Wheels.Count; avgForwardSlip = totalForwardSlip / Wheels.Count; diff --git a/Code/Car/VeloXCar.cs b/Code/Car/VeloXCar.cs index 6bbb63d..faf7def 100644 --- a/Code/Car/VeloXCar.cs +++ b/Code/Car/VeloXCar.cs @@ -10,27 +10,27 @@ public partial class VeloXCar : VeloXBase protected override void OnStart() { base.OnStart(); - StreamPlayer = new( Stream ); - if ( IsDriver ) - { - UpdateGearList(); - UpdatePowerDistribution(); - } + //StreamPlayer = new( Stream ); + //if ( IsDriver ) + //{ + // UpdateGearList(); + // UpdatePowerDistribution(); + //} } protected override void OnUpdate() { base.OnUpdate(); - if ( StreamPlayer is not null ) - { + //if ( StreamPlayer is not null ) + //{ - StreamPlayer.Throttle = Throttle; - StreamPlayer.RPMPercent = RPMPercent; - StreamPlayer.EngineState = EngineState; - StreamPlayer.IsRedlining = IsRedlining; + // StreamPlayer.Throttle = Throttle; + // StreamPlayer.RPMPercent = RPMPercent; + // StreamPlayer.EngineState = EngineState; + // StreamPlayer.IsRedlining = IsRedlining; - StreamPlayer.Update( Time.Delta, WorldPosition ); - } + // StreamPlayer.Update( Time.Delta, WorldPosition ); + //} } protected override void OnFixedUpdate() @@ -40,9 +40,10 @@ public partial class VeloXCar : VeloXBase base.OnFixedUpdate(); - Brake = Math.Clamp( frontBrake + rearBrake + (Input.Down( "Jump" ) ? 1 : 0), 0, 1 ); + Brake = Math.Clamp( (Input.Down( "Jump" ) ? 1 : 0), 0, 1 ); var dt = Time.Delta; + EngineThink( dt ); WheelThink( dt ); UpdateSteering( dt );