103 lines
3.2 KiB
C#
103 lines
3.2 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Hallucinate.GameSetup.Maze
|
|
{
|
|
/// <summary>
|
|
/// Responsible for the visual representation of the maze.
|
|
/// Handles spawning, pooling, and animations.
|
|
/// </summary>
|
|
public class MazeRenderer : MonoBehaviour
|
|
{
|
|
[SerializeField] private MazeVisualProfile visualProfile;
|
|
|
|
private readonly Dictionary<Vector2Int, GameObject> _spawnedCells = new Dictionary<Vector2Int, GameObject>();
|
|
private Transform _container;
|
|
|
|
public void Initialize(MazeGrid grid, Transform container)
|
|
{
|
|
_container = container;
|
|
grid.OnCellChanged += HandleCellChanged;
|
|
|
|
// Initial render
|
|
for (int z = 0; z < grid.Depth; z++)
|
|
{
|
|
for (int x = 0; x < grid.Width; x++)
|
|
{
|
|
UpdateCellVisual(x, z, grid.GetCell(x, z), false);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
// IMPORTANT: Stop all running animations to prevent accessing destroyed objects
|
|
StopAllCoroutines();
|
|
|
|
foreach (var cell in _spawnedCells.Values)
|
|
{
|
|
if (cell != null) Destroy(cell);
|
|
}
|
|
_spawnedCells.Clear();
|
|
}
|
|
|
|
private void HandleCellChanged(int x, int z, MazeCellType type)
|
|
{
|
|
UpdateCellVisual(x, z, type, true);
|
|
}
|
|
|
|
private void UpdateCellVisual(int x, int z, MazeCellType type, bool animate)
|
|
{
|
|
Vector2Int pos = new Vector2Int(x, z);
|
|
|
|
// Remove old visual if exists
|
|
if (_spawnedCells.TryGetValue(pos, out GameObject oldObj))
|
|
{
|
|
Destroy(oldObj);
|
|
_spawnedCells.Remove(pos);
|
|
}
|
|
|
|
GameObject prefab = visualProfile.GetPrefab(type);
|
|
if (prefab == null) return;
|
|
|
|
Vector3 worldPos = new Vector3(x * visualProfile.scale, 0, z * visualProfile.scale);
|
|
GameObject newObj = Instantiate(prefab, worldPos, Quaternion.identity, _container);
|
|
newObj.transform.localScale = Vector3.one * visualProfile.scale;
|
|
_spawnedCells[pos] = newObj;
|
|
|
|
if (animate)
|
|
{
|
|
StartCoroutine(AnimateCell(newObj.transform));
|
|
}
|
|
}
|
|
|
|
private IEnumerator AnimateCell(Transform target)
|
|
{
|
|
if (target == null) yield break;
|
|
|
|
float duration = visualProfile.animationDuration;
|
|
float elapsed = 0;
|
|
Vector3 finalScale = target.localScale;
|
|
target.localScale = Vector3.zero;
|
|
|
|
while (elapsed < duration)
|
|
{
|
|
// Extra safety check in case the object is destroyed mid-animation
|
|
if (target == null) yield break;
|
|
|
|
elapsed += Time.deltaTime;
|
|
float t = elapsed / duration;
|
|
float s = Mathf.Sin(t * Mathf.PI * 0.5f);
|
|
target.localScale = finalScale * s;
|
|
yield return null;
|
|
}
|
|
|
|
if (target != null)
|
|
{
|
|
target.localScale = finalScale;
|
|
}
|
|
}
|
|
}
|
|
}
|