Files
BABA_YAGA/Assets/Scripts/GameSetup/Maze/MazeManager.cs

242 lines
7.6 KiB
C#
Raw Normal View History

2026-04-21 23:28:49 +07:00
using System.Collections;
using System.Collections.Generic;
2026-06-09 02:05:00 +07:00
using Sirenix.OdinInspector;
2026-04-21 23:28:49 +07:00
using UnityEngine;
namespace Hallucinate.GameSetup.Maze
{
/// <summary>
/// Central controller for the Maze system.
/// Manages algorithm selection, debug speed, and regeneration.
/// </summary>
public class MazeManager : MonoBehaviour
{
public enum AlgorithmType { Recursive, Wilsons, Prims, Crawler }
2026-06-09 02:05:00 +07:00
[BoxGroup("Generation")]
[InfoBox("Set the array size to control how many maze floors are generated. Runtime grid data is rebuilt when Regenerate runs.")]
[ValidateInput(nameof(HasAtLeastOneFloor), "Maze Manager needs at least one floor.")]
2026-05-03 06:49:11 +07:00
public MazeGrid[] mazes;
2026-06-09 02:05:00 +07:00
[BoxGroup("Generation")]
[MinValue(0.001f)]
2026-05-03 06:49:11 +07:00
public float floorHeight = 3.5f;
2026-06-09 02:05:00 +07:00
[BoxGroup("Generation")]
[MinValue(0)]
2026-05-03 06:49:11 +07:00
public int connectionsPerFloor = 2;
2026-06-09 02:05:00 +07:00
[BoxGroup("Generation")]
2026-04-21 23:28:49 +07:00
[SerializeField] private AlgorithmType selectedAlgorithm;
2026-06-09 02:05:00 +07:00
[BoxGroup("Generation/Grid Size")]
[PropertyRange(5, 200)]
2026-04-21 23:28:49 +07:00
[SerializeField] private int width = 30;
2026-06-09 02:05:00 +07:00
[BoxGroup("Generation/Grid Size")]
[PropertyRange(5, 200)]
2026-04-21 23:28:49 +07:00
[SerializeField] private int depth = 30;
2026-06-09 02:05:00 +07:00
[BoxGroup("Debug")]
2026-04-21 23:28:49 +07:00
[SerializeField] private bool debugMode = true;
2026-06-09 02:05:00 +07:00
[BoxGroup("Debug")]
[ShowIf(nameof(debugMode))]
[PropertyRange(0.001f, 0.5f)]
2026-04-21 23:28:49 +07:00
[SerializeField] private float visualizationInterval = 0.05f;
2026-06-09 02:05:00 +07:00
[BoxGroup("References")]
[Required]
2026-04-21 23:28:49 +07:00
[SerializeField] private MazeRenderer mazeRenderer;
2026-06-09 02:05:00 +07:00
[BoxGroup("References")]
[Required]
2026-04-21 23:28:49 +07:00
[SerializeField] private Transform mazeContainer;
2026-06-09 02:05:00 +07:00
[FoldoutGroup("Manhole Prefabs")]
2026-05-03 06:49:11 +07:00
public GameObject straightManHoleLadder;
2026-06-09 02:05:00 +07:00
[FoldoutGroup("Manhole Prefabs")]
2026-05-03 06:49:11 +07:00
public GameObject straightManHoleUp;
2026-06-09 02:05:00 +07:00
[FoldoutGroup("Manhole Prefabs")]
2026-05-03 06:49:11 +07:00
public GameObject deadendManHoleLadder;
2026-06-09 02:05:00 +07:00
[FoldoutGroup("Manhole Prefabs")]
2026-05-03 06:49:11 +07:00
public GameObject deadendManHoleUp;
2026-06-09 02:05:00 +07:00
[ShowInInspector]
[ReadOnly]
[BoxGroup("Runtime")]
private int FloorCount => mazes?.Length ?? 0;
[ShowInInspector]
[ReadOnly]
[BoxGroup("Runtime")]
private string CurrentGrid => _grid == null ? "None" : $"{_grid.Width}x{_grid.Depth}, Level {_grid.Level}";
2026-05-03 06:49:11 +07:00
2026-04-21 23:28:49 +07:00
private MazeGrid _grid;
private Coroutine _generationCoroutine;
private void Start()
{
Regenerate();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
Regenerate();
}
}
[ContextMenu("Regenerate")]
2026-06-09 02:05:00 +07:00
[Button("Regenerate Maze", ButtonSizes.Large)]
2026-04-21 23:28:49 +07:00
public void Regenerate()
{
2026-06-09 02:05:00 +07:00
if (mazeRenderer == null)
{
Debug.LogError("MazeManager needs a MazeRenderer reference before regenerating.", this);
return;
}
if (mazeContainer == null)
{
Debug.LogError("MazeManager needs a maze container reference before regenerating.", this);
return;
}
if (mazes == null || mazes.Length == 0)
{
mazes = new MazeGrid[1];
}
2026-05-06 01:47:40 +07:00
if (_generationCoroutine != null)
{
StopCoroutine(_generationCoroutine);
}
mazeRenderer.Clear();
// Step 1: Initialize all maze floors
2026-05-03 06:49:11 +07:00
for (int i = 0; i < mazes.Length; i++)
{
2026-05-06 01:47:40 +07:00
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]);
2026-05-03 06:49:11 +07:00
}
2026-05-06 01:47:40 +07:00
// Step 2: Create connections between adjacent floors
2026-05-03 06:49:11 +07:00
for (int i = 0; i < mazes.Length - 1; i++)
{
MazeGrid currentFloor = mazes[i];
MazeGrid nextFloor = mazes[i + 1];
List<Vector2Int> possibleConnections = new List<Vector2Int>();
for (int z = 0; z < depth; z++)
{
for (int x = 0; x < width; x++)
{
2026-05-06 01:47:40 +07:00
// Check if both floors have a corridor at this position
bool isCurrentFloorPath = currentFloor.GetCell(x, z) == MazeCellType.Corridor;
bool isNextFloorPath = nextFloor.GetCell(x, z) == MazeCellType.Corridor;
2026-05-03 06:49:11 +07:00
if (isCurrentFloorPath && isNextFloorPath)
{
possibleConnections.Add(new Vector2Int(x, z));
}
}
}
ShuffleList(possibleConnections);
2026-05-06 01:47:40 +07:00
int connectionsMade = 0;
2026-05-03 06:49:11 +07:00
foreach (Vector2Int pos in possibleConnections)
{
2026-05-06 01:47:40 +07:00
if (connectionsMade >= connectionsPerFloor) break;
2026-05-03 06:49:11 +07:00
int x = pos.x;
int z = pos.y;
2026-05-06 01:47:40 +07:00
// Set stair cells
2026-05-08 09:50:34 +07:00
currentFloor.SetCell(x, z, MazeCellType.StairsUp);
nextFloor.SetCell(x, z, MazeCellType.StairsDown);
2026-05-03 06:49:11 +07:00
connectionsMade++;
}
}
2026-05-06 01:47:40 +07:00
// Step 3: Render all floors
if (mazes.Length > 0)
2026-04-21 23:28:49 +07:00
{
2026-05-06 01:47:40 +07:00
for (int i = 0; i < mazes.Length; i++)
{
mazeRenderer.Initialize(mazes[i], mazeContainer, i == 0);
}
_grid = mazes[0];
2026-04-21 23:28:49 +07:00
}
else
{
2026-05-08 13:01:04 +07:00
// _grid = new MazeGrid(width, depth);
// mazeRenderer.Initialize(_grid, mazeContainer);
2026-05-06 01:47:40 +07:00
IMazeAlgorithm algorithm = GetAlgorithm(selectedAlgorithm);
if (debugMode)
{
_generationCoroutine = StartCoroutine(algorithm.GenerateStepByStep(_grid, visualizationInterval));
}
else
{
algorithm.Generate(_grid);
}
2026-05-08 13:01:04 +07:00
_grid = new MazeGrid(width, depth);
mazeRenderer.Initialize(_grid, mazeContainer);
2026-04-21 23:28:49 +07:00
}
}
2026-05-03 06:49:11 +07:00
private void ShuffleList<T>(List<T> list)
{
for (int i = 0; i < list.Count; i++)
{
T temp = list[i];
int randomIndex = Random.Range(i, list.Count);
list[i] = list[randomIndex];
list[randomIndex] = temp;
}
}
2026-04-21 23:28:49 +07:00
private IMazeAlgorithm GetAlgorithm(AlgorithmType type)
{
return type switch
{
AlgorithmType.Recursive => new RecursiveAlgorithm(),
AlgorithmType.Wilsons => new WilsonsAlgorithm(),
AlgorithmType.Prims => new PrimsAlgorithm(),
AlgorithmType.Crawler => new CrawlerAlgorithm(),
_ => new RecursiveAlgorithm()
};
}
2026-06-09 02:05:00 +07:00
[Button("Find Scene References")]
private void FindSceneReferences()
{
if (mazeRenderer == null)
{
mazeRenderer = GetComponentInChildren<MazeRenderer>();
}
if (mazeContainer == null)
{
mazeContainer = transform;
}
}
private bool HasAtLeastOneFloor(MazeGrid[] floors)
{
return floors != null && floors.Length > 0;
}
2026-04-21 23:28:49 +07:00
}
}