new powertrain смерть чуркам
This commit is contained in:
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 );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user