Files
2026-02-16 18:32:48 +01:00

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--; }
}
}