using DG.Tweening; using TMPro; using UnityEngine; using UnityEngine.UI; using System.Collections.Generic; using asap.core; using PinballUncountable; using UniRx; using System.Threading.Tasks; using System; using Game; using GameCore; using game; public class PinballUncountableProgressBarView : MonoBehaviour { [SerializeField] private Image[] bars; [SerializeField] private PinballUncountableProgressRewardItemView[] rewards; [SerializeField] private OfferTreasureAscentGrandRewardView grandRewardView; [SerializeField] private RectTransform scroller; [SerializeField] private float startPos = 1246.9f, gap = 188f; [SerializeField] private TMP_Text textScore, textRewardCount; [SerializeField] private PinballUncountableGaugeAnimationView gauge; private int _scoreDisplay, _scoreLogic, _idx; private readonly int _displayCount = 3; private Tween _tween = null; private readonly Queue _scoreQueue = new Queue(); private bool _isProcessingQueue = false; // public bool IsProcessingQueue => _isProcessingQueue; private void Awake() { var manager = GContext.container.Resolve(); manager.EventAggregator.GetEvent().Subscribe(OnScore).AddTo(this); } public void Init(int idx, List items) { var manager = GContext.container.Resolve(); _idx = idx; if (items.Count < rewards.Length) Debug.LogError($"Rewards count {items.Count}, less than {rewards.Length}.", this); for (int i = 0; i < rewards.Length; i++) rewards[i].Init(items[i]); grandRewardView.Init(items[^1].Item, manager.InflationRate); _scoreLogic = manager.Score; _scoreDisplay = _scoreLogic; SetScrollerToIdx(idx); (var barIdx, var percentage) = manager.TableContext.GetBarProgressDataFromScore(_scoreDisplay); SetBarsByScore(barIdx, percentage); SetScoreText(manager.TableContext.GetScopeScoreFromActualScore(_scoreLogic), manager.TableContext.GetCurrentMaxScore(_scoreLogic)); UpdateRewardCount(0, rewards.Length + 1); for (int i = items.Count - 1; i >= 0; i--) { if (items[i].IsReceived) { UpdateRewardCount(i + 1, rewards.Length + 1); break; } } // _maxScore = manager.TableContext.GetMaxScore(manager.Score); } private void ResetProgressBar() { var manager = GContext.container.Resolve(); _idx = 0; var items = manager.TableContext.GetRewardsData(manager.InflationRate, manager.Score); if (items.Count < rewards.Length) Debug.LogError($"Rewards count {items.Count}, less than {rewards.Length}.", this); for (int i = 0; i < rewards.Length; i++) rewards[i].Init(items[i]); SetScrollerToIdx(0); SetBarsByScore(0, 0); SetScoreText(0, manager.TableContext.GetCurrentMaxScore(_scoreLogic)); foreach (var reward in rewards) reward.SetReceived(false); grandRewardView.Init(items[^1].Item, manager.InflationRate); grandRewardView.SetClaimed(false); // _maxScore = manager.TableContext.GetMaxScore(manager.Score); } /// /// Update score text, update score progress bar, and while at it, if a new reward is to be given, tick it and move the scroller /// /// The incoming exit event private void OnScore(EventExit e) { var manager = GContext.container.Resolve(); var score2Add = manager.TableContext.GetScoreFromExitIndex(e.ExitIdx); _scoreLogic += score2Add; _scoreQueue.Enqueue(_scoreLogic); gauge.OnAddScore(score2Add); ProcessQueue(); } private async void ProcessQueue() { if (_isProcessingQueue) return; var manager = GContext.container.Resolve(); _isProcessingQueue = true; while (_scoreQueue.Count > 0) { var targetScore = _scoreQueue.Dequeue(); await MoveBarsByScoreAsync(targetScore); } _isProcessingQueue = false; } #region ScoreText private void SetScoreText(int score, int maxScore) { textScore.text = score.ToString() + "/" + maxScore.ToString(); } #endregion #region Bars private void SetBarsByScore(int idx, float percentage) { var manager = GContext.container.Resolve(); // (var idx, var percentage) = manager.TableContext.GetBarProgressDataFromScore(score); for (int i = 0; i < bars.Length; i++) { if (i < idx) bars[i].fillAmount = 1; else if (i == idx) bars[i].fillAmount = percentage; else bars[i].fillAmount = 0; } } [SerializeField] private float barSpeed = 1f; private async Task MoveBarsByScoreAsync(int targetScore) { try { var manager = GContext.container.Resolve(); (var oldIdx, var oldPercentage) = manager.TableContext.GetBarProgressDataFromScore(_scoreDisplay); (var newIdx, var newPercentage) = manager.TableContext.GetBarProgressDataFromScore(targetScore); // Debug.Log($"[PinballUncountable] From {_scoreDisplay} To {targetScore} !"); if (oldIdx == newIdx) { // Debug.Log("[PinballUncountable] BarMove: Same!"); await bars[oldIdx].DOFillAmount(newPercentage, (newPercentage - oldPercentage) / barSpeed).SetId(this).AsyncWaitForCompletion(); MoveScrollerToIdx(oldIdx); _scoreDisplay = targetScore; SetScoreText(manager.TableContext.GetScopeScoreFromActualScore(targetScore), manager.TableContext.GetCurrentMaxScore(targetScore)); } else if (oldIdx < newIdx) { // Debug.Log("[PinballUncountable] BarMove: Next!"); await bars[oldIdx].DOFillAmount(1, (1 - oldPercentage) / barSpeed).SetId(this).AsyncWaitForCompletion(); await SetReceived(oldIdx); MoveScrollerToIdx(oldIdx); for (int i = oldIdx + 1; i < newIdx; i++) { await bars[i].DOFillAmount(1, 1 / barSpeed).SetId(this).AsyncWaitForCompletion(); await SetReceived(i); MoveScrollerToIdx(i); } await bars[newIdx].DOFillAmount(newPercentage, newPercentage / barSpeed).SetId(this).AsyncWaitForCompletion(); MoveScrollerToIdx(newIdx); _scoreDisplay = targetScore; SetScoreText(manager.TableContext.GetScopeScoreFromActualScore(targetScore), manager.TableContext.GetCurrentMaxScore(targetScore)); } else { // Debug.Log("[PinballUncountable] BarMove: Twist!"); await bars[oldIdx].DOFillAmount(1, (1 - oldPercentage) / barSpeed).SetId(this).AsyncWaitForCompletion(); SetScoreText(manager.TableContext.GetCurrentMaxScore(_scoreDisplay), manager.TableContext.GetCurrentMaxScore(_scoreDisplay)); await SetReceived(oldIdx); Debug.Log("[OfferTreasureAscent] Show special panel."); var openGo = await UIManager.Instance.ShowUINotLoading(UITypes.PinballUncountableBoxPanel); await openGo.GetComponent().PlayAnimation(); UIManager.Instance.DestroyUI(UITypes.PinballUncountableBoxPanel); // 等待玩家在奖励弹窗中点击领取后再继续:订阅一次 FishingTurnTableContinueMultiDraw,弹窗关闭时会发布该事件 var claimTcs = new TaskCompletionSource(); IDisposable claimSub = null; claimSub = GContext.OnEvent() .Take(1) .Subscribe(_ => { claimTcs.TrySetResult(true); claimSub?.Dispose(); }); GContext.Publish(new ShowData(grandRewardView.RewardItems)); GContext.Publish(new ShowData()); await claimTcs.Task; claimSub?.Dispose(); MoveScrollerToIdx(oldIdx); for (int i = oldIdx + 1; i < bars.Length; i++) { await bars[i].DOFillAmount(1, 1 / barSpeed).SetId(this).AsyncWaitForCompletion(); await SetReceived(i); MoveScrollerToIdx(i); } ResetProgressBar(); for (int i = 0; i < newIdx; i++) { await bars[i].DOFillAmount(1, 1 / barSpeed).SetId(this).AsyncWaitForCompletion(); await SetReceived(i); MoveScrollerToIdx(i); } await bars[newIdx].DOFillAmount(newPercentage, newPercentage / barSpeed).SetId(this).AsyncWaitForCompletion(); MoveScrollerToIdx(newIdx); _scoreDisplay = targetScore; SetScoreText(manager.TableContext.GetScopeScoreFromActualScore(targetScore), manager.TableContext.GetCurrentMaxScore(targetScore)); } } catch (Exception e) { Debug.LogError(e); } } #endregion #region Scroller private void MoveScrollerToIdx(int idx) { idx -= 1; idx = Mathf.Clamp(idx, 0, rewards.Length - _displayCount); _idx = idx; // scroller.anchoredPosition = new Vector2(startPos - gap * idx, scroller.anchoredPosition.y); _tween?.Kill(); _tween = scroller.DOAnchorPosX(startPos - gap * idx, 0.5f); // Debug.Log($"[PinballUncountable] move to {idx}"); } private void SetScrollerToIdx(int idx) { idx = Mathf.Clamp(idx, 0, rewards.Length - _displayCount); _idx = idx; scroller.anchoredPosition = new Vector2(startPos - gap * idx, scroller.anchoredPosition.y); } #endregion #region Reward // UGLY: may be able to separate final reward display private async Task SetReceived(int idx) { if (idx < 0 || idx > rewards.Length) return; if (idx == rewards.Length) { Debug.Log("[PinballUncountable] SetReceived: Final reward!!!!!!!!!!"); grandRewardView.SetClaimed(); GContext.Publish(new EventUISound("audio_ui_reward_claim")); UpdateRewardCount(idx + 1, rewards.Length + 1); // await Task.Delay(TimeSpan.FromSeconds(2f)); return; } if (rewards[idx] == null) return; rewards[idx].SetReceived(true); GContext.Publish(new EventUISound("audio_ui_reward_claim")); UpdateRewardCount(idx + 1, rewards.Length + 1); await Task.Delay(TimeSpan.FromSeconds(0.5f)); } #endregion private void UpdateRewardCount(int receivedRewardCount, int maxRewardCount) { // textRewardCount.text = $"我拿到了{receivedRewardCount}/{maxRewardCount},缺少多语言"; textRewardCount.text = LocalizationMgr.GetFormatTextValue("UI_EventPinballUncountableCowboyPanel_2", receivedRewardCount, maxRewardCount); } #if UNITY_EDITOR [SerializeField] private int testScore; private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { MoveScrollerToIdx(_idx + 1); } if (Input.GetKeyDown(KeyCode.R)) { scroller.anchoredPosition = new Vector2(startPos, 0); _idx = 0; } // if (Input.GetKeyDown(KeyCode.B)) // { // SetBarsByScore(testScore); // } } // private void OnGUI() // { // GUI.Box(new Rect(20, 20, 200, 20), $"IsProcessingQueue: {_isProcessingQueue}"); // } #endif }