using RuntimeData; using TH1_Logic.Core; using TMPro; using UnityEngine; using UnityEngine.UI; namespace TH1_UI.View.Top { public class UITopTopBarView : Base.View { private const string TopBarAnimTimerMessage = "UITopTopBarView TopBarAnim"; private const float CoinSelfCheckInterval = 0.5f; private int _topBarAnimVersion; private bool _coinAnimActive; private float _coinAnimEndTime; private float _nextCoinSelfCheckTime; //public Button closeButton; public ViDelegateAssisstant.Dele OnBtnCloseClick; public TextMeshProUGUI Faith; public TextMeshProUGUI Turn; public TextMeshProUGUI Coin; public TextMeshProUGUI CoinPerTurn; public Transform CoinTransform; public Transform FaithTransform; public TextMeshProUGUI Tech; public TextMeshProUGUI TechPerTurn; public Transform TechTransform; public TextMeshProUGUI Culture; public TextMeshProUGUI CulturePerTurn; public Transform CultureTransform; public RectTransform FatherPanel; public GameObject PerfectTime; public enum TopBarPanelType { Coin, Faith, Tech, Culture } protected override void OnInit() { base.OnInit(); //closeButton.onClick.RemoveAllListeners(); //closeButton.onClick.AddListener(() => { OnBtnCloseClick.Invoke(); }); //CheckPanel.InitStart(RefreshStatus); // 确保所有Transform初始时都是active的,等待数据显示逻辑来控制 // 这样可以防止Prefab中误设为inactive导致无法显示 if (CultureTransform != null) CultureTransform.gameObject.SetActive(true); if (TechTransform != null) TechTransform.gameObject.SetActive(true); } //通常一局只会set一次,每次都是完全清空,然后绑定新的一个对局的按钮 public void SetContent() { UpdateAllInstant(); // 首次SetContent时强制重建布局,确保所有Panel的位置和大小正确 RebuildCoinPanelLayout(); } public void UpdateAllInstant() { //注意 开局首次调用本函数,所有city都是空,percoin和pertech perculture都是0,需要controller里的每个update函数来刷新的 if (Main.MapData?.PlayerMap?.SelfPlayerData == null) return; CancelTopBarAnim(); // PerfectTime:仅在Perfect模式下显示 if (PerfectTime != null) PerfectTime.SetActive(Main.MapData.MapConfig.GameMode == GameMode.PERFECT); Turn.text = (Main.MapData.PlayerMap.SelfPlayerData.Turn + 1).ToString(); Faith.text = Main.MapData.PlayerMap.SelfPlayerData.PlayerScore.ToString(); SetCoinText(Main.MapData.PlayerMap.SelfPlayerData.PlayerCoin); CoinPerTurn.text = "" + Main.PlayerLogic.GetPlayerCoinPerTurn(Main.MapData,Main.MapData.PlayerMap.SelfPlayerData.Id) + ""; RebuildCoinPanelLayout(); var techPerTurn = Main.PlayerLogic.GetPlayerTechPointPerTurn(Main.MapData, Main.MapData.PlayerMap.SelfPlayerData.Id); // 强制根据数据显示/隐藏Tech模块 bool techNeedShow = (techPerTurn > 0 || Main.MapData.PlayerMap.SelfPlayerData.PlayerTechPoint > 0); if (TechTransform != null) { bool wasActive = TechTransform.gameObject.activeSelf; TechTransform.gameObject.SetActive(techNeedShow); if (wasActive != techNeedShow) { LayoutRebuilder.ForceRebuildLayoutImmediate(FatherPanel); } if (techNeedShow) { Tech.text = Main.MapData.PlayerMap.SelfPlayerData.PlayerTechPoint.ToString(); TechPerTurn.text = "" + techPerTurn + ""; } } var culturePerTurn = Main.PlayerLogic.GetPlayerCulturePointPerTurn(Main.MapData, Main.MapData.PlayerMap.SelfPlayerData.Id); // 强制根据数据显示/隐藏Culture模块 bool cultureNeedShow = (culturePerTurn > 0 || Main.MapData.PlayerMap.SelfPlayerData.PlayerCultureInfo.PlayerCulture > 0); //cultureNeedShow = true; if (CultureTransform != null) { bool wasActive = CultureTransform.gameObject.activeSelf; CultureTransform.gameObject.SetActive(cultureNeedShow); if (wasActive != cultureNeedShow) { LayoutRebuilder.ForceRebuildLayoutImmediate(FatherPanel); } if (cultureNeedShow) { Culture.text = Main.MapData.PlayerMap.SelfPlayerData.PlayerCultureInfo.PlayerCulture.ToString(); CulturePerTurn.text = "" + culturePerTurn + ""; } } } public void CloseView() { //AudioManager.Instance.StopMusic(); } private void Update() { if (Time.time < _nextCoinSelfCheckTime) return; _nextCoinSelfCheckTime = Time.time + CoinSelfCheckInterval; SelfCheckCoinText(); } public void UpdateTurn() { Turn.text = (Main.MapData.PlayerMap.SelfPlayerData.Turn + 1).ToString(); } public void UpdateCoin() { if (Main.MapData?.PlayerMap?.SelfPlayerData == null) return; CancelTopBarAnim(); if (!int.TryParse(Coin.text, out var old)) old = Main.MapData.PlayerMap.SelfPlayerData.PlayerCoin; float delay = Table.Instance.AnimDataAssets.ProjectileCoinMoveTime; if (old > Main.MapData.PlayerMap.SelfPlayerData.PlayerCoin) delay = 0f; TopBarAnim(Coin,old,Main.MapData.PlayerMap.SelfPlayerData.PlayerCoin,delay,TopBarPanelType.Coin); } public void UpdateTech() { if (Main.MapData?.PlayerMap?.SelfPlayerData == null) return; var techPerTurn = Main.PlayerLogic.GetPlayerTechPointPerTurn(Main.MapData, Main.MapData.PlayerMap.SelfPlayerData.Id); //如果techTransform应该显示的状态和实际状态不一致,更新其显示状态 bool needShow = (techPerTurn > 0 || Main.MapData.PlayerMap.SelfPlayerData.PlayerTechPoint > 0); if (needShow != TechTransform.gameObject.activeSelf) { TechTransform.gameObject.SetActive(techPerTurn > 0); LayoutRebuilder.ForceRebuildLayoutImmediate(FatherPanel); } if (needShow) { Tech.text = Main.MapData.PlayerMap.SelfPlayerData.PlayerTechPoint.ToString(); TechPerTurn.text = "" + techPerTurn + ""; } } public void UpdateCulture() { if (Main.MapData?.PlayerMap?.SelfPlayerData == null) return; var culturePerTurn = Main.PlayerLogic.GetPlayerCulturePointPerTurn(Main.MapData, Main.MapData.PlayerMap.SelfPlayerData.Id); // 强制根据数据显示/隐藏Culture模块 bool needShow = (culturePerTurn > 0 || Main.MapData.PlayerMap.SelfPlayerData.PlayerCultureInfo.PlayerCulture > 0); if (CultureTransform != null) { bool wasActive = CultureTransform.gameObject.activeSelf; CultureTransform.gameObject.SetActive(needShow); if (wasActive != needShow) { LayoutRebuilder.ForceRebuildLayoutImmediate(FatherPanel); } if (needShow) { Culture.text = Main.MapData.PlayerMap.SelfPlayerData.PlayerCultureInfo.PlayerCulture.ToString(); CulturePerTurn.text = "" + culturePerTurn + ""; } } } public void UpdateFaith() { if (Main.MapData?.PlayerMap?.SelfPlayerData == null) return; if (!int.TryParse(Faith.text, out var old)) return; //不允许脱离action逻辑修改mapData //Main.PlayerLogic.CalcAllPlayerScore(Main.MapData); Faith.text = Main.MapData.PlayerMap.SelfPlayerData.PlayerScore.ToString(); /*float delay = Table.Instance.AnimDataAssets.ProjectileCoinMoveTime; if (old > Main.MapData.PlayerMap.SelfPlayerData.PlayerScore) delay = 0f; TopBarAnim(Faith,old,Main.MapData.PlayerMap.SelfPlayerData.PlayerScore,delay); */ } private void TopBarAnim(TextMeshProUGUI targetText, int oldValue,int targetValue,float startDelay,TopBarPanelType panelType) { var animVersion = _topBarAnimVersion; int maxTime = 100; int now = oldValue; int time = Mathf.Abs(targetValue - oldValue); int step = targetValue > oldValue ? 1 : -1; if (time > maxTime) { time = maxTime; step = (targetValue - oldValue) / time; } if (time == 0) { SetTopBarAnimText(targetText, targetValue, panelType); return; } if (panelType == TopBarPanelType.Coin) { _coinAnimActive = true; _coinAnimEndTime = Time.time + Mathf.Max(0f, startDelay) + (time - 1) * 0.03f + 0.1f; } for (int s = 0; s < time; s++) { now += step; //如果时长太长,直接跳到结果 //final Check用来在最后一帧强制对其真实数值coin 或者faith bool finalCheck = false; if (s == time - 1) { now = targetValue; finalCheck = true; } var panel = panelType; var text = targetText; var tmp = now; var tmps = Mathf.Min(s,200); Timer.Instance.TimerRegister(this, () => { if (animVersion != _topBarAnimVersion) return; SetTopBarAnimText(text, tmp, panel); if (finalCheck) { if(panel == TopBarPanelType.Coin && Main.MapData != null) { SetTopBarAnimText(text, Main.MapData.PlayerMap.SelfPlayerData.PlayerCoin, panel); _coinAnimActive = false; } } },tmps * 0.03f + startDelay , TopBarAnimTimerMessage); } } private void CancelTopBarAnim() { _topBarAnimVersion++; _coinAnimActive = false; Timer.Instance?.CancelByMessage(TopBarAnimTimerMessage); } private void SelfCheckCoinText() { if (Main.MapData?.PlayerMap?.SelfPlayerData == null || Coin == null) return; if (_coinAnimActive) { if (Time.time <= _coinAnimEndTime) return; CancelTopBarAnim(); } var realCoin = Main.MapData.PlayerMap.SelfPlayerData.PlayerCoin; if (int.TryParse(Coin.text, out var showCoin) && showCoin == realCoin) return; CancelTopBarAnim(); SetCoinText(realCoin); } public void UpdateCoinPerTurn() { if (Main.MapData?.PlayerMap?.SelfPlayerData == null) return; CoinPerTurn.text = "" + Main.PlayerLogic.GetPlayerCoinPerTurn(Main.MapData,Main.MapData.PlayerMap.SelfPlayerData.Id) + ""; RebuildCoinPanelLayout(); } private void RebuildCoinPanelLayout() { RebuildTopBarLayout( Coin != null ? Coin.rectTransform : null, CoinPerTurn != null ? CoinPerTurn.rectTransform : null, CoinTransform as RectTransform); } private void SetTopBarAnimText(TextMeshProUGUI targetText, int value, TopBarPanelType panelType) { if (panelType == TopBarPanelType.Coin) { SetCoinText(value); return; } if (targetText == null) return; targetText.text = value.ToString(); } private void SetCoinText(int value) { if (Coin == null) return; Coin.text = value.ToString(); Coin.ForceMeshUpdate(); RebuildTopBarLayout(Coin.rectTransform, CoinTransform as RectTransform); } private void RebuildTopBarLayout(params RectTransform[] rebuildRoots) { foreach (var root in rebuildRoots) { if (root != null) LayoutRebuilder.ForceRebuildLayoutImmediate(root); } if (FatherPanel != null) LayoutRebuilder.ForceRebuildLayoutImmediate(FatherPanel); } } }