new powertrain смерть чуркам
This commit is contained in:
parent
ba9afba4d1
commit
964b46e1c5
49
Code/Base/Powertrain/Clutch.cs
Normal file
49
Code/Base/Powertrain/Clutch.cs
Normal file
@ -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 );
|
||||
}
|
||||
}
|
||||
79
Code/Base/Powertrain/Differential/BaseDifferential.cs
Normal file
79
Code/Base/Powertrain/Differential/BaseDifferential.cs
Normal file
@ -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;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The PowertrainComponent this component will output to.
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
|
||||
}
|
||||
13
Code/Base/Powertrain/Differential/OpenDifferential.cs
Normal file
13
Code/Base/Powertrain/Differential/OpenDifferential.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
101
Code/Base/Powertrain/Engine.cs
Normal file
101
Code/Base/Powertrain/Engine.cs
Normal file
@ -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 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
45
Code/Base/Powertrain/Gearbox/BaseGearbox.cs
Normal file
45
Code/Base/Powertrain/Gearbox/BaseGearbox.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
52
Code/Base/Powertrain/Gearbox/ManualGearbox.cs
Normal file
52
Code/Base/Powertrain/Gearbox/ManualGearbox.cs
Normal file
@ -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 );
|
||||
}
|
||||
}
|
||||
29
Code/Base/Powertrain/PowerWheel.cs
Normal file
29
Code/Base/Powertrain/PowerWheel.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
100
Code/Base/Powertrain/PowertrainComponent.cs
Normal file
100
Code/Base/Powertrain/PowertrainComponent.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using Sandbox;
|
||||
using System;
|
||||
|
||||
namespace VeloX.Powertrain;
|
||||
|
||||
public abstract class PowertrainComponent : Component
|
||||
{
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
Vehicle ??= Components.Get<VeloXBase>( 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;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Input component. Set automatically.
|
||||
/// </summary>
|
||||
[Property]
|
||||
public PowertrainComponent Input
|
||||
{
|
||||
get => _input;
|
||||
set
|
||||
{
|
||||
if ( value == null || value == this )
|
||||
{
|
||||
_input = null;
|
||||
return;
|
||||
}
|
||||
|
||||
_input = value;
|
||||
}
|
||||
}
|
||||
|
||||
private PowertrainComponent _input;
|
||||
public int InputNameHash;
|
||||
|
||||
/// <summary>
|
||||
/// The PowertrainComponent this component will output to.
|
||||
/// </summary>
|
||||
[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 );
|
||||
}
|
||||
}
|
||||
@ -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 );
|
||||
}
|
||||
|
||||
@ -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; }
|
||||
@ -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()
|
||||
{
|
||||
|
||||
@ -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<int, float> 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<int, float> 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);
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 );
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user