velox/Code/Base/Powertrain/PowertrainComponent.cs
2025-11-06 12:13:30 +07:00

182 lines
4.4 KiB
C#

using System;
using Sandbox;
namespace VeloX;
public abstract class PowertrainComponent : Component
{
[Property] public VeloXBase Controller;
/// <summary>
/// Name of the component. Only unique names should be used on the same vehicle.
/// </summary>
[Property] public string Name { get; set; }
/// <summary>
/// Angular inertia of the component. Higher inertia value will result in a powertrain that is slower to spin up, but
/// also slower to spin down. Too high values will result in (apparent) sluggish response while too low values will
/// result in vehicle being easy to stall and possible powertrain instability / glitches.
/// </summary>
[Property, Range( 0.0002f, 2f )] public float Inertia { get; set; } = 0.05f;
[Property, ReadOnly] public float InputTorque;
[Property, ReadOnly] public float OutputTorque;
public float InputAngularVelocity;
public float OutputAngularVelocity;
public float InputInertia;
public float OutputInertia;
/// <summary>
/// Input component. Set automatically.
/// </summary>
[Property]
public PowertrainComponent Input
{
get => _input;
set
{
if ( value == null || value == this )
{
_input = null;
InputNameHash = 0;
return;
}
_input = value;
InputNameHash = _input.GetHashCode();
}
}
protected PowertrainComponent _input;
public int InputNameHash;
/// <summary>
/// The PowertrainComponent this component will output to.
/// </summary>
[Property]
public PowertrainComponent Output
{
get { return _output; }
set
{
if ( value == this )
{
Log.Warning( $"{Name}: PowertrainComponent Output can not be self." );
OutputNameHash = 0;
_output = null;
return;
}
_output = value;
if ( _output != null )
{
_output.Input = this;
OutputNameHash = _output.GetHashCode();
}
else
{
OutputNameHash = 0;
}
}
}
protected PowertrainComponent _output;
public int OutputNameHash { get; private set; }
/// <summary>
/// Input shaft RPM of component.
/// </summary>
[Property, ReadOnly]
public float InputRPM => AngularVelocityToRPM( InputAngularVelocity );
/// <summary>
/// Output shaft RPM of component.
/// </summary>
[Property, ReadOnly]
public float OutputRPM => AngularVelocityToRPM( OutputAngularVelocity );
public virtual float QueryAngularVelocity( float angularVelocity, float dt )
{
InputAngularVelocity = angularVelocity;
if ( OutputNameHash == 0 )
{
return angularVelocity;
}
OutputAngularVelocity = angularVelocity;
return _output.QueryAngularVelocity( OutputAngularVelocity, dt );
}
public virtual float QueryInertia()
{
if ( OutputNameHash == 0 )
return Inertia;
float Ii = Inertia;
float Ia = _output.QueryInertia();
return Ii + Ia;
}
public virtual float ForwardStep( float torque, float inertiaSum, float dt )
{
InputTorque = torque;
InputInertia = inertiaSum;
if ( OutputNameHash == 0 )
return torque;
OutputTorque = InputTorque;
OutputInertia = inertiaSum + Inertia;
return _output.ForwardStep( OutputTorque, OutputInertia, dt );
}
public static float TorqueToPowerInKW( in float angularVelocity, in float torque )
{
// Power (W) = Torque (Nm) * Angular Velocity (rad/s)
float powerInWatts = torque * angularVelocity;
// Convert power from watts to kilowatts
float powerInKW = powerInWatts / 1000f;
return powerInKW;
}
public static float PowerInKWToTorque( in float angularVelocity, in float powerInKW )
{
// Convert power from kilowatts to watts
float powerInWatts = powerInKW * 1000f;
// Torque (Nm) = Power (W) / Angular Velocity (rad/s)
float absAngVel = Math.Abs( angularVelocity );
float clampedAngularVelocity = (absAngVel > -1f && absAngVel < 1f) ? 1f : angularVelocity;
float torque = powerInWatts / clampedAngularVelocity;
return torque;
}
public float CalculateOutputPowerInKW()
{
return GetPowerInKW( OutputTorque, OutputAngularVelocity );
}
public static float GetPowerInKW( in float torque, in float angularVelocity )
{
// Power (W) = Torque (Nm) * Angular Velocity (rad/s)
float powerInWatts = torque * angularVelocity;
// Convert power from watts to kilowatts
float powerInKW = powerInWatts / 1000f;
return powerInKW;
}
public static float AngularVelocityToRPM( float angularVelocity ) => angularVelocity * 9.5492965855137f;
public static float RPMToAngularVelocity( float RPM ) => RPM * 0.10471975511966f;
}