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.2f, 0.2f, 0.2f); // Dark Grey [SerializeField] private Color warningColor = new Color(1f, 0.2f, 0.2f); // Neon Red [SerializeField] private Color fragileColor = new Color(0.6f, 0.8f, 1f, 0.5f); // Cyan/Glass [SerializeField] private float colorSpeed = 2f; [Self][SerializeField] private Rigidbody rb; [Self][SerializeField] private MeshRenderer meshRenderer; public Rigidbody Rigidbody => rb; public MeshRenderer MeshRenderer => meshRenderer; 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; 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; } public void Dispose() { StartCoroutine(ShrinkAndDestroy()); } public void OnPlayerStep() { _linkedTile?.StepOn(); } public void PulseEmission(float intensity) { StartCoroutine(PulseEmissionRoutine(intensity, 0.1f)); StartCoroutine(PulseScaleRoutine()); } 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 < 1f) { 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; } } private IEnumerator PulseScaleRoutine() { var original = transform.localScale; transform.localScale = original * 1.05f; yield return new WaitForSeconds(0.1f); transform.localScale = original; } private IEnumerator PulseEmissionRoutine(float intensity, float duration) { meshRenderer.GetPropertyBlock(_propBlock); var baseColor = _propBlock.GetColor(ColorProperty); var glowingColor = baseColor * intensity; _propBlock.SetColor(EmissionColorProperty, glowingColor); meshRenderer.SetPropertyBlock(_propBlock); yield return new WaitForSeconds(duration); _propBlock.SetColor(EmissionColorProperty, Color.black); meshRenderer.SetPropertyBlock(_propBlock); } } }