using UnityEngine; using UnityEngine.UI; using TMPro; using System.Collections; using System.Collections.Generic; /// /// MatchResultUI — Unified VICTORY / DEFEAT end-of-match panel. /// Works for both Cash System (team 3v3) and Practice (1v1) modes. /// /// Stats auto-populate based on mode: /// Cash System → Kills, Cash Deposited, Cash Stolen, Damage /// Practice → Kills, Deaths, Assists, Damage /// /// Hierarchy (from scene): /// Stats (root, this script) /// ├─ continue (Button) /// ├─ restart (Button) /// ├─ Title — result header "VICTORY" / "DEFEAT" /// ├─ Title(1) — score text "24 VICTORY 20" /// ├─ Playerstatsui /// │ ├─ PlayerName /// │ ├─ kills /// │ ├─ deaths /// │ ├─ assists /// │ └─ damage /// ├─ Enemystatsui /// │ ├─ EnemyName /// │ ├─ kills /// │ ├─ deaths /// │ ├─ assists /// │ └─ damage /// └─ Victory tab /// public class MatchResultUI : MonoBehaviour { [Header("Panel Root")] [Tooltip("The root panel that gets shown/hidden. If null, uses this.gameObject.")] [SerializeField] private GameObject rootPanel; [Header("Header")] [SerializeField] private TextMeshProUGUI resultHeaderText; // "VICTORY" / "DEFEAT" [SerializeField] private TextMeshProUGUI scoreText; // "24 VICTORY 20" style [Header("Team Names")] [SerializeField] private TextMeshProUGUI playerTeamLabel; // e.g. "CHEETAH WIN!" [SerializeField] private TextMeshProUGUI enemyTeamLabel; // e.g. "RABBIT LOSE!" [Header("Player Stats Texts")] [Tooltip("Player/team name text inside Playerstatsui")] [SerializeField] private TextMeshProUGUI playerNameText; [Tooltip("Stat row 1 — Kills (both modes)")] [SerializeField] private TextMeshProUGUI playerKillsText; [Tooltip("Stat row 2 — Deaths (practice) / Cash Deposited (cash system)")] [SerializeField] private TextMeshProUGUI playerDeathsText; [Tooltip("Stat row 3 — Assists (practice) / Cash Stolen (cash system)")] [SerializeField] private TextMeshProUGUI playerAssistsText; [Tooltip("Stat row 4 — Damage (both modes)")] [SerializeField] private TextMeshProUGUI playerDamageText; [Header("Enemy Stats Texts")] [Tooltip("Enemy/team name text inside Enemystatsui")] [SerializeField] private TextMeshProUGUI enemyNameText; [SerializeField] private TextMeshProUGUI enemyKillsText; [SerializeField] private TextMeshProUGUI enemyDeathsText; [SerializeField] private TextMeshProUGUI enemyAssistsText; [SerializeField] private TextMeshProUGUI enemyDamageText; [Header("Buttons")] [SerializeField] private Button continueButton; [SerializeField] private Button restartButton; [Header("Colors")] [SerializeField] private Color victoryColor = new Color(1f, 0.84f, 0f); // Gold [SerializeField] private Color defeatColor = new Color(0.96f, 0.26f, 0.21f); // Red [SerializeField] private Color panelBgColor = new Color(0.08f, 0.12f, 0.18f, 0.92f); [Header("Audio")] [SerializeField] private AudioClip victorySFX; [SerializeField] private AudioClip defeatSFX; [SerializeField] private AudioClip buttonClickSFX; [SerializeField] private float sfxVolume = 1f; [Header("Animation")] [SerializeField] private float revealDuration = 0.6f; // runtime private AudioSource _audio; private CanvasGroup _canvasGroup; private float _savedFixedDeltaTime; private static MatchResultUI _instance; public static MatchResultUI Instance => _instance; /// /// Ensures a MatchResultUI instance exists in the scene. /// Finds inactive instances first, or creates a minimal one with buttons on the existing Canvas. /// Call from CashSystemManager.Start() so end-of-match always shows a panel. /// public static void EnsureExists() { if (_instance != null) return; // 1. Try to find an inactive instance already in the scene MatchResultUI[] all = Resources.FindObjectsOfTypeAll(); foreach (var m in all) { if (m.gameObject.scene.name == null) continue; // Activate parents top-down first, then the object itself List chain = new List(); Transform t = m.transform; while (t != null) { if (!t.gameObject.activeSelf) chain.Add(t.gameObject); t = t.parent; } for (int i = chain.Count - 1; i >= 0; i--) chain[i].SetActive(true); if (_instance != null) { DevLog.Log("[MatchResultUI] Found existing inactive panel, activated it"); return; } } // 2. Create a minimal panel on an existing Canvas Canvas canvas = Object.FindObjectOfType(); if (canvas == null) { GameObject canvasObj = new GameObject("UICanvas"); canvas = canvasObj.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = 100; canvasObj.AddComponent(); canvasObj.AddComponent(); } GameObject panelRoot = new GameObject("MatchResultUI_Auto"); panelRoot.transform.SetParent(canvas.transform, false); RectTransform rt = panelRoot.AddComponent(); rt.anchorMin = Vector2.zero; rt.anchorMax = Vector2.one; rt.offsetMin = Vector2.zero; rt.offsetMax = Vector2.zero; // Background Image bg = panelRoot.AddComponent(); bg.color = new Color(0.08f, 0.12f, 0.18f, 0.92f); // Result header GameObject headerObj = new GameObject("ResultHeader"); headerObj.transform.SetParent(panelRoot.transform, false); RectTransform hrt = headerObj.AddComponent(); hrt.anchorMin = new Vector2(0.2f, 0.7f); hrt.anchorMax = new Vector2(0.8f, 0.9f); hrt.offsetMin = Vector2.zero; hrt.offsetMax = Vector2.zero; TextMeshProUGUI headerTxt = headerObj.AddComponent(); headerTxt.text = "MATCH RESULT"; headerTxt.fontSize = 80; headerTxt.alignment = TextAlignmentOptions.Center; headerTxt.color = Color.white; // Score text GameObject scoreObj = new GameObject("ScoreText"); scoreObj.transform.SetParent(panelRoot.transform, false); RectTransform srt = scoreObj.AddComponent(); srt.anchorMin = new Vector2(0.2f, 0.55f); srt.anchorMax = new Vector2(0.8f, 0.7f); srt.offsetMin = Vector2.zero; srt.offsetMax = Vector2.zero; TextMeshProUGUI scoreTxt = scoreObj.AddComponent(); scoreTxt.text = ""; scoreTxt.fontSize = 48; scoreTxt.alignment = TextAlignmentOptions.Center; scoreTxt.color = Color.white; // Continue button Button continueBtn = CreateAutoButton(panelRoot.transform, "Continue", new Vector2(0.25f, 0.1f), new Vector2(0.48f, 0.22f), new Color(0.2f, 0.7f, 0.3f)); // Restart button Button restartBtn = CreateAutoButton(panelRoot.transform, "Restart", new Vector2(0.52f, 0.1f), new Vector2(0.75f, 0.22f), new Color(0.8f, 0.4f, 0.1f)); MatchResultUI ui = panelRoot.AddComponent(); ui.resultHeaderText = headerTxt; ui.scoreText = scoreTxt; ui.continueButton = continueBtn; ui.restartButton = restartBtn; DevLog.Log("[MatchResultUI] Auto-created minimal result panel on Canvas"); } private static Button CreateAutoButton(Transform parent, string label, Vector2 anchorMin, Vector2 anchorMax, Color bgColor) { GameObject btnObj = new GameObject(label + "Button"); btnObj.transform.SetParent(parent, false); RectTransform brt = btnObj.AddComponent(); brt.anchorMin = anchorMin; brt.anchorMax = anchorMax; brt.offsetMin = Vector2.zero; brt.offsetMax = Vector2.zero; Image btnBg = btnObj.AddComponent(); btnBg.color = bgColor; Button btn = btnObj.AddComponent