using System; using System.Collections; using Core.Domain; using Core.Ports; using KBCore.Refs; using UnityEngine; namespace Infrastructure.Unity { [RequireComponent(typeof(MeshRenderer), typeof(Rigidbody))] public class TileViewAdapter : MonoBehaviour, ITileView { private Tile _linkedTile; public string TileId { get; private set; } [Header("Visuals Settings")] [SerializeField] private Color stableColor = new Color(0.33725490196078434f, 0.5058823529411764f, 0.9529411764705882f); // Dark Grey [SerializeField] private Color warningColor = new Color(1f, 0.1803921568627451f, 0.38823529411764707f); // Neon Red [SerializeField] private Color fragileColor = new Color(0.08627450980392157f, 0.12941176470588237f, 0.24313725490196078f, 0.5f); // Cyan/Glass [SerializeField] private float colorSpeed = 2f; [Self][SerializeField] private Rigidbody rb; [Self][SerializeField] private MeshRenderer meshRenderer; [Self] [SerializeField] private Collider col; private MaterialPropertyBlock _propBlock; private static readonly int ColorProperty = Shader.PropertyToID("_BaseColor"); private static readonly int EmissionColorProperty = Shader.PropertyToID("_EmissionColor"); private Action _onReturnToPool; private float _targetAlpha = 1f; public MeshRenderer MeshRenderer => meshRenderer; private void Awake() { _propBlock = new MaterialPropertyBlock(); rb.isKinematic = true; rb.useGravity = false; } public void Initialize(Tile tile) { Initialize(tile, null); } public void Initialize(Tile tile, Action onReturnToPool = null) { _linkedTile = tile; TileId = tile.Id; _onReturnToPool = onReturnToPool; // Reset physics rb.isKinematic = true; rb.useGravity = false; if (_linkedTile.Type == TileType.Fragile) { SetColor(fragileColor); } else { SetColor(ThemeManager.CurrentTheme.StableColor); } _linkedTile.OnStateChanged += OnTileStateChanged; } private void OnTileStateChanged(Tile tile) { SetVisualState(tile.CurrentState); } public void SetVisualState(TileState state) { switch (state) { case TileState.Stable: StartCoroutine(AnimateColor(ThemeManager.CurrentTheme.StableColor)); break; case TileState.Warning: StartCoroutine(AnimateColor(ThemeManager.CurrentTheme.WarningColor)); break; case TileState.Falling: DropPhysics(); break; case TileState.Destroyed: Dispose(); break; default: throw new ArgumentOutOfRangeException(nameof(state), state, null); } } public void DropPhysics() { rb.isKinematic = false; rb.useGravity = true; col.enabled = false; } public void Dispose() { StartCoroutine(ShrinkAndDestroy()); } public void OnPlayerStep() { _linkedTile?.StepOn(); } public void PulseEmission(float intensity) { LeanTween.cancel(gameObject); transform.localScale = Vector3.one; LeanTween.scale(gameObject, Vector3.one * 1.05f, 0.15f).setEasePunch(); meshRenderer.GetPropertyBlock(_propBlock); var baseColor = _propBlock.GetColor(ColorProperty); var flashColor = baseColor * intensity; LeanTween.value(gameObject, (Color col) => { meshRenderer.GetPropertyBlock(_propBlock); _propBlock.SetColor(EmissionColorProperty, col); meshRenderer.SetPropertyBlock(_propBlock); }, flashColor, Color.black, 0.4f) .setEaseOutQuad(); } public void SetAlpha(float alpha) { _targetAlpha = alpha; meshRenderer.GetPropertyBlock(_propBlock); var currentColor = _propBlock.GetColor(ColorProperty); currentColor.a = _targetAlpha; _propBlock.SetColor(ColorProperty, currentColor); meshRenderer.SetPropertyBlock(_propBlock); } private void SetColor(Color color) { meshRenderer.GetPropertyBlock(_propBlock); color.a = _targetAlpha; _propBlock.SetColor(ColorProperty, color); meshRenderer.SetPropertyBlock(_propBlock); } private IEnumerator AnimateColor(Color targetColor) { meshRenderer.GetPropertyBlock(_propBlock); var startColor = _propBlock.GetColor(ColorProperty); var t = 0f; while (t < 1f) { t += Time.deltaTime * colorSpeed; SetColor(Color.Lerp(startColor, targetColor, t)); yield return null; } } private IEnumerator ShrinkAndDestroy() { var t = 0f; var startScale = transform.localScale; while (t < 0.4f) { t += Time.deltaTime; transform.localScale = Vector3.Lerp(startScale, Vector3.zero, t); yield return null; } if (_onReturnToPool != null) { _onReturnToPool(this); } else { Destroy(gameObject); } } private void OnDestroy() { if (_linkedTile != null) { _linkedTile.OnStateChanged -= OnTileStateChanged; } } } }