using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
/// <summary>
/// GAME 1303 Tier 3 — A runaway hot air balloon. Replaces PlayerController2D for Hot Air.
///
/// Feel: the balloon always sinks slowly. Hold Jump to fire the burner — it pushes you up
/// and burns fuel. Left/Right gives a weak nudge (a balloon isn't a plane). Wind zones
/// shove you around. With no fuel you just drift down.
///
/// SETUP
/// 1. Balloon: Sprite + Rigidbody2D (Gravity Scale 0.3, Linear Damping 1, Angular
/// Damping 2, DON'T freeze rotation — a little tilt looks great) + Collider2D +
/// Health + FuelSystem + this script + PlayerInput (Send Messages). Tag "Player".
/// 2. Optional Basket child with the collider offset low, so the balloon tilts realistically.
/// 3. Burner Force vs gravity: with Gravity Scale 0.3 and Rigidbody mass 1, a Burner
/// Force of 8 gives a nice slow climb. Tune Sink Speed Max so it never plummets.
/// 4. Pair with GrapplingHook (Aim = Mouse) on the same object.
/// 5. Burner Particles: drag a Particle System; it plays while burning.
///
/// Checkpoints, Health, DamageOnContact, RespawnManager all work unchanged — the
/// RespawnManager looks for PlayerController2D but tolerates its absence.
/// </summary>
[RequireComponent(typeof(Rigidbody2D))]
public class BalloonController : MonoBehaviour
{
[Header("Burner")]
public float burnerForce = 8f;
public float fuelPerSecond = 10f;
public float maxRiseSpeed = 5f;
[Header("Drift")]
public float horizontalForce = 3f;
public float maxHorizontalSpeed = 4f;
public float maxSinkSpeed = 3f;
[Tooltip("Torque from horizontal input so the balloon leans into the move.")]
public float leanTorque = 0.5f;
[Tooltip("Spring that rights the balloon back to upright.")]
public float uprightSpring = 2f;
[Header("References")]
public FuelSystem fuel;
public ParticleSystem burnerParticles;
[Header("Events")]
public UnityEvent OnBurnerStarted;
public UnityEvent OnBurnerStopped;
public bool IsBurning { get; private set; }
public bool InputEnabled { get; set; } = true;
private Rigidbody2D rb;
private Vector2 moveInput;
private bool burnerHeld;
void Awake()
{
rb = GetComponent<Rigidbody2D>();
if (fuel == null) fuel = GetComponent<FuelSystem>();
}
void OnMove(InputValue v) { moveInput = v.Get<Vector2>(); }
void OnJump(InputValue v) { burnerHeld = v.isPressed; }
void FixedUpdate()
{
bool canBurn = InputEnabled && burnerHeld && (fuel == null || !fuel.IsEmpty);
// Burner
if (canBurn)
{
if (fuel != null) fuel.Consume(fuelPerSecond * Time.fixedDeltaTime);
if (rb.linearVelocity.y < maxRiseSpeed) rb.AddForce(Vector2.up * burnerForce);
}
SetBurning(canBurn);
// Horizontal nudge
if (InputEnabled && Mathf.Abs(moveInput.x) > 0.1f && Mathf.Abs(rb.linearVelocity.x) < maxHorizontalSpeed)
rb.AddForce(Vector2.right * moveInput.x * horizontalForce);
// Clamp sink speed
if (rb.linearVelocity.y < -maxSinkSpeed)
rb.linearVelocity = new Vector2(rb.linearVelocity.x, -maxSinkSpeed);
// Lean + self-righting
if (rb.freezeRotation == false)
{
rb.AddTorque(-moveInput.x * leanTorque);
float angle = Mathf.DeltaAngle(rb.rotation, 0f);
rb.AddTorque(angle * uprightSpring * Time.fixedDeltaTime);
}
}
void SetBurning(bool on)
{
if (on == IsBurning) return;
IsBurning = on;
if (burnerParticles != null) { if (on) burnerParticles.Play(); else burnerParticles.Stop(); }
if (on) OnBurnerStarted?.Invoke(); else OnBurnerStopped?.Invoke();
}
/// <summary>RespawnManager-friendly reset.</summary>
public void ResetMotion()
{
rb.linearVelocity = Vector2.zero;
rb.angularVelocity = 0f;
rb.rotation = 0f;
}
}