using UnityEngine; using DG.Tweening; public enum DeathType { Normal, Laser, Spikes } public class Skywalker_GameManager : MonoBehaviour { public static Skywalker_GameManager Instance; [Header("UI References")] public GameObject gameOverPanel; [Header("Player Reference")] public Skywalker_PlayerController player; // assign in inspector [Header("Heaven Tween")] public float heavenHeight = 4f; // ascent height public float ascendDuration = 2.5f; // ascent time public float fadeDelay = 2.0f; // wait before fade (2–3s) public float fadeDuration = 0.5f; // fade to 1 [Header("Material (AllIn1SpriteShader)")] public Material playerMaterial; private bool isGameOver = false; // AllIn1SpriteShader property IDs static readonly int ID_FadeAmount = Shader.PropertyToID("_FadeAmount"); static readonly int ID_FadeBurnWidth = Shader.PropertyToID("_FadeBurnWidth"); static readonly int ID_GreyscaleBlend = Shader.PropertyToID("_GreyscaleBlend"); // <-- added static readonly int ID_GhostBlend = Shader.PropertyToID("_GhostBlend"); // <-- added // AllIn1SpriteShader keywords (kept; safe even if features are enabled on the asset) const string KW_FADE = "FADE_ON"; const string KW_GREYSCALE = "GREYSCALE_ON"; const string KW_GHOST = "GHOST_ON"; const string KW_OVERLAY = "OVERLAY_ON"; const string KW_OVERLAYMULT = "OVERLAYMULT_ON"; // store original keyword states so we can restore on disable bool origFade, origGrey, origGhost, origOverlay, origOverlayMult; Sequence deathSeq; // --- Blueberry Glow Pulse (AllIn1SpriteShader) --- [Header("Blueberry Glow Pulse")] public Material glowMaterial; // optional: defaults to playerMaterial if null [Tooltip("Shader float property for glow intensity (AllIn1SpriteShader).")] public string glowIntensityProp = "_Glow"; // <-- default corrected to _Glow public float glowBase = 1.75f; public float glowPeak = 7.75f; public float glowPulseDuration = 0.6f; // total time (up + down) private Sequence glowSeq; private int _ID_GlowIntensity; private string _lastGlowPropName; static readonly int ID_OverlayBlend = Shader.PropertyToID("_OverlayBlend"); void Awake() { if (Instance == null) Instance = this; else { Destroy(gameObject); return; } if (gameOverPanel) gameOverPanel.SetActive(false); if (!glowMaterial) glowMaterial = playerMaterial; _ID_GlowIntensity = Shader.PropertyToID(glowIntensityProp); _lastGlowPropName = glowIntensityProp; CacheOriginalKeywordStates(); } void CacheOriginalKeywordStates() { if (!playerMaterial) return; origFade = playerMaterial.IsKeywordEnabled(KW_FADE); origGrey = playerMaterial.IsKeywordEnabled(KW_GREYSCALE); origGhost = playerMaterial.IsKeywordEnabled(KW_GHOST); origOverlay = playerMaterial.IsKeywordEnabled(KW_OVERLAY); origOverlayMult = playerMaterial.IsKeywordEnabled(KW_OVERLAYMULT); } // --- Public helpers to call from hazards / tests --- public void KillBySpikes() => TriggerGameOver(DeathType.Spikes); public void KillByLaser() => TriggerGameOver(DeathType.Laser); public void KillNormal() => TriggerGameOver(DeathType.Normal); [ContextMenu("TEST: Kill By Spikes")] void _TestKillSpikes() => KillBySpikes(); [ContextMenu("TEST: Kill By Laser")] void _TestKillLaser() => KillByLaser(); public void TriggerGameOver(DeathType type) { if (isGameOver || player == null) return; isGameOver = true; var col = player.GetComponent(); var rb = player.GetComponent(); if (col) col.enabled = false; switch (type) { case DeathType.Spikes: PrepKinematic(rb); DeathBySpikes(); break; case DeathType.Laser: PrepKinematic(rb); DeathByLaser(); break; default: // Normal player.ForceJumpForGameOver(); if (rb) { rb.useGravity = true; rb.isKinematic = false; } break; } GameoverInvoker(); // now 5 seconds Debug.Log("GAME OVER!"); } void PrepKinematic(Rigidbody rb) { if (!rb) return; rb.velocity = Vector3.zero; rb.angularVelocity = Vector3.zero; rb.useGravity = false; rb.isKinematic = true; } public void PulseBlueberryGlow() { if (!glowMaterial) return; // Refresh property ID if you change the prop name in the Inspector if (_lastGlowPropName != glowIntensityProp || _ID_GlowIntensity == 0) { _ID_GlowIntensity = Shader.PropertyToID(glowIntensityProp); _lastGlowPropName = glowIntensityProp; } // Kill previous pulse only (don’t touch other tweens like fade) if (glowSeq != null && glowSeq.IsActive()) glowSeq.Kill(); // Ensure starting at base glowMaterial.SetFloat(_ID_GlowIntensity, glowBase); float half = Mathf.Max(0.01f, glowPulseDuration * 0.5f); glowSeq = DOTween.Sequence().SetId("BlueberryGlow") .Append(glowMaterial.DOFloat(glowPeak, _ID_GlowIntensity, half).SetEase(Ease.OutQuad).SetId("BlueberryGlow")) .Append(glowMaterial.DOFloat(glowBase, _ID_GlowIntensity, half).SetEase(Ease.InQuad).SetId("BlueberryGlow")); glowSeq.Play(); } // -------- Death styles -------- void DeathBySpikes() { player.animator.Play("Angel"); BeginHeavenSequence(laserStyle: false); } void DeathByLaser() { player.animator.Play("Angel"); BeginHeavenSequence(laserStyle: true); } public void GameoverInvoker(int duration = 5) { CancelInvoke(nameof(GameoverPanelEnabler)); Invoke(nameof(GameoverPanelEnabler), duration); } public void GameoverPanelEnabler() { if (gameOverPanel) gameOverPanel.SetActive(true); } // -------- Tweens + Shader toggles / values -------- void BeginHeavenSequence(bool laserStyle) { if (deathSeq != null && deathSeq.IsActive()) deathSeq.Kill(); if (playerMaterial) DOTween.Kill(playerMaterial); if (playerMaterial) { playerMaterial.EnableKeyword(KW_FADE); if (laserStyle) { // Laser: Overlay + Ghost, NO Greyscale playerMaterial.DisableKeyword(KW_GREYSCALE); playerMaterial.EnableKeyword(KW_OVERLAY); playerMaterial.DisableKeyword(KW_OVERLAYMULT); playerMaterial.EnableKeyword(KW_GHOST); } else { // Spikes: Greyscale + Ghost, NO Overlay (+ make sure OVERLAYMULT is OFF) playerMaterial.EnableKeyword(KW_GREYSCALE); playerMaterial.DisableKeyword(KW_OVERLAY); playerMaterial.DisableKeyword(KW_OVERLAYMULT); playerMaterial.EnableKeyword(KW_GHOST); } // Ensure visible before fade playerMaterial.SetFloat(ID_FadeAmount, -0.1f); if (!laserStyle) playerMaterial.SetFloat(ID_FadeBurnWidth, 0f); // Start blends from zero so tweens are visible playerMaterial.SetFloat(ID_GreyscaleBlend, 0f); playerMaterial.SetFloat(ID_GhostBlend, 0f); playerMaterial.SetFloat(ID_OverlayBlend, 0f); } Vector3 endPos = player.transform.position + Vector3.up * heavenHeight; deathSeq = DOTween.Sequence(); if (laserStyle && playerMaterial) { // Start ALL laser visuals together: // - BurnWidth widens (0.5s) // - Ghost 0 -> 0.65 (0.35s) // - Overlay 0 -> 1.0 (0.35s) deathSeq.Append(playerMaterial.DOFloat(1f, ID_FadeBurnWidth, 0.5f)); // append first deathSeq.Join(playerMaterial.DOFloat(0.65f, ID_GhostBlend, 0.35f).SetEase(Ease.OutQuad)); deathSeq.Join(playerMaterial.DOFloat(1.0f, ID_OverlayBlend, 0.35f).SetEase(Ease.OutQuad)); } else if (playerMaterial) { // Spikes: Greyscale 0 -> 0.7, Ghost 0 -> 0.65 together deathSeq.Join(playerMaterial.DOFloat(0.7f, ID_GreyscaleBlend, 0.35f).SetEase(Ease.OutQuad)); deathSeq.Join(playerMaterial.DOFloat(0.65f, ID_GhostBlend, 0.35f).SetEase(Ease.OutQuad)); } // Float up like an angel deathSeq.Append(player.transform.DOMoveY(endPos.y, ascendDuration).SetEase(Ease.OutSine)); // Wait before final fade deathSeq.AppendInterval(fadeDelay); // Final fade to 1 if (playerMaterial) { if (laserStyle) { // Laser: fade out AND shrink burn width back to 0 at the same time deathSeq.Append(playerMaterial.DOFloat(1f, ID_FadeAmount, fadeDuration)); deathSeq.Join(playerMaterial.DOFloat(0f, ID_FadeBurnWidth, fadeDuration)); // <- new } else { // Spikes: just fade out deathSeq.Append(playerMaterial.DOFloat(1f, ID_FadeAmount, fadeDuration)); } } deathSeq.Play(); } // -------- Revert shader changes on disable -------- void OnDisable() { if (deathSeq != null && deathSeq.IsActive()) deathSeq.Kill(); DOTween.Kill(playerMaterial); playerMaterial.SetFloat(ID_OverlayBlend, 0f); if (playerMaterial) { // revert fade values playerMaterial.SetFloat(ID_FadeAmount, 0f); playerMaterial.SetFloat(ID_FadeBurnWidth, 0f); // revert blends playerMaterial.SetFloat(ID_GreyscaleBlend, 0f); playerMaterial.SetFloat(ID_GhostBlend, 0f); // restore original keywords SetKeyword(playerMaterial, KW_FADE, origFade); SetKeyword(playerMaterial, KW_GREYSCALE, origGrey); SetKeyword(playerMaterial, KW_GHOST, origGhost); SetKeyword(playerMaterial, KW_OVERLAY, origOverlay); SetKeyword(playerMaterial, KW_OVERLAYMULT, origOverlayMult); } if (glowSeq != null && glowSeq.IsActive()) glowSeq.Kill(); DOTween.Kill("BlueberryGlow"); if (glowMaterial) glowMaterial.SetFloat(_ID_GlowIntensity, glowBase); } static void SetKeyword(Material m, string keyword, bool enabled) { if (!m) return; if (enabled) m.EnableKeyword(keyword); else m.DisableKeyword(keyword); } }