using UnityEngine; using TMPro; namespace VRBeats { public class FinalScoreLabel : MonoBehaviour { [SerializeField] private TextMeshProUGUI scoreText = null; [SerializeField] private int length = 10; private string initialValue = ""; private ScoreManager scoreManager = null; private GameObject resultRoot = null; private TextMeshProUGUI rankShadowText = null; private TextMeshProUGUI rankDepthText = null; private TextMeshProUGUI rankMainText = null; private TextMeshProUGUI resultScoreText = null; private TextMeshProUGUI resultComboText = null; private void Awake() { for (int n = 0; n < length; n++) initialValue += "0"; scoreManager = FindFirstObjectByType(); ApplyPopupTextStyle(); BuildResultLayout(); } public void ShowScore() { if (scoreText == null || scoreManager == null) return; SetTitleActive(false); gameObject.CancelAllTweens(); if (resultRoot != null) { scoreText.gameObject.SetActive(false); PopulateResultLayout(); resultRoot.SetActive(true); } else { scoreText.text = scoreManager.BuildResultSummary(length); } } public void ResetValues() { gameObject.CancelAllTweens(); if (resultRoot != null) resultRoot.SetActive(false); if (scoreText != null) scoreText.gameObject.SetActive(true); SetTitleActive(true); ApplyPopupTextStyle(); if (scoreText != null) scoreText.text = initialValue; } private void PopulateResultLayout() { if (scoreManager == null || rankShadowText == null || rankDepthText == null || rankMainText == null || resultScoreText == null || resultComboText == null) return; string rank = scoreManager.Rank; Color mainColor = HexToColor(scoreManager.RankColorHex); Color depthColor = HexToColor(GetRankDepthColorHex(rank)); rankShadowText.text = rank; rankDepthText.text = rank; rankDepthText.color = depthColor; rankMainText.text = rank; rankMainText.color = mainColor; resultScoreText.text = scoreManager.CurrentScore.ToString("N0"); resultComboText.text = $"MAX COMBO {scoreManager.MaxCombo}"; } private void SetTitleActive(bool active) { Transform titleObj = scoreText != null ? scoreText.rectTransform.parent?.Find("Title") : null; if (titleObj != null) titleObj.gameObject.SetActive(active); } private void ApplyPopupTextStyle() { if (scoreText == null) return; RectTransform rect = scoreText.rectTransform; rect.anchorMin = new Vector2(0.5f, 0.5f); rect.anchorMax = new Vector2(0.5f, 0.5f); rect.anchoredPosition = new Vector2(0.0f, 0.0f); rect.sizeDelta = new Vector2(620.0f, 250.0f); scoreText.enableAutoSizing = true; scoreText.fontSizeMin = 1.2f; scoreText.fontSizeMax = 5.5f; scoreText.alignment = TextAlignmentOptions.MidlineLeft; scoreText.overflowMode = TextOverflowModes.Truncate; scoreText.textWrappingMode = TextWrappingModes.NoWrap; scoreText.lineSpacing = -10.0f; scoreText.color = Color.white; scoreText.richText = true; } private void BuildResultLayout() { if (scoreText == null) return; Transform parent = scoreText.rectTransform.parent; if (parent == null) return; GameObject root = new GameObject("ResultLayoutRoot"); root.transform.SetParent(parent, false); RectTransform rootRect = root.AddComponent(); rootRect.anchorMin = new Vector2(0.5f, 0.5f); rootRect.anchorMax = new Vector2(0.5f, 0.5f); rootRect.anchoredPosition = Vector2.zero; rootRect.sizeDelta = new Vector2(620.0f, 250.0f); root.SetActive(false); resultRoot = root; // Rank badge left side — hierarchy order = draw order (shadow first, main on top) rankShadowText = MakeTmpLabel(root.transform, "RankShadowText", new Vector2(-166.0f, 6.0f), new Vector2(200.0f, 200.0f), 14.0f, new Color(0.0f, 0.0f, 0.0f, 0.55f), TextAlignmentOptions.Midline); rankDepthText = MakeTmpLabel(root.transform, "RankDepthText", new Vector2(-168.0f, 8.0f), new Vector2(200.0f, 200.0f), 14.0f, Color.white, TextAlignmentOptions.Midline); rankMainText = MakeTmpLabel(root.transform, "RankMainText", new Vector2(-170.0f, 10.0f), new Vector2(200.0f, 200.0f), 14.0f, Color.white, TextAlignmentOptions.Midline); // Score and combo right side resultScoreText = MakeTmpLabel(root.transform, "ResultScoreText", new Vector2(70.0f, 35.0f), new Vector2(260.0f, 80.0f), 5.5f, Color.white, TextAlignmentOptions.MidlineLeft); resultComboText = MakeTmpLabel(root.transform, "ResultComboText", new Vector2(70.0f, -35.0f), new Vector2(260.0f, 50.0f), 3.8f, new Color(0.84f, 0.97f, 1.0f, 1.0f), TextAlignmentOptions.MidlineLeft); } private TextMeshProUGUI MakeTmpLabel(Transform parent, string name, Vector2 pos, Vector2 size, float fontSize, Color color, TextAlignmentOptions align) { GameObject go = new GameObject(name); go.transform.SetParent(parent, false); RectTransform rect = go.AddComponent(); rect.anchorMin = new Vector2(0.5f, 0.5f); rect.anchorMax = new Vector2(0.5f, 0.5f); rect.anchoredPosition = pos; rect.sizeDelta = size; TextMeshProUGUI tmp = go.AddComponent(); tmp.fontSize = fontSize; tmp.color = color; tmp.alignment = align; tmp.overflowMode = TextOverflowModes.Overflow; tmp.textWrappingMode = TextWrappingModes.NoWrap; tmp.raycastTarget = false; if (scoreText != null && scoreText.font != null) { tmp.font = scoreText.font; tmp.fontSharedMaterial = scoreText.fontSharedMaterial; } return tmp; } private static string GetRankDepthColorHex(string rank) { switch (rank) { case "M": return "#7EEBFF"; case "S+": return "#116BFF"; case "S": return "#B56A16"; case "A": return "#5CAA30"; case "B": return "#B89E20"; case "C": return "#C05A10"; case "D": return "#B02040"; default: return "#606870"; } } private static Color HexToColor(string hex) { if (ColorUtility.TryParseHtmlString(hex, out Color color)) return color; return Color.white; } } }