102 lines
3.1 KiB
C#
102 lines
3.1 KiB
C#
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 );
|
|
|
|
}
|
|
|
|
}
|