using System.Threading; using Cysharp.Threading.Tasks; using Enums; using Services; using UnityEngine; using Utils; namespace Views { public class GemView : MonoBehaviour { private Gem gem; public Gem Gem => this.gem; private SpriteRenderer spriteRenderer; private bool isFalling; private const float SPAWN_SCALE_FROM = 0f; private const float SPAWN_SCALE_DURATION = 0.12f; private CancellationTokenSource spawnScaleCts; public void Bind(Gem gem, bool isBomb = false) { this.gem = gem; this.gameObject.SetActive(true); SetupGem(isBomb); PlaySpawnScale(); } private void SetupGem(bool isBomb) { this.spriteRenderer ??= GetComponent(); if (isBomb) { this.spriteRenderer.color = this.gem.MatchColor switch { GemType.Blue => Color.blue, GemType.Green => Color.green, GemType.Red => Color.red, GemType.Yellow => Color.yellow, GemType.Purple => Color.magenta, _ => this.spriteRenderer.color }; } else { this.spriteRenderer.color = Color.white; } } public void Unbind() { this.spawnScaleCts?.Cancel(); this.spawnScaleCts?.Dispose(); this.spawnScaleCts = null; this.gem = null; this.gameObject.SetActive(false); this.isFalling = false; } private void PlaySpawnScale() { this.spawnScaleCts?.Cancel(); this.spawnScaleCts?.Dispose(); this.spawnScaleCts = new CancellationTokenSource(); this.transform.localScale = Vector3.one * SPAWN_SCALE_FROM; AnimateSpawnScaleAsync(this.spawnScaleCts.Token).Forget(); } private async UniTask AnimateSpawnScaleAsync(CancellationToken ct) { float timer = 0f; while (timer < SPAWN_SCALE_DURATION) { ct.ThrowIfCancellationRequested(); timer += Time.deltaTime; float scale = Mathf.Clamp01(timer / SPAWN_SCALE_DURATION); scale = Mathf.SmoothStep(0f, 1f, scale); this.transform.localScale = Vector3.LerpUnclamped( Vector3.one * SPAWN_SCALE_FROM, Vector3.one, scale ); await UniTask.Yield(PlayerLoopTiming.Update, ct); } this.transform.localScale = Vector3.one; } private async UniTask FallDelay() { float fallDelay = 1 * (this.gem.Position.y / 10f); await UniTask.WaitForSeconds(fallDelay); this.isFalling = true; } public async UniTaskVoid UpdatePosition(Vector2Int positionBasedOnIndex, float gemSpeed) { if (!this.isFalling) { await FallDelay(); } if (!this.isFalling) return; if (Vector2.Distance(this.transform.position, positionBasedOnIndex.ToVector2()) > 0.01f) { this.transform.position = Vector2.Lerp(this.transform.position, positionBasedOnIndex.ToVector2(), gemSpeed); } } } }