664 lines
25 KiB
C#
664 lines
25 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
/// <summary>
|
|
/// CashSystemUI — Event-driven HUD for Cash System mode.
|
|
/// Subscribes to GameEvents; never polls via FindObjectOfType.
|
|
/// Includes: timer, vault bars, carried cash, kill feed, combo popup, vault attack warning, countdown.
|
|
/// </summary>
|
|
public class CashSystemUI : MonoBehaviour
|
|
{
|
|
[Header("Timer Display")]
|
|
[SerializeField] private TextMeshProUGUI timerText;
|
|
|
|
[Header("Vault Displays")]
|
|
[SerializeField] private TextMeshProUGUI playerVaultText;
|
|
[SerializeField] private TextMeshProUGUI enemyVaultText;
|
|
[SerializeField] private Slider playerVaultBar;
|
|
[SerializeField] private Slider enemyVaultBar;
|
|
|
|
[Header("Carried Cash Display")]
|
|
[SerializeField] private TextMeshProUGUI carriedCashText;
|
|
[SerializeField] private GameObject carriedCashPanel;
|
|
|
|
[Header("Character Switch Indicator")]
|
|
[SerializeField] private TextMeshProUGUI currentCharacterText;
|
|
[SerializeField] private Image[] teamCharacterIcons;
|
|
|
|
[Header("Steal Progress")]
|
|
[SerializeField] private GameObject stealProgressPanel;
|
|
[SerializeField] private Slider stealProgressBar;
|
|
[SerializeField] private TextMeshProUGUI stealProgressText;
|
|
|
|
[Header("Steal Dial (optional)")]
|
|
[Tooltip("Optional sprite to use for the steal progress radial dial. If left empty the code will try to copy the import UI's dial sprite at runtime.")]
|
|
[SerializeField] private Sprite stealDialSprite;
|
|
[Header("Countdown Display")]
|
|
[SerializeField] private TextMeshProUGUI countdownText;
|
|
[SerializeField] private GameObject countdownPanel;
|
|
|
|
[Header("Kill Feed")]
|
|
[SerializeField] private TextMeshProUGUI killFeedText;
|
|
[SerializeField] private int maxFeedEntries = 5;
|
|
|
|
[Header("Combo Popup")]
|
|
[SerializeField] private TextMeshProUGUI comboText;
|
|
[SerializeField] private GameObject comboPanel;
|
|
|
|
[Header("Popup Message")]
|
|
[SerializeField] private TextMeshProUGUI popupText;
|
|
[SerializeField] private GameObject popupPanel;
|
|
|
|
[Header("Pickup Screen Effect")]
|
|
[Tooltip("Full-screen flash image (stretch to fill, starts transparent)")]
|
|
[SerializeField] private Image pickupFlashImage;
|
|
[Tooltip("Color of the screen flash when picking up cash")]
|
|
[SerializeField] private Color pickupFlashColor = new Color(1f, 0.84f, 0f, 0.35f); // Gold
|
|
[Tooltip("How long the flash lasts")]
|
|
[SerializeField] private float pickupFlashDuration = 0.3f;
|
|
[Tooltip("Text popup showing collected amount (e.g. '+$100')")]
|
|
[SerializeField] private TextMeshProUGUI pickupAmountText;
|
|
[SerializeField] private GameObject pickupAmountPanel;
|
|
|
|
[Header("Win Target")]
|
|
[SerializeField] private float targetCash = 2000f;
|
|
|
|
// ─── Runtime ─────────────────────────────────────────────
|
|
private readonly List<string> _feedEntries = new List<string>();
|
|
private Coroutine _comboFade;
|
|
private Coroutine _popupFade;
|
|
private Coroutine _pickupFlashCoroutine;
|
|
private float _originalTimerFontSize = -1f;
|
|
private bool _dirtyVault;
|
|
|
|
// Cached score values (set by events, read in LateUpdate for dirty-flag refresh)
|
|
private float _playerScore, _enemyScore;
|
|
|
|
// Cached carrier reference — invalidated on character switch
|
|
private CashCarrier _cachedCarrier;
|
|
private GameObject _cachedCarrierCharacter;
|
|
private bool _stealWasActive;
|
|
|
|
// CanvasGroup for intro delay — hidden until intro panel finishes
|
|
private CanvasGroup _canvasGroup;
|
|
|
|
// ─── Lifecycle ───────────────────────────────────────────
|
|
|
|
private void Start()
|
|
{
|
|
if (SelectionOptions.Instance == null || !SelectionOptions.Instance.isCashSystemSelected)
|
|
{
|
|
gameObject.SetActive(false);
|
|
return;
|
|
}
|
|
|
|
// Set up CanvasGroup so we can hide during intro without disabling the script
|
|
_canvasGroup = GetComponent<CanvasGroup>();
|
|
if (_canvasGroup == null) _canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
|
|
|
// Hide the HUD during the intro panel — CashSystemManager will show it after intro completes
|
|
_canvasGroup.alpha = 0f;
|
|
_canvasGroup.blocksRaycasts = false;
|
|
_canvasGroup.interactable = false;
|
|
|
|
if (playerVaultBar != null) playerVaultBar.maxValue = targetCash;
|
|
if (enemyVaultBar != null) enemyVaultBar.maxValue = targetCash;
|
|
if (stealProgressPanel != null) stealProgressPanel.SetActive(false);
|
|
ConfigureStealDial();
|
|
if (comboPanel != null) comboPanel.SetActive(false);
|
|
if (popupPanel != null) popupPanel.SetActive(false);
|
|
|
|
// Explicitly hide carried cash panel and clear text on start
|
|
HideCarried();
|
|
if (carriedCashText != null) carriedCashText.text = "";
|
|
}
|
|
|
|
/// <summary>Show the HUD (called by CashSystemManager after intro completes).</summary>
|
|
public void ShowHUD()
|
|
{
|
|
if (_canvasGroup == null) return;
|
|
_canvasGroup.alpha = 1f;
|
|
_canvasGroup.blocksRaycasts = true;
|
|
_canvasGroup.interactable = true;
|
|
Debug.Log("[CashSystemUI] HUD shown");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configure the steal progress dial to match the import UI's dial if possible.
|
|
/// Tries in this order:
|
|
/// 1) If `stealDialSprite` is assigned in inspector, use that.
|
|
/// 2) If an ImportUIPanel exists in the scene (created by CashBoxImportController), copy its ProgressDial sprite.
|
|
/// 3) If we have a Slider with a fill Rect, apply the sprite as a radial Image.
|
|
/// </summary>
|
|
private void ConfigureStealDial()
|
|
{
|
|
if (stealProgressBar == null) return;
|
|
|
|
Sprite spriteToUse = stealDialSprite;
|
|
|
|
// Try to find the runtime ImportUIPanel created by CashBoxImportController
|
|
if (spriteToUse == null)
|
|
{
|
|
var importPanel = GameObject.Find("ImportUIPanel");
|
|
if (importPanel != null)
|
|
{
|
|
var dial = importPanel.transform.Find("ProgressDial");
|
|
if (dial != null)
|
|
{
|
|
var img = dial.GetComponent<Image>();
|
|
if (img != null) spriteToUse = img.sprite;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (spriteToUse == null) return;
|
|
|
|
// Apply sprite to the Slider's fill image if available
|
|
var fillRect = stealProgressBar.fillRect;
|
|
if (fillRect != null)
|
|
{
|
|
var fillImg = fillRect.GetComponent<Image>();
|
|
if (fillImg != null)
|
|
{
|
|
fillImg.sprite = spriteToUse;
|
|
fillImg.type = Image.Type.Filled;
|
|
fillImg.fillMethod = Image.FillMethod.Radial360;
|
|
fillImg.fillOrigin = (int)Image.Origin360.Top;
|
|
fillImg.fillClockwise = true;
|
|
fillImg.preserveAspect = true;
|
|
}
|
|
}
|
|
|
|
// COPY ADDITIONAL VISUAL SETTINGS FROM IMPORT UI
|
|
var importPanelObj = GameObject.Find("ImportUIPanel");
|
|
if (importPanelObj != null)
|
|
{
|
|
// Copy panel background color if stealProgressPanel has an Image
|
|
var importImage = importPanelObj.GetComponent<Image>();
|
|
if (importImage != null && stealProgressPanel != null)
|
|
{
|
|
var stealPanelImg = stealProgressPanel.GetComponent<Image>();
|
|
if (stealPanelImg != null)
|
|
{
|
|
stealPanelImg.color = importImage.color;
|
|
}
|
|
}
|
|
|
|
// Copy font/size/color from Import's AmountText to our stealProgressText
|
|
var amountTf = importPanelObj.transform.Find("AmountText");
|
|
if (amountTf != null && stealProgressText != null)
|
|
{
|
|
var importAmountTmp = amountTf.GetComponent<TextMeshProUGUI>();
|
|
if (importAmountTmp != null)
|
|
{
|
|
// Copy common TMP settings
|
|
stealProgressText.font = importAmountTmp.font;
|
|
stealProgressText.fontSize = importAmountTmp.fontSize;
|
|
stealProgressText.color = importAmountTmp.color;
|
|
stealProgressText.fontStyle = importAmountTmp.fontStyle;
|
|
stealProgressText.enableAutoSizing = importAmountTmp.enableAutoSizing;
|
|
stealProgressText.outlineWidth = importAmountTmp.outlineWidth;
|
|
stealProgressText.outlineColor = importAmountTmp.outlineColor;
|
|
stealProgressText.alignment = importAmountTmp.alignment;
|
|
}
|
|
}
|
|
|
|
// Also copy countdown/status text style if present (optional)
|
|
var countdownTf = importPanelObj.transform.Find("CountdownText");
|
|
if (countdownTf != null && timerText != null)
|
|
{
|
|
var importCountdownTmp = countdownTf.GetComponent<TextMeshProUGUI>();
|
|
if (importCountdownTmp != null)
|
|
{
|
|
timerText.font = importCountdownTmp.font;
|
|
timerText.fontSize = importCountdownTmp.fontSize;
|
|
timerText.color = importCountdownTmp.color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
GameEvents.OnTimerUpdated += OnTimerUpdated;
|
|
GameEvents.OnScoreChanged += OnScoreChanged;
|
|
GameEvents.OnBagPickedUp += OnBagPickedUp;
|
|
GameEvents.OnCashDeposited += OnCashDeposited;
|
|
GameEvents.OnKillFeedEntry += OnKillFeedEntry;
|
|
GameEvents.OnComboMultiplier += OnComboMultiplier;
|
|
GameEvents.OnVaultUnderAttack += OnVaultUnderAttack;
|
|
GameEvents.OnVaultDefended += OnVaultDefended;
|
|
GameEvents.OnCountdownTick += OnCountdownTick;
|
|
GameEvents.OnPopupMessage += OnPopupMessage;
|
|
GameEvents.OnCharacterSwitched += OnCharacterSwitched;
|
|
GameEvents.OnCarrierKilled += OnCarrierKilled;
|
|
GameEvents.OnMatchEnd += OnMatchEnd;
|
|
GameEvents.OnBagDropped += OnBagDropped;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
GameEvents.OnTimerUpdated -= OnTimerUpdated;
|
|
GameEvents.OnScoreChanged -= OnScoreChanged;
|
|
GameEvents.OnBagPickedUp -= OnBagPickedUp;
|
|
GameEvents.OnCashDeposited -= OnCashDeposited;
|
|
GameEvents.OnKillFeedEntry -= OnKillFeedEntry;
|
|
GameEvents.OnComboMultiplier -= OnComboMultiplier;
|
|
GameEvents.OnVaultUnderAttack -= OnVaultUnderAttack;
|
|
GameEvents.OnVaultDefended -= OnVaultDefended;
|
|
GameEvents.OnCountdownTick -= OnCountdownTick;
|
|
GameEvents.OnPopupMessage -= OnPopupMessage;
|
|
GameEvents.OnCharacterSwitched -= OnCharacterSwitched;
|
|
GameEvents.OnCarrierKilled -= OnCarrierKilled;
|
|
GameEvents.OnMatchEnd -= OnMatchEnd;
|
|
GameEvents.OnBagDropped -= OnBagDropped;
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
// Dirty-flag: only refresh vault bars when data changed
|
|
if (_dirtyVault)
|
|
{
|
|
_dirtyVault = false;
|
|
RefreshVaultBars();
|
|
}
|
|
|
|
// Steal progress: check every frame only while active, otherwise throttle to ~6Hz
|
|
if (_stealWasActive || Time.frameCount % 10 == 0)
|
|
{
|
|
UpdateStealProgress();
|
|
}
|
|
|
|
// Carried cash: event-driven via OnBagPickedUp/OnBagDropped/OnCashDeposited/OnCarrierKilled
|
|
// Only poll at ~10Hz as a safety net for edge cases
|
|
if (Time.frameCount % 6 == 0)
|
|
{
|
|
RefreshCarriedCash();
|
|
}
|
|
}
|
|
|
|
// ─── Event Handlers ──────────────────────────────────────
|
|
|
|
private void OnTimerUpdated(float remaining)
|
|
{
|
|
if (timerText == null) return;
|
|
int m = Mathf.FloorToInt(remaining / 60);
|
|
int s = Mathf.FloorToInt(remaining % 60);
|
|
timerText.text = $"{m:00}:{s:00}";
|
|
timerText.color = remaining <= 30f
|
|
? Color.Lerp(Color.red, Color.white, Mathf.PingPong(Time.time * 2, 1))
|
|
: Color.white;
|
|
}
|
|
|
|
private void OnScoreChanged(string teamTag, float total)
|
|
{
|
|
if (teamTag == "Player") _playerScore = total;
|
|
else _enemyScore = total;
|
|
_dirtyVault = true;
|
|
}
|
|
|
|
private void OnBagPickedUp(CashBag bag, CashCarrier carrier)
|
|
{
|
|
// Update carrier display immediately
|
|
RefreshCarriedCash();
|
|
|
|
// Only show screen effects for the player-controlled character
|
|
CashSystemManager mgr = CashSystemManager.Instance;
|
|
if (mgr == null) return;
|
|
GameObject controlled = mgr.CurrentControlledCharacter;
|
|
if (controlled == null || carrier == null) return;
|
|
if (carrier.gameObject != controlled) return;
|
|
|
|
// Screen flash effect
|
|
ShowPickupFlash();
|
|
|
|
// Floating "+$X" amount text
|
|
float amount = bag != null ? bag.CashValue : 0f;
|
|
ShowPickupAmount(amount);
|
|
}
|
|
|
|
private void OnBagDropped(CashBag bag, Vector3 pos)
|
|
{
|
|
RefreshCarriedCash();
|
|
}
|
|
|
|
private void OnCashDeposited(string teamTag, float value, int combo)
|
|
{
|
|
_dirtyVault = true;
|
|
RefreshCarriedCash();
|
|
}
|
|
|
|
private void OnKillFeedEntry(string killer, string action, string victim)
|
|
{
|
|
string entry = $"<b>{killer}</b> {action} <b>{victim}</b>";
|
|
_feedEntries.Add(entry);
|
|
if (_feedEntries.Count > maxFeedEntries)
|
|
_feedEntries.RemoveAt(0);
|
|
|
|
if (killFeedText != null)
|
|
killFeedText.text = string.Join("\n", _feedEntries);
|
|
}
|
|
|
|
private void OnComboMultiplier(int multiplier)
|
|
{
|
|
if (comboText == null) return;
|
|
comboText.text = $"x{multiplier} COMBO!";
|
|
if (comboPanel != null) comboPanel.SetActive(true);
|
|
if (_comboFade != null) StopCoroutine(_comboFade);
|
|
_comboFade = StartCoroutine(FadePanel(comboPanel, 2f));
|
|
}
|
|
|
|
private void OnVaultUnderAttack(TeamVault vault)
|
|
{
|
|
if (vault.TeamTag != "Player") return;
|
|
if (stealProgressPanel != null) stealProgressPanel.SetActive(true);
|
|
if (stealProgressText != null) stealProgressText.text = "VAULT UNDER ATTACK!";
|
|
}
|
|
|
|
private void OnVaultDefended(TeamVault vault)
|
|
{
|
|
if (vault.TeamTag != "Player") return;
|
|
if (stealProgressPanel != null) stealProgressPanel.SetActive(false);
|
|
}
|
|
|
|
private void OnCountdownTick(string text)
|
|
{
|
|
ShowCountdown(text);
|
|
}
|
|
|
|
private void OnPopupMessage(string message, float duration)
|
|
{
|
|
if (popupText != null) popupText.text = message;
|
|
if (popupPanel != null) popupPanel.SetActive(true);
|
|
if (_popupFade != null) StopCoroutine(_popupFade);
|
|
_popupFade = StartCoroutine(FadePanel(popupPanel, duration));
|
|
}
|
|
|
|
private void OnCharacterSwitched(GameObject oldChar, GameObject newChar)
|
|
{
|
|
if (newChar == null) return;
|
|
if (currentCharacterText != null)
|
|
currentCharacterText.text = newChar.name;
|
|
|
|
// Highlight icon
|
|
if (teamCharacterIcons != null)
|
|
{
|
|
CashSystemManager mgr = CashSystemManager.Instance;
|
|
if (mgr != null)
|
|
{
|
|
var team = mgr.GetTeamCharacters("Player");
|
|
int idx = team.IndexOf(newChar);
|
|
for (int i = 0; i < teamCharacterIcons.Length; i++)
|
|
if (teamCharacterIcons[i] != null)
|
|
teamCharacterIcons[i].color = i == idx ? Color.white : new Color(1, 1, 1, 0.5f);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnCarrierKilled(CashCarrier carrier)
|
|
{
|
|
RefreshCarriedCash();
|
|
}
|
|
|
|
private void OnMatchEnd(string winnerTag)
|
|
{
|
|
// Could show final score overlay
|
|
}
|
|
|
|
// ─── Helpers ─────────────────────────────────────────────
|
|
|
|
private void RefreshVaultBars()
|
|
{
|
|
if (playerVaultText != null) playerVaultText.text = $"${_playerScore:F0}";
|
|
if (enemyVaultText != null) enemyVaultText.text = $"${_enemyScore:F0}";
|
|
if (playerVaultBar != null) playerVaultBar.value = _playerScore;
|
|
if (enemyVaultBar != null) enemyVaultBar.value = _enemyScore;
|
|
}
|
|
|
|
private void RefreshCarriedCash()
|
|
{
|
|
CashSystemManager mgr = CashSystemManager.Instance;
|
|
if (mgr == null) { HideCarried(); return; }
|
|
GameObject cur = mgr.CurrentControlledCharacter;
|
|
if (cur == null) { HideCarried(); return; }
|
|
|
|
// Cache CashCarrier — only re-fetch when controlled character changes
|
|
if (_cachedCarrierCharacter != cur)
|
|
{
|
|
_cachedCarrierCharacter = cur;
|
|
_cachedCarrier = cur.GetComponent<CashCarrier>();
|
|
}
|
|
|
|
if (_cachedCarrier == null || _cachedCarrier.CarriedCash < 0.01f) { HideCarried(); return; }
|
|
|
|
if (carriedCashText != null) carriedCashText.text = $"Carrying: ${_cachedCarrier.CarriedCash:F0}";
|
|
if (carriedCashPanel != null) carriedCashPanel.SetActive(true);
|
|
}
|
|
|
|
private void HideCarried()
|
|
{
|
|
if (carriedCashPanel != null) carriedCashPanel.SetActive(false);
|
|
}
|
|
|
|
private void UpdateStealProgress()
|
|
{
|
|
// Check player vault steal progress (uses EntityRegistry now)
|
|
var vaults = EntityRegistry<TeamVault>.GetAll();
|
|
TeamVault playerVault = null;
|
|
for (int i = 0; i < vaults.Count; i++)
|
|
if (vaults[i] != null && vaults[i].TeamTag == "Player") { playerVault = vaults[i]; break; }
|
|
|
|
if (playerVault != null && playerVault.IsBeingStolen)
|
|
{
|
|
_stealWasActive = true;
|
|
if (stealProgressPanel != null) stealProgressPanel.SetActive(true);
|
|
if (stealProgressBar != null) stealProgressBar.value = playerVault.StealProgress;
|
|
}
|
|
else
|
|
{
|
|
_stealWasActive = false;
|
|
if (stealProgressPanel != null) stealProgressPanel.SetActive(false);
|
|
}
|
|
}
|
|
|
|
private IEnumerator FadePanel(GameObject panel, float duration)
|
|
{
|
|
yield return new WaitForSeconds(duration);
|
|
if (panel != null) panel.SetActive(false);
|
|
}
|
|
|
|
// ─── Pickup Screen Effects ───────────────────────────────
|
|
|
|
private void ShowPickupFlash()
|
|
{
|
|
if (_pickupFlashCoroutine != null) StopCoroutine(_pickupFlashCoroutine);
|
|
|
|
// If no flash image assigned, create one at runtime
|
|
if (pickupFlashImage == null)
|
|
{
|
|
CreatePickupFlashImage();
|
|
}
|
|
|
|
if (pickupFlashImage != null)
|
|
{
|
|
_pickupFlashCoroutine = StartCoroutine(PickupFlashRoutine());
|
|
}
|
|
}
|
|
|
|
private void CreatePickupFlashImage()
|
|
{
|
|
Canvas canvas = GetComponentInParent<Canvas>();
|
|
if (canvas == null) canvas = FindObjectOfType<Canvas>();
|
|
if (canvas == null) return;
|
|
|
|
GameObject flashObj = new GameObject("PickupFlash");
|
|
flashObj.transform.SetParent(canvas.transform, false);
|
|
|
|
RectTransform rt = flashObj.AddComponent<RectTransform>();
|
|
rt.anchorMin = Vector2.zero;
|
|
rt.anchorMax = Vector2.one;
|
|
rt.offsetMin = Vector2.zero;
|
|
rt.offsetMax = Vector2.zero;
|
|
|
|
pickupFlashImage = flashObj.AddComponent<Image>();
|
|
pickupFlashImage.color = Color.clear;
|
|
pickupFlashImage.raycastTarget = false;
|
|
|
|
// Make sure it renders on top
|
|
flashObj.transform.SetAsLastSibling();
|
|
}
|
|
|
|
private IEnumerator PickupFlashRoutine()
|
|
{
|
|
pickupFlashImage.color = pickupFlashColor;
|
|
|
|
float elapsed = 0f;
|
|
while (elapsed < pickupFlashDuration)
|
|
{
|
|
elapsed += Time.deltaTime;
|
|
float t = elapsed / pickupFlashDuration;
|
|
pickupFlashImage.color = Color.Lerp(pickupFlashColor, Color.clear, t);
|
|
yield return null;
|
|
}
|
|
|
|
pickupFlashImage.color = Color.clear;
|
|
}
|
|
|
|
private void ShowPickupAmount(float amount)
|
|
{
|
|
if (amount <= 0) return;
|
|
|
|
// If no pickup amount panel, create one dynamically
|
|
if (pickupAmountText == null)
|
|
{
|
|
CreatePickupAmountText();
|
|
}
|
|
|
|
if (pickupAmountText != null)
|
|
{
|
|
pickupAmountText.text = $"+${amount:F0}";
|
|
if (pickupAmountPanel != null) pickupAmountPanel.SetActive(true);
|
|
|
|
// Auto-hide after a short duration
|
|
StartCoroutine(FadePickupAmount());
|
|
}
|
|
}
|
|
|
|
private void CreatePickupAmountText()
|
|
{
|
|
Canvas canvas = GetComponentInParent<Canvas>();
|
|
if (canvas == null) canvas = FindObjectOfType<Canvas>();
|
|
if (canvas == null) return;
|
|
|
|
pickupAmountPanel = new GameObject("PickupAmountPanel");
|
|
pickupAmountPanel.transform.SetParent(canvas.transform, false);
|
|
|
|
RectTransform panelRect = pickupAmountPanel.AddComponent<RectTransform>();
|
|
panelRect.anchorMin = new Vector2(0.5f, 0.6f);
|
|
panelRect.anchorMax = new Vector2(0.5f, 0.6f);
|
|
panelRect.sizeDelta = new Vector2(700f, 160f);
|
|
panelRect.anchoredPosition = Vector2.zero;
|
|
|
|
GameObject textObj = new GameObject("PickupAmountText");
|
|
textObj.transform.SetParent(pickupAmountPanel.transform, false);
|
|
|
|
RectTransform textRect = textObj.AddComponent<RectTransform>();
|
|
textRect.anchorMin = Vector2.zero;
|
|
textRect.anchorMax = Vector2.one;
|
|
textRect.offsetMin = Vector2.zero;
|
|
textRect.offsetMax = Vector2.zero;
|
|
|
|
pickupAmountText = textObj.AddComponent<TextMeshProUGUI>();
|
|
pickupAmountText.fontSize = 96;
|
|
pickupAmountText.alignment = TextAlignmentOptions.Center;
|
|
pickupAmountText.color = new Color(1f, 0.92f, 0.23f); // Bright gold
|
|
pickupAmountText.fontStyle = FontStyles.Bold;
|
|
pickupAmountText.enableAutoSizing = false;
|
|
|
|
// Add outline for readability
|
|
pickupAmountText.outlineWidth = 0.35f;
|
|
pickupAmountText.outlineColor = new Color32(0, 0, 0, 200);
|
|
|
|
pickupAmountPanel.SetActive(false);
|
|
}
|
|
|
|
private IEnumerator FadePickupAmount()
|
|
{
|
|
float displayDuration = 1.2f;
|
|
float fadeDuration = 0.4f;
|
|
|
|
if (pickupAmountText == null) yield break;
|
|
|
|
// Float upward animation
|
|
RectTransform rt = pickupAmountPanel.GetComponent<RectTransform>();
|
|
Vector2 startPos = new Vector2(0f, 0f);
|
|
Vector2 endPos = new Vector2(0f, 50f);
|
|
|
|
Color startColor = pickupAmountText.color;
|
|
|
|
float elapsed = 0f;
|
|
while (elapsed < displayDuration)
|
|
{
|
|
elapsed += Time.deltaTime;
|
|
float t = elapsed / displayDuration;
|
|
|
|
// Float upward
|
|
if (rt != null)
|
|
rt.anchoredPosition = Vector2.Lerp(startPos, endPos, t);
|
|
|
|
// Fade out in last portion
|
|
if (t > 0.6f)
|
|
{
|
|
float fadeT = (t - 0.6f) / 0.4f;
|
|
pickupAmountText.color = new Color(startColor.r, startColor.g, startColor.b, 1f - fadeT);
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
// Reset
|
|
pickupAmountText.color = startColor;
|
|
if (rt != null) rt.anchoredPosition = startPos;
|
|
if (pickupAmountPanel != null) pickupAmountPanel.SetActive(false);
|
|
}
|
|
|
|
// ─── Legacy API (called from other scripts) ──────────────
|
|
|
|
public void UpdateTimerDisplay(float timeRemaining) => OnTimerUpdated(timeRemaining);
|
|
public void UpdateVaultDisplay(TeamVault vault)
|
|
{
|
|
if (vault == null) return;
|
|
if (vault.TeamTag == "Player") _playerScore = vault.StoredCash;
|
|
else _enemyScore = vault.StoredCash;
|
|
_dirtyVault = true;
|
|
}
|
|
public void UpdateCarriedCashDisplay(CashCarrier carrier) => RefreshCarriedCash();
|
|
public void UpdateCurrentCharacter(string characterName, int index)
|
|
{
|
|
if (currentCharacterText != null) currentCharacterText.text = characterName;
|
|
}
|
|
|
|
public void ShowCountdown(string text)
|
|
{
|
|
if (countdownText != null)
|
|
countdownText.text = text;
|
|
if (countdownPanel != null)
|
|
countdownPanel.SetActive(!string.IsNullOrEmpty(text));
|
|
|
|
// Fallback: use timer text for countdown
|
|
if (countdownText == null && timerText != null && !string.IsNullOrEmpty(text))
|
|
{
|
|
if (_originalTimerFontSize < 0) _originalTimerFontSize = timerText.fontSize;
|
|
timerText.text = text;
|
|
timerText.fontSize = 72;
|
|
}
|
|
else if (countdownText == null && timerText != null && string.IsNullOrEmpty(text))
|
|
{
|
|
if (_originalTimerFontSize > 0) timerText.fontSize = _originalTimerFontSize;
|
|
}
|
|
}
|
|
}
|