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 );