using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// GAME 1303 Tier 4 — Crates, cracked walls, pots. Takes damage like anything else and
/// shatters. The Magnet, Stardust, Spark of Corruption.
///
/// SETUP
/// 1. Sprite + Collider2D (solid, so it blocks) + Health (Max 2, Invulnerability 0,
/// Destroy On Death OFF — this script handles it) + this script.
/// 2. If the player attacks with Tier 2 Hitboxes: add a child with a trigger collider +
/// Hurtbox (Team = Neutral) so any team can hit it. DamageOnContact from a thrown
/// MetalObject or a Dash-through hitbox also works.
/// 3. Min Damage To Break: 0 = anything chips it; 3 = only a strong hit (charged launch,
/// thrown metal) breaks it — weak hits are ignored. Good for "you need the Sorcerer
/// to break this wall" gating in Spark of Corruption.
/// 4. Loot: drop a Collectible prefab (or several). Debris: a particle or chunk prefab.
/// 5. Cracked Sprite: swaps in when health is below half — visual feedback.
/// </summary>
[RequireComponent(typeof(Health))]
public class Breakable : MonoBehaviour
{
public int minDamageToBreak = 0;
[Header("Visuals")]
public Sprite crackedSprite;
public GameObject debrisPrefab;
public string breakSfx = "break";
public string hitSfx = "thud";
[Header("Loot")]
public GameObject[] lootPrefabs;
public int lootCount = 1;
public float lootScatter = 3f;
public UnityEvent OnBroken;
private Health health;
private SpriteRenderer sr;
private int lastHealth;
void Awake()
{
health = GetComponent<Health>();
health.destroyOnDeath = false;
health.invulnerabilityTime = 0f;
sr = GetComponentInChildren<SpriteRenderer>();
lastHealth = health.maxHealth;
health.OnHealthChanged.AddListener(OnHealthChanged);
health.OnDied.AddListener(Break);
}
void OnHealthChanged(int current, int max)
{
int taken = lastHealth - current;
lastHealth = current;
if (taken <= 0 || current <= 0) return;
// Too weak? Undo the damage.
if (minDamageToBreak > 0 && taken < minDamageToBreak)
{
health.Heal(taken);
lastHealth = health.CurrentHealth;
if (!string.IsNullOrEmpty(hitSfx)) AudioManager.Instance?.PlaySFX(hitSfx);
return;
}
if (!string.IsNullOrEmpty(hitSfx)) AudioManager.Instance?.PlaySFX(hitSfx);
if (crackedSprite != null && sr != null && current <= max / 2) sr.sprite = crackedSprite;
}
public void Break()
{
if (!string.IsNullOrEmpty(breakSfx)) AudioManager.Instance?.PlaySFX(breakSfx);
if (debrisPrefab != null) Instantiate(debrisPrefab, transform.position, Quaternion.identity);
if (lootPrefabs != null && lootPrefabs.Length > 0)
for (int i = 0; i < lootCount; i++)
{
var prefab = lootPrefabs[Random.Range(0, lootPrefabs.Length)];
if (prefab == null) continue;
var loot = Instantiate(prefab, transform.position, Quaternion.identity);
var rb = loot.GetComponent<Rigidbody2D>();
if (rb != null) rb.AddForce(new Vector2(Random.Range(-1f, 1f), 1f).normalized * lootScatter, ForceMode2D.Impulse);
}
OnBroken?.Invoke();
Destroy(gameObject);
}
}