using UnityEngine; using UnityEngine.UI; using Ashwild.Player; namespace Ashwild.UI { public class DeathScreen : MonoBehaviour { [Header("Timing")] [SerializeField] private float fadeDelay = 0.8f; [SerializeField] private float fadeDuration = 1.5f; [SerializeField] private float respawnDelay = 1f; [Header("UI")] [SerializeField] private Image fadeOverlay; private PlayerLifecycle playerLifecycle; private bool isDying; private float timer; private enum Phase { Wait, Fade, Black, Done } private Phase phase; private bool bound; /// /// Waits for the networked local player to spawn before hooking onto its death event. /// private void OnEnable() { PlayerEvents.LocalPlayerSpawned += HandleLocalPlayerSpawned; } /// /// Unsubscribes — mirrors OnEnable exactly. /// private void OnDisable() { PlayerEvents.LocalPlayerSpawned -= HandleLocalPlayerSpawned; } private void Start() { if (fadeOverlay != null) { fadeOverlay.color = Color.clear; fadeOverlay.raycastTarget = false; } // The player may already exist (late UI init); otherwise we wait for the spawn event. if (PlayerStats.Instance != null) BindToPlayer(); } /// /// Binds to the local player as soon as it spawns on the network. /// private void HandleLocalPlayerSpawned() => BindToPlayer(); /// /// Caches the lifecycle and listens for the local player's death; runs once. /// private void BindToPlayer() { if (bound) return; if (PlayerStats.Instance == null) return; bound = true; // Take the lifecycle from the LOCAL player only. A global Find would also match remote // players (their root GameObject stays active; only the Behaviour is disabled), and could // respawn the wrong player in multiplayer. playerLifecycle = PlayerStats.Instance.GetComponent(); PlayerStats.Instance.onDeath.AddListener(OnDeath); } private void OnDeath() { if (isDying) return; isDying = true; timer = 0f; phase = Phase.Wait; } private void Update() { if (!isDying) return; timer += Time.deltaTime; switch (phase) { case Phase.Wait: if (timer >= fadeDelay) { phase = Phase.Fade; timer = 0f; } break; case Phase.Fade: float fadeT = Mathf.Clamp01(timer / fadeDuration); if (fadeOverlay != null) fadeOverlay.color = new Color(0f, 0f, 0f, fadeT); if (fadeT >= 1f) { phase = Phase.Black; timer = 0f; } break; case Phase.Black: if (timer >= respawnDelay) { playerLifecycle.Respawn(); if (fadeOverlay != null) fadeOverlay.color = Color.clear; isDying = false; phase = Phase.Done; } break; } } private void OnDestroy() { if (PlayerStats.Instance != null) PlayerStats.Instance.onDeath.RemoveListener(OnDeath); } } }