Files
decay-grid/Assets/Scripts/Infrastructure/Unity/TileViewAdapter.cs

189 lines
5.6 KiB
C#

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 EmissionIntensity = Shader.PropertyToID("_EmissionIntensity");
private Action<TileViewAdapter> _onReturnToPool;
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<TileViewAdapter> 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.2f));
StartCoroutine(PulseScaleRoutine());
}
private void SetColor(Color color)
{
meshRenderer.GetPropertyBlock(_propBlock);
_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 originalIntensity = _propBlock.GetFloat(EmissionIntensity);
_propBlock.SetFloat(EmissionIntensity, intensity);
meshRenderer.SetPropertyBlock(_propBlock);
yield return new WaitForSeconds(duration);
_propBlock.SetFloat(EmissionIntensity, originalIntensity);
meshRenderer.SetPropertyBlock(_propBlock);
}
}
}