using UnityEngine;
public class MainEngine : MonoBehaviour
{
[Header("References")]
public FuelTank fuelTank; // Reference to the fuel tank supplying this engine
public Altimeter altimeter; // Reference to the altimeter for gravity calculations
[Header("Engine Settings")]
public float maxThrust = 1000f; // kN
public float Isp = 300f; // seconds
public float throttleRampTime = 2f; // seconds to reach full throttle
public float minStartupFlow = 0.05f; // minimum fraction of max flow to maintain ignition
public AnimationCurve throttleCurve = AnimationCurve.Linear(0, 0, 1, 1);
[Header("Efficiency Settings")]
[Range(0f, 1f)] public float engineEfficiency = 1f; // e.g., reduce if engine is hot or damaged
[Header("Engine Status")]
public bool engineOnline = false; // true if engine is running
public bool engineIgnited = false; // true if ignition completed
public bool restartable = true; // if false, engine cannot restart once shut down
[Range(0f, 1f)]public float throttleInput = 0f; // 0-1 input from pilot
public float thrust = 0f; // kN
public float fuelFlowRate = 0f; // kg/s
private float effectiveThrottle = 0f; // ramped throttle for smooth startup/shutdown
private float startupTimer = 0f;
private bool everStarted = false; // tracks if engine has ever been started
private float postIgnitionTimer = 0f; // timer for post-ignition grace period
private const float postIgnitionGrace = 0.5f; // seconds to allow ramp-up after ignition
private float g = 9.81f; // local gravity from altimeter
void Update()
{
HandleEngineState();
UpdateThrottle();
// Only calculate thrust and fuel flow if engine is ignited
if (engineOnline && engineIgnited)
{
// Update post-ignition timer
if (postIgnitionTimer < postIgnitionGrace)
postIgnitionTimer += Time.deltaTime;
CalculateThrustAndFuelFlow();
}
else
{
thrust = 0f;
fuelFlowRate = 0f;
postIgnitionTimer = 0f;
}
}
///
/// Handles startup, shutdown, and engine cutout.
///
private void HandleEngineState()
{
g = (float)altimeter.gh; // Update local gravity from altimeter each frame
// Check if engine is offline and restartable conditions
if (!engineOnline)
{
effectiveThrottle = Mathf.MoveTowards(effectiveThrottle, 0f, Time.deltaTime / throttleRampTime);
thrust = 0f;
fuelFlowRate = 0f;
// Mark engine as having been started
if (engineIgnited) everStarted = true;
if (engineIgnited)
Debug.Log("[MainEngine] Engine shutdown: engineOnline set to false.");
engineIgnited = false;
return;
}
// Prevent restart if engine is not restartable and was previously started
if (!restartable && everStarted)
{
Debug.Log("[MainEngine] Engine shutdown: not restartable and already started.");
engineOnline = false;
effectiveThrottle = 0f;
thrust = 0f;
fuelFlowRate = 0f;
engineIgnited = false;
return;
}
// Engine is commanded online
if (!engineIgnited)
{
// Startup delay / ignition sequence
startupTimer += Time.deltaTime;
if (startupTimer >= throttleRampTime)
{
engineIgnited = true;
startupTimer = 0f;
postIgnitionTimer = 0f; // reset grace period timer
Debug.Log("[MainEngine] Engine ignition complete.");
}
else
{
// Slowly ramp effective throttle during startup
effectiveThrottle = Mathf.Lerp(0f, throttleInput, startupTimer / throttleRampTime);
}
}
}
///
/// Smooths throttle input over time (fuel ramping)
///
private void UpdateThrottle()
{
if (!engineOnline || !engineIgnited)
return;
// Smooth throttle changes to avoid instant jumps
effectiveThrottle = Mathf.MoveTowards(effectiveThrottle, throttleInput, Time.deltaTime / throttleRampTime);
}
///
/// Calculates thrust and fuel flow based on current throttle and efficiency
///
private void CalculateThrustAndFuelFlow()
{
// Base thrust from throttle curve and max thrust
thrust = throttleCurve.Evaluate(effectiveThrottle) * maxThrust * engineEfficiency;
// Fuel flow based on thrust and Isp
fuelFlowRate = thrust / (Isp * g);
// Request fuel from the tank if assigned
if (fuelTank != null)
{
float fuelRequested = fuelFlowRate * Time.deltaTime;
float fuelProvided = fuelTank.RequestFuel(fuelRequested);
if (fuelProvided < fuelRequested)
{
Debug.Log($"[MainEngine] Engine flameout: insufficient fuel (requested {fuelRequested:F3}, got {fuelProvided:F3}).");
engineIgnited = false;
effectiveThrottle = 0f;
thrust = 0f;
fuelFlowRate = 0f;
return;
}
}
// Only check for flameout if engine is fully ignited and grace period has passed
float nominalFlow = maxThrust / (Isp * g);
if (engineIgnited && postIgnitionTimer >= postIgnitionGrace && (fuelFlowRate / nominalFlow) < minStartupFlow)
{
Debug.Log($"[MainEngine] Engine flameout: fuel flow below minimum ({fuelFlowRate / nominalFlow:F3} < {minStartupFlow}).");
engineIgnited = false; // engine flameout
effectiveThrottle = 0f;
thrust = 0f;
fuelFlowRate = 0f;
}
}
///
/// Call to turn the engine on
///
public void StartEngine()
{
if (!engineOnline)
{
// Prevent starting if not restartable and already started
if (!restartable && everStarted)
{
Debug.Log("[MainEngine] StartEngine() called but engine is not restartable and has already started.");
return;
}
Debug.Log("[MainEngine] Engine start command received.");
engineOnline = true;
startupTimer = 0f;
}
}
///
/// Call to turn the engine off
///
public void ShutdownEngine()
{
Debug.Log("[MainEngine] Engine shutdown command received.");
engineOnline = false;
engineIgnited = false;
}
public void SetThrottle(float value)
{
throttleInput = Mathf.Clamp01(value);
}
}