Files
BABA_YAGA/Assets/Scripts/GameSetup/Maze/MazeRenderer.cs
2026-04-22 00:29:09 +07:00

105 lines
3.3 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 with safety checks.
/// </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()
{
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);
if (_spawnedCells.TryGetValue(pos, out GameObject oldObj))
{
Destroy(oldObj);
_spawnedCells.Remove(pos);
}
GameObject prefab = visualProfile.GetPrefab(type);
if (prefab == null) return;
// Ensure scale is always positive to avoid BoxCollider issues
float safeScale = Mathf.Max(0.001f, visualProfile.scale);
Vector3 worldPos = new Vector3(x * safeScale, 0, z * safeScale);
GameObject newObj = Instantiate(prefab, worldPos, Quaternion.identity, _container);
newObj.transform.localScale = Vector3.one * safeScale;
_spawnedCells[pos] = newObj;
if (animate && visualProfile.animationDuration > 0)
{
StartCoroutine(AnimateCell(newObj.transform));
}
}
private IEnumerator AnimateCell(Transform target)
{
if (target == null) yield break;
float duration = Mathf.Max(0.01f, visualProfile.animationDuration);
float elapsed = 0;
Vector3 finalScale = target.localScale;
target.localScale = Vector3.one * 0.001f; // Use tiny positive instead of zero
while (elapsed < duration)
{
if (target == null) yield break;
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
float s = Mathf.Sin(t * Mathf.PI * 0.5f);
// Ensure s is never negative
target.localScale = finalScale * Mathf.Max(0.001f, s);
yield return null;
}
if (target != null)
{
target.localScale = finalScale;
}
}
}
}