Add maze generation visualization with 2-phase animation
Enhance maze generation animation system with visual feedback during algorithm execution and a two-phase rendering approach: - Phase 1: Preview mode displays simple blocks while algorithms run, with real-time feedback for path checking (valid/invalid/evaluating states) - Phase 2: Sweep 3D modular pieces into place with pop-in animations Updates: - New MazeCellHighlight states (EvaluatingValid, EvaluatingInvalid) for algorithm feedback - Modified all maze algorithms (DFS, Kruskal's, Prim's) to emit visual feedback when checking adjacent cells - New animation components: HighlightLinger (self-destruct highlights) and PopInAnimation (juicy pop-in effect) - Refactored MazeReworkSpawner to support preview prefabs and track spawned object state - New prefabs: Stair room and MazeVisualize variants - Added stepDelay and isPreviewMode controls to MazeAnimator for flexible pacing - Reduced default maze size and adjusted material colors for testing
This commit is contained in:
@@ -29,8 +29,28 @@ namespace Baba_yaga.GameSetup.MazeRework.Algorithms
|
||||
{
|
||||
int nx = current.x + dx[i];
|
||||
int nz = current.y + dz[i];
|
||||
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1 && !visited[nx, nz])
|
||||
candidates.Add(i);
|
||||
int wx = current.x + dx[i] / 2;
|
||||
int wz = current.y + dz[i] / 2;
|
||||
|
||||
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1)
|
||||
{
|
||||
if (!visited[nx, nz])
|
||||
{
|
||||
candidates.Add(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Checked a visited cell
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.EvaluatingInvalid);
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.None);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Checked out of bounds
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.EvaluatingInvalid);
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.None);
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.Count > 0)
|
||||
@@ -46,6 +66,10 @@ namespace Baba_yaga.GameSetup.MazeRework.Algorithms
|
||||
visited[wx, wz] = true;
|
||||
visited[nx2, nz2] = true;
|
||||
|
||||
// Show valid pick
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.EvaluatingValid);
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.None);
|
||||
|
||||
// Move head off current cell
|
||||
onCellChanged?.Invoke(current.x, current.y, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
|
||||
|
||||
|
||||
@@ -38,25 +38,44 @@ namespace Baba_yaga.GameSetup.MazeRework.Algorithms
|
||||
int wx = cx + dx[order[i]] / 2;
|
||||
int wz = cz + dz[order[i]] / 2;
|
||||
|
||||
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1 && !visited[nx, nz])
|
||||
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1)
|
||||
{
|
||||
grid[wx, wz] = MazeReworkCellType.Corridor;
|
||||
grid[nx, nz] = MazeReworkCellType.Corridor;
|
||||
visited[wx, wz] = true;
|
||||
visited[nx, nz] = true;
|
||||
if (!visited[nx, nz])
|
||||
{
|
||||
// Valid path found! Show valid check
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.EvaluatingValid);
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.None);
|
||||
|
||||
// Move head off current cell
|
||||
onCellChanged?.Invoke(cx, cz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
|
||||
|
||||
// Show intermediate wall breaking with head
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
|
||||
grid[wx, wz] = MazeReworkCellType.Corridor;
|
||||
grid[nx, nz] = MazeReworkCellType.Corridor;
|
||||
visited[wx, wz] = true;
|
||||
visited[nx, nz] = true;
|
||||
|
||||
CarveFrom(nx, nz, grid, visited, rng, width, depth, onCellChanged);
|
||||
// Move head off current cell
|
||||
onCellChanged?.Invoke(cx, cz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
|
||||
|
||||
// Show intermediate wall breaking with head
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
|
||||
|
||||
// Clear head from the child cell and restore it here
|
||||
onCellChanged?.Invoke(nx, nz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
|
||||
onCellChanged?.Invoke(cx, cz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
|
||||
CarveFrom(nx, nz, grid, visited, rng, width, depth, onCellChanged);
|
||||
|
||||
// Clear head from the child cell and restore it here
|
||||
onCellChanged?.Invoke(nx, nz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.None);
|
||||
onCellChanged?.Invoke(cx, cz, MazeReworkCellType.Corridor, Animation.MazeCellHighlight.SearchHead);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid path (already visited)
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.EvaluatingInvalid);
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.None);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid path (out of bounds)
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.EvaluatingInvalid);
|
||||
onCellChanged?.Invoke(wx, wz, MazeReworkCellType.Wall, Animation.MazeCellHighlight.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,9 +49,13 @@ namespace Baba_yaga.GameSetup.MazeRework.Algorithms
|
||||
|
||||
// Show evaluating highlight
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.Evaluating);
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.None);
|
||||
|
||||
if (uf.Find(cellId[ax, az]) != uf.Find(cellId[bx, bz]))
|
||||
{
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.EvaluatingValid);
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.None);
|
||||
|
||||
grid[wx, wz] = MazeReworkCellType.Corridor;
|
||||
grid[ax, az] = MazeReworkCellType.Corridor;
|
||||
grid[bx, bz] = MazeReworkCellType.Corridor;
|
||||
@@ -65,7 +69,8 @@ namespace Baba_yaga.GameSetup.MazeRework.Algorithms
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear evaluate highlight
|
||||
// Invalid
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.EvaluatingInvalid);
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,17 @@ namespace Baba_yaga.GameSetup.MazeRework.Algorithms
|
||||
|
||||
if (visited[nx, nz])
|
||||
{
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.EvaluatingInvalid);
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.None);
|
||||
|
||||
// Clear the frontier highlight if this cell was already visited by another path
|
||||
onCellChanged?.Invoke(nx, nz, grid[nx, nz], Animation.MazeCellHighlight.None);
|
||||
continue;
|
||||
}
|
||||
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.EvaluatingValid);
|
||||
onCellChanged?.Invoke(wx, wz, grid[wx, wz], Animation.MazeCellHighlight.None);
|
||||
|
||||
grid[wx, wz] = MazeReworkCellType.Corridor;
|
||||
grid[nx, nz] = MazeReworkCellType.Corridor;
|
||||
visited[wx, wz] = true;
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Baba_yaga.GameSetup.MazeRework.Animation
|
||||
{
|
||||
public class HighlightLinger : MonoBehaviour
|
||||
{
|
||||
public float lingerTime = 0.4f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
StartCoroutine(LingerAndDie());
|
||||
}
|
||||
|
||||
private IEnumerator LingerAndDie()
|
||||
{
|
||||
yield return new WaitForSeconds(lingerTime);
|
||||
|
||||
// Optional: fade out logic could go here
|
||||
float fadeOutTime = 0.1f;
|
||||
float time = 0f;
|
||||
Vector3 startScale = transform.localScale;
|
||||
|
||||
while (time < fadeOutTime)
|
||||
{
|
||||
time += Time.deltaTime;
|
||||
transform.localScale = Vector3.Lerp(startScale, Vector3.zero, time / fadeOutTime);
|
||||
yield return null;
|
||||
}
|
||||
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e88f5f0389dbd043937d08377e3168a
|
||||
@@ -7,9 +7,12 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
|
||||
public class MazeAnimator : MonoBehaviour
|
||||
{
|
||||
[Header("Animation Settings")]
|
||||
[Tooltip("How many cell changes to process in a single frame. Higher = faster generation.")]
|
||||
[Tooltip("How many cell changes to process in a single frame (if stepDelay is 0).")]
|
||||
[Min(1)]
|
||||
public int cellsPerFrame = 5;
|
||||
public int cellsPerFrame = 1; // Default to 1 so you can see it clearly!
|
||||
|
||||
[Tooltip("Delay in seconds between every single cell change. Set to > 0 to actually see the checking flashes!")]
|
||||
public float stepDelay = 0.05f;
|
||||
|
||||
[Tooltip("Extra delay (in seconds) between major generation phases (like switching from Rooms to Carving).")]
|
||||
public float delayBetweenPhases = 0.5f;
|
||||
@@ -63,6 +66,7 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
|
||||
}
|
||||
|
||||
spawner.Clear();
|
||||
spawner.isPreviewMode = true; // Phase 1: Simple preview blocks
|
||||
|
||||
MazeAnimationPhase currentPhase = MazeAnimationPhase.RoomPlacement;
|
||||
int processedThisFrame = 0;
|
||||
@@ -80,13 +84,29 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
|
||||
}
|
||||
|
||||
workingGrid[change.X, change.Z] = change.Type;
|
||||
workingHighlights[change.X, change.Z] = change.Highlight;
|
||||
|
||||
if (change.Highlight == MazeCellHighlight.EvaluatingValid ||
|
||||
change.Highlight == MazeCellHighlight.EvaluatingInvalid ||
|
||||
change.Highlight == MazeCellHighlight.Evaluating)
|
||||
{
|
||||
// Linger flashes independently so they don't get erased if cellsPerFrame > 1
|
||||
spawner.FlashHighlight(change.Highlight, change.X, change.Z, yOffset, container);
|
||||
}
|
||||
else
|
||||
{
|
||||
workingHighlights[change.X, change.Z] = change.Highlight;
|
||||
}
|
||||
|
||||
// Refresh the cell and its neighbors in the spawner
|
||||
spawner.RefreshCell(workingGrid, workingHighlights, change.X, change.Z, yOffset, container);
|
||||
|
||||
processedThisFrame++;
|
||||
if (processedThisFrame >= cellsPerFrame)
|
||||
|
||||
if (stepDelay > 0f)
|
||||
{
|
||||
yield return new WaitForSeconds(stepDelay);
|
||||
}
|
||||
else if (processedThisFrame >= cellsPerFrame)
|
||||
{
|
||||
yield return null; // Wait for next frame
|
||||
processedThisFrame = 0;
|
||||
@@ -96,21 +116,52 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
|
||||
// Wait a moment at the end before finalizing
|
||||
if (delayBetweenPhases > 0f)
|
||||
{
|
||||
yield return new WaitForSeconds(delayBetweenPhases);
|
||||
yield return new WaitForSeconds(delayBetweenPhases * 2f); // Extra pause to admire the 2D layout!
|
||||
}
|
||||
|
||||
// One final sync with finalGrid just to be absolutely safe
|
||||
// --- Phase 2: Render 3D Map ---
|
||||
spawner.isPreviewMode = false;
|
||||
|
||||
// Sweep across the grid and spawn the heavy 3D modular pieces
|
||||
for (int z = 0; z < depth; z++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
bool gridChanged = workingGrid[x, z] != finalGrid[x, z];
|
||||
bool highlightChanged = workingHighlights[x, z] != MazeCellHighlight.None;
|
||||
|
||||
if (gridChanged || highlightChanged)
|
||||
workingGrid[x, z] = finalGrid[x, z];
|
||||
workingHighlights[x, z] = MazeCellHighlight.None;
|
||||
|
||||
// Only yield when we actually spawn a piece to create a cool sweep wave!
|
||||
if (finalGrid[x, z] != MazeReworkCellType.Wall)
|
||||
{
|
||||
workingGrid[x, z] = finalGrid[x, z];
|
||||
workingHighlights[x, z] = MazeCellHighlight.None;
|
||||
// 1. Flash an Evaluating highlight to visualize "choosing" this cell
|
||||
spawner.FlashHighlight(MazeCellHighlight.EvaluatingValid, x, z, yOffset, container);
|
||||
|
||||
if (stepDelay > 0f)
|
||||
{
|
||||
yield return new WaitForSeconds(stepDelay * 0.5f); // Short pause for the check
|
||||
}
|
||||
|
||||
// 2. Spawn the actual piece
|
||||
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
|
||||
|
||||
// Wait a tiny fraction of a second to create the sweeping wave effect
|
||||
if (stepDelay > 0f)
|
||||
{
|
||||
yield return new WaitForSeconds(stepDelay * 0.5f); // faster than the algorithm checks
|
||||
}
|
||||
else
|
||||
{
|
||||
processedThisFrame++;
|
||||
if (processedThisFrame >= cellsPerFrame * 2) // Twice as fast as algorithm phase
|
||||
{
|
||||
yield return null;
|
||||
processedThisFrame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Even if it's a wall, refresh it to clear the preview walls (if any)
|
||||
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
|
||||
None,
|
||||
SearchHead, // Current cell being evaluated (DFS, Prim's)
|
||||
Frontier, // Known candidate cells (Prim's)
|
||||
Evaluating // Walls currently being considered (Kruskal's)
|
||||
Evaluating, // Walls currently being considered (Kruskal's)
|
||||
EvaluatingValid,
|
||||
EvaluatingInvalid
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Baba_yaga.GameSetup.MazeRework.Animation
|
||||
{
|
||||
public class PopInAnimation : MonoBehaviour
|
||||
{
|
||||
public float duration = 0.25f;
|
||||
public float delay = 0f;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
StartCoroutine(AnimateScale());
|
||||
}
|
||||
|
||||
private IEnumerator AnimateScale()
|
||||
{
|
||||
Vector3 targetScale = transform.localScale;
|
||||
Quaternion targetRot = transform.localRotation;
|
||||
|
||||
transform.localScale = Vector3.zero;
|
||||
// Start rotation off by 90 degrees on Y axis so it visibly "spins" into the correct orientation
|
||||
transform.localRotation = targetRot * Quaternion.Euler(0, -90f, 0);
|
||||
|
||||
if (delay > 0f)
|
||||
yield return new WaitForSeconds(delay);
|
||||
|
||||
float time = 0f;
|
||||
while (time < duration)
|
||||
{
|
||||
time += Time.deltaTime;
|
||||
float t = time / duration;
|
||||
|
||||
// easeOutBack formula for a juicy overshoot effect
|
||||
float c1 = 1.70158f;
|
||||
float c3 = c1 + 1f;
|
||||
float easeT = 1f + c3 * Mathf.Pow(t - 1f, 3f) + c1 * Mathf.Pow(t - 1f, 2f);
|
||||
|
||||
transform.localScale = targetScale * Mathf.Max(0f, easeT);
|
||||
|
||||
// Spin into place using easeOut
|
||||
float easeOutQuad = 1 - (1 - t) * (1 - t);
|
||||
transform.localRotation = Quaternion.SlerpUnclamped(targetRot * Quaternion.Euler(0, -90f, 0), targetRot, easeT);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
transform.localScale = targetScale;
|
||||
transform.localRotation = targetRot;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43114e744edaec247a2ece63347b73cd
|
||||
@@ -28,6 +28,16 @@ namespace Baba_yaga.GameSetup.MazeRework
|
||||
[Tooltip("Prefab for the End cell (player exit point). Auto-rotates based on neighbors.")]
|
||||
public GameObject endPrefab;
|
||||
|
||||
[Header("Preview Mode Settings (Phase 1)")]
|
||||
[Tooltip("If true, the spawner will only spawn simple preview blocks instead of full 3D modular pieces.")]
|
||||
public bool isPreviewMode = false;
|
||||
|
||||
[Tooltip("Simple prefab to represent carved paths during the algorithm phase (e.g. a flat plane or basic cube).")]
|
||||
public GameObject previewPathPrefab;
|
||||
|
||||
[Tooltip("Simple prefab to represent walls during the algorithm phase (optional, can be left null).")]
|
||||
public GameObject previewWallPrefab;
|
||||
|
||||
[Header("Highlight Prefabs (Animation Only)")]
|
||||
public GameObject searchHeadPrefab;
|
||||
public GameObject frontierPrefab;
|
||||
@@ -53,7 +63,14 @@ namespace Baba_yaga.GameSetup.MazeRework
|
||||
[Tooltip("Physical distance between each grid cell center.")]
|
||||
public float spacing = 3.0f;
|
||||
|
||||
private readonly Dictionary<Vector2Int, GameObject> _spawnedObjects = new Dictionary<Vector2Int, GameObject>();
|
||||
private struct SpawnedCellData
|
||||
{
|
||||
public GameObject Instance;
|
||||
public GameObject Prefab;
|
||||
public float Rotation;
|
||||
}
|
||||
|
||||
private readonly Dictionary<Vector2Int, SpawnedCellData> _spawnedGridCells = new Dictionary<Vector2Int, SpawnedCellData>();
|
||||
private readonly Dictionary<Vector2Int, GameObject> _spawnedHighlights = new Dictionary<Vector2Int, GameObject>();
|
||||
|
||||
private void Start()
|
||||
@@ -80,12 +97,12 @@ namespace Baba_yaga.GameSetup.MazeRework
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var obj in _spawnedObjects.Values)
|
||||
foreach (var data in _spawnedGridCells.Values)
|
||||
{
|
||||
if (obj == null) continue;
|
||||
if (Application.isPlaying) Destroy(obj); else DestroyImmediate(obj);
|
||||
if (data.Instance == null) continue;
|
||||
if (Application.isPlaying) Destroy(data.Instance); else DestroyImmediate(data.Instance);
|
||||
}
|
||||
_spawnedObjects.Clear();
|
||||
_spawnedGridCells.Clear();
|
||||
|
||||
foreach (var obj in _spawnedHighlights.Values)
|
||||
{
|
||||
@@ -131,6 +148,23 @@ namespace Baba_yaga.GameSetup.MazeRework
|
||||
RefreshSingleCell(grid, highlights, x, z - 1, width, depth, yOffset, container);
|
||||
}
|
||||
|
||||
public void FlashHighlight(MazeCellHighlight hType, int x, int z, float yOffset, Transform container)
|
||||
{
|
||||
GameObject hPrefab = null;
|
||||
if (hType == MazeCellHighlight.EvaluatingValid) hPrefab = searchHeadPrefab;
|
||||
else if (hType == MazeCellHighlight.EvaluatingInvalid) hPrefab = evaluatingPrefab;
|
||||
else if (hType == MazeCellHighlight.Evaluating) hPrefab = evaluatingPrefab;
|
||||
|
||||
if (hPrefab != null)
|
||||
{
|
||||
Vector3 localPos = new Vector3(x * spacing, yOffset, z * spacing);
|
||||
GameObject spawnedH = Instantiate(hPrefab, container != null ? container : transform);
|
||||
spawnedH.transform.localPosition = localPos;
|
||||
spawnedH.name = $"Flash_{hType}_{x}_{z}";
|
||||
spawnedH.AddComponent<Animation.HighlightLinger>(); // Self-destructs after lingering
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshSingleCell(MazeReworkCellType[,] grid, MazeCellHighlight[,] highlights, int x, int z, int width, int depth, float yOffset, Transform container)
|
||||
{
|
||||
if (x < 0 || x >= width || z < 0 || z >= depth) return;
|
||||
@@ -153,6 +187,8 @@ namespace Baba_yaga.GameSetup.MazeRework
|
||||
if (hType == MazeCellHighlight.SearchHead) hPrefab = searchHeadPrefab;
|
||||
else if (hType == MazeCellHighlight.Frontier) hPrefab = frontierPrefab;
|
||||
else if (hType == MazeCellHighlight.Evaluating) hPrefab = evaluatingPrefab;
|
||||
else if (hType == MazeCellHighlight.EvaluatingValid) hPrefab = searchHeadPrefab; // Use same prefab or we can add new ones, but for now fallback to Head/Evaluating
|
||||
else if (hType == MazeCellHighlight.EvaluatingInvalid) hPrefab = evaluatingPrefab;
|
||||
|
||||
if (hPrefab != null)
|
||||
{
|
||||
@@ -160,58 +196,86 @@ namespace Baba_yaga.GameSetup.MazeRework
|
||||
GameObject spawnedH = Instantiate(hPrefab, container != null ? container : transform);
|
||||
spawnedH.transform.localPosition = localPos;
|
||||
spawnedH.name = $"Highlight_{hType}_{x}_{z}";
|
||||
// Highlights should pop instantly without animation since they are short-lived cursors
|
||||
_spawnedHighlights[pos] = spawnedH;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Process Grid Cells
|
||||
if (type == MazeReworkCellType.Wall)
|
||||
GameObject targetPrefab = null;
|
||||
float targetRot = 0f;
|
||||
string targetName = "";
|
||||
|
||||
if (isPreviewMode)
|
||||
{
|
||||
if (_spawnedObjects.TryGetValue(pos, out GameObject existing))
|
||||
if (type == MazeReworkCellType.Wall)
|
||||
{
|
||||
if (Application.isPlaying) Destroy(existing);
|
||||
else DestroyImmediate(existing);
|
||||
_spawnedObjects.Remove(pos);
|
||||
targetPrefab = previewWallPrefab;
|
||||
targetName = "PreviewWall";
|
||||
}
|
||||
else
|
||||
{
|
||||
targetPrefab = previewPathPrefab;
|
||||
targetName = "PreviewPath";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type != MazeReworkCellType.Wall)
|
||||
{
|
||||
if (type == MazeReworkCellType.Start && beginningPrefab != null)
|
||||
{
|
||||
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
|
||||
targetPrefab = beginningPrefab;
|
||||
targetRot = baseRot + beginningRotationOffset;
|
||||
targetName = "Beginning";
|
||||
}
|
||||
else if (type == MazeReworkCellType.End && endPrefab != null)
|
||||
{
|
||||
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
|
||||
targetPrefab = endPrefab;
|
||||
targetRot = baseRot + endRotationOffset;
|
||||
targetName = "End";
|
||||
}
|
||||
else
|
||||
{
|
||||
(targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
|
||||
targetName = $"{type}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (targetPrefab == null)
|
||||
{
|
||||
if (_spawnedGridCells.TryGetValue(pos, out var existing))
|
||||
{
|
||||
if (Application.isPlaying) Destroy(existing.Instance);
|
||||
else DestroyImmediate(existing.Instance);
|
||||
_spawnedGridCells.Remove(pos);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == MazeReworkCellType.Start && beginningPrefab != null)
|
||||
// If it already exists and is the identical prefab/rotation, DO NOT recreate it!
|
||||
// This prevents PopInAnimation from constantly restarting when neighbors are evaluated.
|
||||
if (_spawnedGridCells.TryGetValue(pos, out var existingData))
|
||||
{
|
||||
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
|
||||
SpawnPrefab(beginningPrefab, x, yOffset, z, baseRot + beginningRotationOffset, container, "Beginning");
|
||||
return;
|
||||
if (existingData.Prefab == targetPrefab && Mathf.Approximately(existingData.Rotation, targetRot))
|
||||
{
|
||||
return; // No change needed!
|
||||
}
|
||||
if (Application.isPlaying) Destroy(existingData.Instance);
|
||||
else DestroyImmediate(existingData.Instance);
|
||||
}
|
||||
|
||||
if (type == MazeReworkCellType.End && endPrefab != null)
|
||||
{
|
||||
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
|
||||
SpawnPrefab(endPrefab, x, yOffset, z, baseRot + endRotationOffset, container, "End");
|
||||
return;
|
||||
}
|
||||
|
||||
(GameObject modularPrefab, float yRotation) = GetModularPrefabAndRotation(grid, x, z, width, depth);
|
||||
if (modularPrefab != null)
|
||||
{
|
||||
SpawnPrefab(modularPrefab, x, yOffset, z, yRotation, container, $"{type}");
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnPrefab(GameObject prefab, int x, float y, int z, float yRotation, Transform container, string namePrefix)
|
||||
{
|
||||
Vector3 localPosition = new Vector3(x * spacing, y, z * spacing);
|
||||
GameObject spawnedObj = Instantiate(prefab, container != null ? container : transform);
|
||||
Vector3 localPosition = new Vector3(x * spacing, yOffset, z * spacing);
|
||||
GameObject spawnedObj = Instantiate(targetPrefab, container != null ? container : transform);
|
||||
spawnedObj.transform.localPosition = localPosition;
|
||||
spawnedObj.transform.localRotation = Quaternion.Euler(0f, yRotation, 0f);
|
||||
spawnedObj.name = $"{namePrefix}_{x}_{z}";
|
||||
spawnedObj.transform.localRotation = Quaternion.Euler(0f, targetRot, 0f);
|
||||
spawnedObj.name = $"{targetName}_{x}_{z}";
|
||||
spawnedObj.AddComponent<Animation.PopInAnimation>();
|
||||
|
||||
var pos = new Vector2Int(x, z);
|
||||
if (_spawnedObjects.TryGetValue(pos, out GameObject existing))
|
||||
{
|
||||
if (Application.isPlaying) Destroy(existing);
|
||||
else DestroyImmediate(existing);
|
||||
}
|
||||
_spawnedObjects[pos] = spawnedObj;
|
||||
_spawnedGridCells[pos] = new SpawnedCellData { Instance = spawnedObj, Prefab = targetPrefab, Rotation = targetRot };
|
||||
}
|
||||
|
||||
private (GameObject, float) GetModularPrefabAndRotation(MazeReworkCellType[,] grid, int x, int z, int width, int depth)
|
||||
|
||||
Reference in New Issue
Block a user