using System.Threading; using Cysharp.Threading.Tasks; using FlappyBird.Core; using UnityEngine; using Zenject; namespace FlappyBird.UI { [RequireComponent(typeof(CanvasGroup))] public class ScorePopupView : MonoBehaviour, Core.IPoolable { [SerializeField] private float floatSpeed = 100f; [SerializeField] private float duration = 0.7f; [SerializeField] private AnimationCurve alphaCurve = AnimationCurve.Linear(0, 1, 1, 0); private IObjectPoolManager _poolManager; private CanvasGroup _canvasGroup; private RectTransform _rectTransform; private CancellationTokenSource _cts; [Inject] public void Construct(IObjectPoolManager poolManager) { _poolManager = poolManager; } private void Awake() { _canvasGroup = GetComponent(); _rectTransform = transform as RectTransform; } /// /// Called by the ObjectPoolManager when the popup is retrieved from the pool. /// Starts the async animation task. /// public void OnSpawned() { _cts?.Cancel(); _cts = new CancellationTokenSource(); AnimateAndReturnAsync(_cts.Token).Forget(); } public void OnDespawned() { _cts?.Cancel(); _cts?.Dispose(); _cts = null; } private async UniTaskVoid AnimateAndReturnAsync(CancellationToken token) { float elapsed = 0f; Vector2 startPosition = _rectTransform.anchoredPosition; while (elapsed < duration) { if (token.IsCancellationRequested) return; elapsed += Time.deltaTime; float normalizedTime = elapsed / duration; // Move upwards using RectTransform for UI consistency _rectTransform.anchoredPosition = startPosition + (Vector2.up * (floatSpeed * normalizedTime)); // Apply fading based on curve if (_canvasGroup != null) { _canvasGroup.alpha = alphaCurve.Evaluate(normalizedTime); } await UniTask.Yield(PlayerLoopTiming.Update, token); } // Return to pool after animation finishes _poolManager.Return(this); } private void OnDestroy() { _cts?.Cancel(); _cts?.Dispose(); } } }