126 lines
4.5 KiB
C#
126 lines
4.5 KiB
C#
using Car_simulation.Core.Physics;
|
|
|
|
namespace Car_simulation.Core.Components
|
|
{
|
|
public class Drivetrain : ICarComponent
|
|
{
|
|
public Engine Engine { get; private set; }
|
|
public WheelSystem WheelSystem { get; private set; }
|
|
|
|
private int _currentGear = 1;
|
|
public float[] GearRatios { get; set; } = { 3.8f, 2.5f, 1.8f, 1.3f, 1.0f, 0.8f, 0.65f };
|
|
public float FinalDriveRatio { get; set; } = 4.0f;
|
|
public float Efficiency { get; set; } = 0.95f;
|
|
public float ClutchEngagement { get; set; } = 0f;
|
|
|
|
public float MaxClutchTorque { get; set; } = 400f;
|
|
public float ClutchStiffness { get; set; } = 50f;
|
|
|
|
public float ClutchTorque { get; private set; }
|
|
public float TransmittedPower { get; private set; }
|
|
public float ClutchSlipRatio { get; private set; }
|
|
|
|
public Drivetrain(Engine engine, WheelSystem wheelSystem)
|
|
{
|
|
Engine = engine;
|
|
WheelSystem = wheelSystem;
|
|
}
|
|
|
|
public void Update(float deltaTime)
|
|
{
|
|
if (ClutchEngagement <= 0.01f || TotalRatio == 0)
|
|
{
|
|
ClutchTorque = 0;
|
|
TransmittedPower = 0;
|
|
ClutchSlipRatio = 1f;
|
|
return;
|
|
}
|
|
|
|
float expectedWheelOmega = Engine.AngularVelocity / TotalRatio;
|
|
float actualWheelOmega = WheelSystem.AngularVelocity;
|
|
float omegaDifference = actualWheelOmega - expectedWheelOmega;
|
|
|
|
float maxClutchTorque = MaxClutchTorque * ClutchEngagement;
|
|
float desiredTorque = -omegaDifference * ClutchStiffness;
|
|
desiredTorque = Math.Clamp(desiredTorque, -maxClutchTorque, maxClutchTorque);
|
|
|
|
if (desiredTorque > 0)
|
|
{
|
|
float engineTorque = Engine.GetTorqueOutput() * Engine.GetActualThrottle();
|
|
float maxEngineTorqueAtWheels = engineTorque * TotalRatio * Efficiency;
|
|
desiredTorque = Math.Min(desiredTorque, maxEngineTorqueAtWheels);
|
|
}
|
|
|
|
ClutchTorque = desiredTorque;
|
|
|
|
float energyTransferred = 0f;
|
|
|
|
if (omegaDifference > 0.01f) // Wheels → Engine
|
|
{
|
|
float power = ClutchTorque * Engine.AngularVelocity;
|
|
energyTransferred = power * deltaTime;
|
|
float wheelEnergyLoss = Math.Abs(energyTransferred);
|
|
float engineEnergyGain = wheelEnergyLoss * Efficiency;
|
|
|
|
WheelSystem.TotalEnergy -= wheelEnergyLoss;
|
|
Engine.FlywheelEnergy += engineEnergyGain;
|
|
}
|
|
else if (omegaDifference < -0.01f) // Engine → Wheels
|
|
{
|
|
float power = -ClutchTorque * Engine.AngularVelocity;
|
|
energyTransferred = power * deltaTime;
|
|
float engineEnergyLoss = Math.Abs(energyTransferred);
|
|
float wheelEnergyGain = engineEnergyLoss * Efficiency;
|
|
|
|
Engine.FlywheelEnergy -= engineEnergyLoss;
|
|
WheelSystem.TotalEnergy += wheelEnergyGain;
|
|
}
|
|
|
|
TransmittedPower = energyTransferred / deltaTime;
|
|
|
|
if (maxClutchTorque > 0)
|
|
{
|
|
float torqueRatio = Math.Abs(ClutchTorque) / maxClutchTorque;
|
|
ClutchSlipRatio = torqueRatio;
|
|
}
|
|
else
|
|
{
|
|
ClutchSlipRatio = 1f;
|
|
}
|
|
}
|
|
|
|
public float GearRatio => GetCurrentGearRatio();
|
|
public float TotalRatio => GearRatio * FinalDriveRatio;
|
|
|
|
private float GetCurrentGearRatio()
|
|
{
|
|
if (_currentGear == 0) return 0f;
|
|
if (_currentGear == -1) return -3.5f;
|
|
if (_currentGear > 0 && _currentGear <= GearRatios.Length)
|
|
return GearRatios[_currentGear - 1];
|
|
return 0f;
|
|
}
|
|
|
|
public float GetSpeedDifferenceRPM()
|
|
{
|
|
float expectedWheelOmega = Engine.AngularVelocity / TotalRatio;
|
|
float actualWheelOmega = WheelSystem.AngularVelocity;
|
|
return (actualWheelOmega - expectedWheelOmega) * PhysicsUtil.RAD_PER_SEC_TO_RPM;
|
|
}
|
|
|
|
public string GetCurrentGearName()
|
|
{
|
|
return _currentGear switch
|
|
{
|
|
-1 => "R",
|
|
0 => "N",
|
|
_ => _currentGear.ToString()
|
|
};
|
|
}
|
|
|
|
public float GetClutchSlipPercent() => ClutchSlipRatio * 100f;
|
|
|
|
public void GearUp() { if (_currentGear < GearRatios.Length) _currentGear++; }
|
|
public void GearDown() { if (_currentGear > 1) _currentGear--; }
|
|
}
|
|
} |