update
This commit is contained in:
@@ -16,13 +16,13 @@ namespace Hallucinate.GameSetup.Maze
|
||||
for (int i = 0; i < HorizontalCrawlerCount; i++) CrawlH(grid, 0);
|
||||
}
|
||||
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, int cellsPerFrame)
|
||||
{
|
||||
for (int i = 0; i < VerticalCrawlerCount; i++) yield return CrawlV(grid, interval);
|
||||
for (int i = 0; i < HorizontalCrawlerCount; i++) yield return CrawlH(grid, interval);
|
||||
for (int i = 0; i < VerticalCrawlerCount; i++) yield return CrawlV(grid, cellsPerFrame);
|
||||
for (int i = 0; i < HorizontalCrawlerCount; i++) yield return CrawlH(grid, cellsPerFrame);
|
||||
}
|
||||
|
||||
private IEnumerator CrawlV(MazeGrid grid, float interval)
|
||||
private IEnumerator CrawlV(MazeGrid grid, int cellsPerFrame)
|
||||
{
|
||||
bool done = false;
|
||||
int x = Random.Range(MinBoundary, grid.Width - MinBoundary);
|
||||
@@ -31,7 +31,12 @@ namespace Hallucinate.GameSetup.Maze
|
||||
while (!done)
|
||||
{
|
||||
grid.SetCell(x, z, MazeCellType.Processing);
|
||||
if (interval > 0) yield return new WaitForSeconds(interval);
|
||||
MazeManager.cellsProcessedThisFrame++;
|
||||
if (MazeManager.cellsProcessedThisFrame >= cellsPerFrame)
|
||||
{
|
||||
MazeManager.cellsProcessedThisFrame = 0;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
grid.SetCell(x, z, MazeCellType.Corridor);
|
||||
|
||||
@@ -48,7 +53,7 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator CrawlH(MazeGrid grid, float interval)
|
||||
private IEnumerator CrawlH(MazeGrid grid, int cellsPerFrame)
|
||||
{
|
||||
bool done = false;
|
||||
int x = MinBoundary;
|
||||
@@ -57,7 +62,12 @@ namespace Hallucinate.GameSetup.Maze
|
||||
while (!done)
|
||||
{
|
||||
grid.SetCell(x, z, MazeCellType.Processing);
|
||||
if (interval > 0) yield return new WaitForSeconds(interval);
|
||||
MazeManager.cellsProcessedThisFrame++;
|
||||
if (MazeManager.cellsProcessedThisFrame >= cellsPerFrame)
|
||||
{
|
||||
MazeManager.cellsProcessedThisFrame = 0;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
grid.SetCell(x, z, MazeCellType.Corridor);
|
||||
|
||||
|
||||
@@ -14,6 +14,6 @@ namespace Hallucinate.GameSetup.Maze
|
||||
/// <summary>
|
||||
/// Generates the maze step-by-step for visualization.
|
||||
/// </summary>
|
||||
System.Collections.IEnumerator GenerateStepByStep(MazeGrid grid, float interval);
|
||||
System.Collections.IEnumerator GenerateStepByStep(MazeGrid grid, int cellsPerFrame);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +37,25 @@ namespace Hallucinate.GameSetup.Maze
|
||||
[PropertyRange(5, 200)]
|
||||
[SerializeField] private int depth = 30;
|
||||
|
||||
[BoxGroup("Debug")]
|
||||
[SerializeField] private bool debugMode = true;
|
||||
[BoxGroup("Animation")]
|
||||
[SerializeField] private bool animateGeneration = true;
|
||||
|
||||
[BoxGroup("Debug")]
|
||||
[ShowIf(nameof(debugMode))]
|
||||
[PropertyRange(0.001f, 0.5f)]
|
||||
[SerializeField] private float visualizationInterval = 0.05f;
|
||||
[BoxGroup("Animation")]
|
||||
[ShowIf(nameof(animateGeneration))]
|
||||
[PropertyRange(1, 500)]
|
||||
[LabelText("Generation Speed (Cells/Frame)")]
|
||||
[SerializeField] private int generationSpeed = 50;
|
||||
|
||||
public static int cellsProcessedThisFrame;
|
||||
|
||||
[BoxGroup("Animation")]
|
||||
[ShowIf(nameof(animateGeneration))]
|
||||
public MazeRenderer.CellAnimationType cellAnimationType = MazeRenderer.CellAnimationType.ScaleUp;
|
||||
|
||||
[BoxGroup("Progress")]
|
||||
[ProgressBar(0, 100)]
|
||||
[ShowInInspector, ReadOnly]
|
||||
private float completionPercentage;
|
||||
|
||||
[BoxGroup("References")]
|
||||
[Required]
|
||||
@@ -74,6 +86,7 @@ namespace Hallucinate.GameSetup.Maze
|
||||
|
||||
private MazeGrid _grid;
|
||||
private Coroutine _generationCoroutine;
|
||||
private HashSet<Vector3Int> _modifiedCells = new HashSet<Vector3Int>();
|
||||
|
||||
private void Start()
|
||||
{
|
||||
@@ -88,6 +101,25 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
[ContextMenu("Clear Maze")]
|
||||
[Button("Clear Maze", ButtonSizes.Large)]
|
||||
public void ClearMaze()
|
||||
{
|
||||
if (_generationCoroutine != null)
|
||||
{
|
||||
StopCoroutine(_generationCoroutine);
|
||||
_generationCoroutine = null;
|
||||
}
|
||||
|
||||
if (mazeRenderer != null)
|
||||
{
|
||||
mazeRenderer.Clear();
|
||||
}
|
||||
|
||||
completionPercentage = 0f;
|
||||
_modifiedCells?.Clear();
|
||||
}
|
||||
|
||||
[ContextMenu("Regenerate")]
|
||||
[Button("Regenerate Maze", ButtonSizes.Large)]
|
||||
public void Regenerate()
|
||||
@@ -109,24 +141,85 @@ namespace Hallucinate.GameSetup.Maze
|
||||
mazes = new MazeGrid[1];
|
||||
}
|
||||
|
||||
if (_generationCoroutine != null)
|
||||
ClearMaze();
|
||||
|
||||
mazeRenderer.currentAnimationType = cellAnimationType;
|
||||
|
||||
if (animateGeneration)
|
||||
{
|
||||
StopCoroutine(_generationCoroutine);
|
||||
_generationCoroutine = StartCoroutine(GenerateMazeRoutine());
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateMazeInstant();
|
||||
}
|
||||
}
|
||||
|
||||
mazeRenderer.Clear();
|
||||
private void GenerateMazeInstant()
|
||||
{
|
||||
_modifiedCells.Clear();
|
||||
completionPercentage = 0f;
|
||||
|
||||
// Step 1: Initialize all maze floors
|
||||
for (int i = 0; i < mazes.Length; i++)
|
||||
{
|
||||
mazes[i] = new MazeGrid(width, depth);
|
||||
mazes[i].Level = i;
|
||||
|
||||
// Generate each floor using the selected algorithm
|
||||
IMazeAlgorithm algorithmForFloor = GetAlgorithm(selectedAlgorithm);
|
||||
algorithmForFloor.Generate(mazes[i]);
|
||||
}
|
||||
|
||||
GenerateConnections();
|
||||
|
||||
for (int i = 0; i < mazes.Length; i++)
|
||||
{
|
||||
mazeRenderer.Initialize(mazes[i], mazeContainer, i == 0);
|
||||
}
|
||||
if (mazes.Length > 0) _grid = mazes[0];
|
||||
|
||||
completionPercentage = 100f;
|
||||
}
|
||||
|
||||
private IEnumerator GenerateMazeRoutine()
|
||||
{
|
||||
_modifiedCells.Clear();
|
||||
completionPercentage = 0f;
|
||||
|
||||
for (int i = 0; i < mazes.Length; i++)
|
||||
{
|
||||
mazes[i] = new MazeGrid(width, depth);
|
||||
mazes[i].Level = i;
|
||||
int floorIndex = i;
|
||||
|
||||
mazes[i].OnCellChanged += (x, z, type) =>
|
||||
{
|
||||
if (type != MazeCellType.Wall)
|
||||
{
|
||||
_modifiedCells.Add(new Vector3Int(x, floorIndex, z));
|
||||
int totalCells = width * depth * mazes.Length;
|
||||
// Approximate the progress to reach roughly 100% since algorithms don't visit all cells
|
||||
float fillRatio = 0.6f;
|
||||
completionPercentage = Mathf.Clamp((_modifiedCells.Count / ((float)totalCells * fillRatio)) * 100f, 0, 99f);
|
||||
}
|
||||
};
|
||||
|
||||
mazeRenderer.Initialize(mazes[i], mazeContainer, i == 0);
|
||||
|
||||
IMazeAlgorithm algorithmForFloor = GetAlgorithm(selectedAlgorithm);
|
||||
cellsProcessedThisFrame = 0;
|
||||
yield return StartCoroutine(algorithmForFloor.GenerateStepByStep(mazes[i], generationSpeed));
|
||||
}
|
||||
|
||||
GenerateConnections();
|
||||
|
||||
if (mazes.Length > 0) _grid = mazes[0];
|
||||
|
||||
completionPercentage = 100f;
|
||||
_generationCoroutine = null;
|
||||
}
|
||||
|
||||
private void GenerateConnections()
|
||||
{
|
||||
// Step 2: Create connections between adjacent floors
|
||||
for (int i = 0; i < mazes.Length - 1; i++)
|
||||
{
|
||||
@@ -167,35 +260,8 @@ namespace Hallucinate.GameSetup.Maze
|
||||
connectionsMade++;
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Render all floors
|
||||
if (mazes.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < mazes.Length; i++)
|
||||
{
|
||||
mazeRenderer.Initialize(mazes[i], mazeContainer, i == 0);
|
||||
}
|
||||
_grid = mazes[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// _grid = new MazeGrid(width, depth);
|
||||
// mazeRenderer.Initialize(_grid, mazeContainer);
|
||||
|
||||
IMazeAlgorithm algorithm = GetAlgorithm(selectedAlgorithm);
|
||||
|
||||
if (debugMode)
|
||||
{
|
||||
_generationCoroutine = StartCoroutine(algorithm.GenerateStepByStep(_grid, visualizationInterval));
|
||||
}
|
||||
else
|
||||
{
|
||||
algorithm.Generate(_grid);
|
||||
}
|
||||
_grid = new MazeGrid(width, depth);
|
||||
mazeRenderer.Initialize(_grid, mazeContainer);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShuffleList<T>(List<T> list)
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace Hallucinate.GameSetup.Maze
|
||||
|
||||
public float Scale => visualProfile != null ? visualProfile.scale : 1f;
|
||||
|
||||
public enum CellAnimationType { None, ScaleUp, DropDown, SpinIn }
|
||||
|
||||
[HideInInspector]
|
||||
public CellAnimationType currentAnimationType = CellAnimationType.ScaleUp;
|
||||
|
||||
[ShowInInspector]
|
||||
[ReadOnly]
|
||||
[BoxGroup("Runtime")]
|
||||
@@ -294,10 +299,27 @@ namespace Hallucinate.GameSetup.Maze
|
||||
{
|
||||
if (target == null) yield break;
|
||||
|
||||
if (currentAnimationType == CellAnimationType.None) yield break;
|
||||
|
||||
float duration = Mathf.Max(0.01f, visualProfile.animationDuration);
|
||||
float elapsed = 0;
|
||||
Vector3 finalScale = target.localScale;
|
||||
target.localScale = Vector3.one * 0.001f;
|
||||
Vector3 finalPosition = target.localPosition;
|
||||
Quaternion finalRotation = target.localRotation;
|
||||
|
||||
if (currentAnimationType == CellAnimationType.ScaleUp)
|
||||
{
|
||||
target.localScale = Vector3.one * 0.001f;
|
||||
}
|
||||
else if (currentAnimationType == CellAnimationType.DropDown)
|
||||
{
|
||||
target.localPosition = finalPosition + Vector3.up * 5f;
|
||||
}
|
||||
else if (currentAnimationType == CellAnimationType.SpinIn)
|
||||
{
|
||||
target.localScale = Vector3.one * 0.001f;
|
||||
target.localRotation = finalRotation * Quaternion.Euler(0, 180, 0);
|
||||
}
|
||||
|
||||
while (elapsed < duration)
|
||||
{
|
||||
@@ -305,16 +327,32 @@ namespace Hallucinate.GameSetup.Maze
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
float s = Mathf.Sin(t * Mathf.PI * 0.5f);
|
||||
|
||||
target.localScale = finalScale * Mathf.Max(0.001f, s);
|
||||
if (currentAnimationType == CellAnimationType.ScaleUp)
|
||||
{
|
||||
float s = Mathf.Sin(t * Mathf.PI * 0.5f);
|
||||
target.localScale = finalScale * Mathf.Max(0.001f, s);
|
||||
}
|
||||
else if (currentAnimationType == CellAnimationType.DropDown)
|
||||
{
|
||||
float s = Mathf.Sin(t * Mathf.PI * 0.5f);
|
||||
target.localPosition = Vector3.Lerp(finalPosition + Vector3.up * 5f, finalPosition, s);
|
||||
}
|
||||
else if (currentAnimationType == CellAnimationType.SpinIn)
|
||||
{
|
||||
float s = Mathf.Sin(t * Mathf.PI * 0.5f);
|
||||
target.localScale = finalScale * Mathf.Max(0.001f, s);
|
||||
target.localRotation = Quaternion.Lerp(finalRotation * Quaternion.Euler(0, 180, 0), finalRotation, s);
|
||||
}
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
// Scale
|
||||
target.localScale = finalScale;
|
||||
target.localPosition = finalPosition;
|
||||
target.localRotation = finalRotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, int cellsPerFrame)
|
||||
{
|
||||
InitializeNoise(grid);
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
yield return GenerateRecursiveStepByStep(grid, 5, 5, interval);
|
||||
yield return GenerateRecursiveStepByStep(grid, 5, 5, cellsPerFrame);
|
||||
}
|
||||
|
||||
private void InitializeNoise(MazeGrid grid)
|
||||
@@ -127,7 +127,7 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator GenerateRecursiveStepByStep(MazeGrid grid, int x, int z, float interval)
|
||||
private IEnumerator GenerateRecursiveStepByStep(MazeGrid grid, int x, int z, int cellsPerFrame)
|
||||
{
|
||||
if (!grid.IsInBounds(x, z)) yield break;
|
||||
if (GetNoiseAt(x, z, grid.Width) < CorridorThreshold) yield break;
|
||||
@@ -136,7 +136,12 @@ namespace Hallucinate.GameSetup.Maze
|
||||
if (grid.CountSquareNeighbours(x, z, MazeCellType.Corridor) >= DeadEndNeighbourThreshold) yield break;
|
||||
|
||||
grid.SetCell(x, z, MazeCellType.Processing);
|
||||
if (interval > 0) yield return new WaitForSeconds(interval);
|
||||
MazeManager.cellsProcessedThisFrame++;
|
||||
if (MazeManager.cellsProcessedThisFrame >= cellsPerFrame)
|
||||
{
|
||||
MazeManager.cellsProcessedThisFrame = 0;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
grid.SetCell(x, z, MazeCellType.Corridor);
|
||||
|
||||
@@ -145,7 +150,7 @@ namespace Hallucinate.GameSetup.Maze
|
||||
|
||||
foreach (var dir in shuffledDirs)
|
||||
{
|
||||
yield return GenerateRecursiveStepByStep(grid, x + dir.x, z + dir.z, interval);
|
||||
yield return GenerateRecursiveStepByStep(grid, x + dir.x, z + dir.z, cellsPerFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, int cellsPerFrame)
|
||||
{
|
||||
int x = InitialX;
|
||||
int z = InitialZ;
|
||||
grid.SetCell(x, z, MazeCellType.Corridor);
|
||||
yield return new WaitForSeconds(interval);
|
||||
yield return null;
|
||||
|
||||
List<MapLocation> walls = GetNeighbouringWalls(grid, x, z);
|
||||
foreach(var w in walls) grid.SetCell(w.x, w.z, MazeCellType.Processing);
|
||||
@@ -59,7 +59,12 @@ namespace Hallucinate.GameSetup.Maze
|
||||
if (grid.CountSquareNeighbours(w.x, w.z, MazeCellType.Corridor) == TargetCorridorNeighbours)
|
||||
{
|
||||
grid.SetCell(w.x, w.z, MazeCellType.Corridor);
|
||||
if (interval > 0) yield return new WaitForSeconds(interval);
|
||||
MazeManager.cellsProcessedThisFrame++;
|
||||
if (MazeManager.cellsProcessedThisFrame >= cellsPerFrame)
|
||||
{
|
||||
MazeManager.cellsProcessedThisFrame = 0;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
foreach (var nw in GetNeighbouringWalls(grid, w.x, w.z))
|
||||
{
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace Hallucinate.GameSetup.Maze
|
||||
GenerateRecursive(grid, StartX, StartZ);
|
||||
}
|
||||
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, int cellsPerFrame)
|
||||
{
|
||||
yield return GenerateRecursiveStepByStep(grid, StartX, StartZ, interval);
|
||||
yield return GenerateRecursiveStepByStep(grid, StartX, StartZ, cellsPerFrame);
|
||||
}
|
||||
|
||||
private void GenerateRecursive(MazeGrid grid, int x, int z)
|
||||
@@ -43,12 +43,17 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator GenerateRecursiveStepByStep(MazeGrid grid, int x, int z, float interval)
|
||||
private IEnumerator GenerateRecursiveStepByStep(MazeGrid grid, int x, int z, int cellsPerFrame)
|
||||
{
|
||||
if (grid.CountSquareNeighbours(x, z, MazeCellType.Corridor) >= DeadEndNeighbourThreshold) yield break;
|
||||
|
||||
grid.SetCell(x, z, MazeCellType.Processing);
|
||||
if (interval > 0) yield return new WaitForSeconds(interval);
|
||||
MazeManager.cellsProcessedThisFrame++;
|
||||
if (MazeManager.cellsProcessedThisFrame >= cellsPerFrame)
|
||||
{
|
||||
MazeManager.cellsProcessedThisFrame = 0;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
grid.SetCell(x, z, MazeCellType.Corridor);
|
||||
|
||||
@@ -61,7 +66,7 @@ namespace Hallucinate.GameSetup.Maze
|
||||
int nz = z + dir.z;
|
||||
if (grid.IsInBounds(nx, nz))
|
||||
{
|
||||
yield return GenerateRecursiveStepByStep(grid, nx, nz, interval);
|
||||
yield return GenerateRecursiveStepByStep(grid, nx, nz, cellsPerFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,17 +32,17 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
|
||||
public IEnumerator GenerateStepByStep(MazeGrid grid, int cellsPerFrame)
|
||||
{
|
||||
int x = Random.Range(MinBoundary, grid.Width - 1);
|
||||
int z = Random.Range(MinBoundary, grid.Depth - 1);
|
||||
grid.SetCell(x, z, MazeCellType.Corridor);
|
||||
yield return new WaitForSeconds(interval);
|
||||
yield return null;
|
||||
|
||||
int safety = 0;
|
||||
while (GetAvailableCells(grid) > 1 && safety < MaxIterationSafety)
|
||||
{
|
||||
yield return RandomWalk(grid, interval);
|
||||
yield return RandomWalk(grid, cellsPerFrame);
|
||||
safety++;
|
||||
}
|
||||
}
|
||||
@@ -123,7 +123,7 @@ namespace Hallucinate.GameSetup.Maze
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator RandomWalk(MazeGrid grid, float interval)
|
||||
private IEnumerator RandomWalk(MazeGrid grid, int cellsPerFrame)
|
||||
{
|
||||
if (_notUsed.Count == 0) yield break;
|
||||
|
||||
@@ -139,7 +139,12 @@ namespace Hallucinate.GameSetup.Maze
|
||||
while (cx > 0 && cx < grid.Width - 1 && cz > 0 && cz < grid.Depth - 1 && loop < MaxWalkSteps && !validPath)
|
||||
{
|
||||
grid.SetCell(cx, cz, MazeCellType.Processing); // State 0
|
||||
if (interval > 0) yield return new WaitForSeconds(interval);
|
||||
MazeManager.cellsProcessedThisFrame++;
|
||||
if (MazeManager.cellsProcessedThisFrame >= cellsPerFrame)
|
||||
{
|
||||
MazeManager.cellsProcessedThisFrame = 0;
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (CountFinalizedNeighbours(grid, cx, cz) > 1) break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user