fix: clean gitignore for Godot C#

This commit is contained in:
maxwes08
2026-04-17 12:38:11 +02:00
commit 3ac0b6b866
23 changed files with 841 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
using System;
public class Engine : RotatingComponent
{
public double ThrottlePosition { get; set; }
public double CurrentPower { get; private set; }
public double CombustionPower { get; private set; }
public int CylinderCount { get; private set; }
public EngineControlUnit Ecu = new EngineControlUnit();
// Friction
private const double _baseFriction = 12.0; // Seals, oil pump, valvetrain (Nm)
private const double _linearFriction = 0.025; // Hydrodynamic bearing drag (Nm/(rad/s))
private const double _quadraticFriction = 0.00002; // Windage & churning (Nm/(rad/s)²)
// Engine geometry
private double _displacementCC;
private double _compressionRatio;
// Volumetric efficiency tuning now in rad/s
public double VolumetricEfficiencyPeak { get; set; } = 1.15; // was 1.10
public double AngularVelocityForVEPeak { get; set; } = 550.0; // 5250 RPM (rad/s = 550)
public double AngularVelocityForVEMin { get; set; } = 800.0; // 7639 RPM
public double VEminAtRedline { get; set; } = 0.85; // much higher at redline
// Physics constants
private const double ATM_PRESSURE_KPA = 101.3;
private const double AIR_DENSITY_KG_PER_M3 = 1.225;
private const double FUEL_HEAT_VALUE_J_PER_KG = 43e6;
private const double STOICHIOMETRIC_AIR_FUEL_RATIO = 14.7;
public Engine(double inertia, int cylinders, double displacementCC, double compressionRatio)
{
CylinderCount = cylinders;
_displacementCC = displacementCC;
_compressionRatio = compressionRatio;
MomentOfInertia = inertia;
AngularVelocity = 100; // rad/s (~955 RPM)
}
public override void Update(double dt)
{
Ecu.Update(dt, this);
ApplyThrottleTorque();
ApplyFrictionTorque();
CurrentPower = AccumulatedTorque * AngularVelocity;
base.Update(dt);
}
private double ComputeIndicatedTorque()
{
double w = AngularVelocity; // rad/s
double throttle = Math.Clamp(ThrottlePosition, 0.0, 1.0);
// Volumetric Efficiency (WOT) as function of w (rad/s)
double veWOT;
if (w <= AngularVelocityForVEPeak)
{
// Start at a realistic 0.75 at zero RPM, peaking at your target
double t = w / AngularVelocityForVEPeak;
veWOT = 0.75 + (VolumetricEfficiencyPeak - 0.75) * t * (2 - t);
}
else
{
// Linear drop from VE_peak to VEminAtRedline
double t = (w - AngularVelocityForVEPeak) / (AngularVelocityForVEMin - AngularVelocityForVEPeak);
t = Math.Clamp(t, 0.0, 1.0);
veWOT = VolumetricEfficiencyPeak - t * (VolumetricEfficiencyPeak - VEminAtRedline);
}
veWOT = Math.Clamp(veWOT, 0.25, VolumetricEfficiencyPeak);
// Intake loss
double maxEngineDemandSpeed = 700.0; // rad/s, roughly 6700 RPM
double throttleArea = Math.Pow(throttle, 1.5);
double engineDemand = (w / maxEngineDemandSpeed) * veWOT;
const double intakeResistance = 0.03; // was 0.5 now physically realistic
double mapFraction = throttleArea / (throttleArea + intakeResistance * engineDemand);
if (throttle == 0) mapFraction = 0;
double manifoldPressureKpa = ATM_PRESSURE_KPA * mapFraction;
manifoldPressureKpa = Math.Clamp(manifoldPressureKpa, 0, ATM_PRESSURE_KPA);
double veActual = veWOT * (manifoldPressureKpa / ATM_PRESSURE_KPA);
// Exhaust loss (backpressure)
double exhaustBackpressureKpa = 2.0e-5 * w * w;
double exhaustLossFactor = 1.0 - Math.Min(0.25, exhaustBackpressureKpa / ATM_PRESSURE_KPA);
// Air & fuel mass per cycle
double displacementM3 = _displacementCC * 1e-6;
double airMassPerCycleKg = veActual * AIR_DENSITY_KG_PER_M3 * displacementM3;
double fuelMassPerCycleKg = airMassPerCycleKg / STOICHIOMETRIC_AIR_FUEL_RATIO;
double energyPerCycleJ = fuelMassPerCycleKg * FUEL_HEAT_VALUE_J_PER_KG;
// Thermal efficiency
double gamma = 1.4;
double ottoEfficiency = 1.0 - 1.0 / Math.Pow(_compressionRatio, gamma - 1.0);
double thermalEfficiency = 0.65 * ottoEfficiency;
double workPerCycleJ = energyPerCycleJ * thermalEfficiency * exhaustLossFactor;
double indicatedTorque = workPerCycleJ / (4.0 * Math.PI);
indicatedTorque = Math.Min(600.0, Math.Max(0.0, indicatedTorque));
return indicatedTorque;
}
public void ApplyThrottleTorque()
{
double torque = ComputeIndicatedTorque();
CombustionPower = torque * AngularVelocity;
ApplyTorque(torque);
}
public void ApplyFrictionTorque()
{
// Friction uses angular velocity (rad/s) directly
double w = AngularVelocity;
double frictionMag = _baseFriction
+ _linearFriction * Math.Abs(w)
+ _quadraticFriction * w * w;
double frictionTorque = -Math.Sign(w) * frictionMag;
ApplyTorque(frictionTorque);
}
}

View File

@@ -0,0 +1 @@
uid://c3gg5mg8rjw50

View File

@@ -0,0 +1,48 @@
using System;
public class EngineControlUnit
{
public double Throttle;
public bool IsInNeutral = true;
private const double _revLimit = 7000;
private const double _idleRpm = 800;
private const double _idleSensitivity = 1e-2;
private const double _throttleSensitivity = 20;
private const double _neutralThrottleLimit = 0.2;
private double _idlePosition = 0;
private double _targetThrottle = 0;
private double _currentThrottle = 0;
public EngineControlUnit()
{
}
public void Update(double dt, Engine engine)
{
if (engine.RPM > _revLimit)
{
engine.ThrottlePosition = 0; return;
}
_targetThrottle = Math.Clamp(GetIdleThrottle(dt, engine.RPM) + Throttle, 0, 1);
_currentThrottle = Util.Lerp(_currentThrottle, _targetThrottle, dt * _throttleSensitivity);
if (IsInNeutral) _currentThrottle = Math.Min(_currentThrottle, _neutralThrottleLimit);
engine.ThrottlePosition = _currentThrottle;
}
public double GetIdleThrottle(double dt, double rpm)
{
if (rpm > _idleRpm) return 0;
double diff = rpm - _idleRpm;
_idlePosition = Math.Clamp(_idlePosition - (diff * _idleSensitivity * dt), 0, 1.0);
return _idlePosition;
}
}

View File

@@ -0,0 +1 @@
uid://0k3uqu06s0im