using System.Collections.Generic; using UnityEngine; namespace Hallucinate.GameSetup.Maze { /// /// Represents a 2D coordinate on the maze grid. /// Used as a lightweight value type to avoid GC allocations. /// public readonly struct MapLocation { public readonly int x; public readonly int z; public MapLocation(int _x, int _z) { x = _x; z = _z; } } /// /// The base class for maze generation. /// Handles map initialization, basic neighbor counting logic, and debug rendering. /// public class Maze : MonoBehaviour { #region Constants public const byte Corridor = 0; public const byte Wall = 1; public const byte Path = 2; #endregion #region Fields [Header("Maze Settings")] [SerializeField] protected int width = 30; // x length [SerializeField] protected int depth = 30; // z length [SerializeField] protected int scale = 6; [Header("Hierarchy Settings")] [UnityEngine.Serialization.FormerlySerializedAs("_mapParentObjet")] [SerializeField] protected Transform mapParentObject; /// /// List of cardinal directions used for neighbor checking and navigation. /// protected List directions = new List() { new MapLocation(1, 0), new MapLocation(0, 1), new MapLocation(-1, 0), new MapLocation(0, -1) }; /// /// 2D array representing the maze grid. /// 0 = Corridor, 1 = Wall, 2 = Special Path. /// public byte[,] map; #endregion protected virtual void Start() { InitialiseMap(); Generate(); DrawMap(); } /// /// Initializes the map array and fills it with walls. /// protected void InitialiseMap() { map = new byte[width, depth]; for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { map[x, z] = Wall; } } } /// /// Virtual method to be overridden by specific maze generation algorithms. /// Default implementation creates a random noise-based map. /// public virtual void Generate() { for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { if (Random.Range(0, 100) < 50) { map[x, z] = Corridor; } } } } /// /// Renders the maze in the scene using Unity primitives. /// protected void DrawMap() { for (int z = 0; z < depth; z++) { for (int x = 0; x < width; x++) { if (map[x, z] == Wall) { Vector3 pos = new Vector3(x * scale, 0, z * scale); GameObject wall = GameObject.CreatePrimitive(PrimitiveType.Cube); wall.transform.localScale = new Vector3(scale, scale, scale); wall.transform.position = pos; if (mapParentObject != null) { wall.transform.SetParent(mapParentObject); } } } } } #region Helpers /// /// Counts the number of horizontal and vertical neighbors that are corridors. /// /// X coordinate. /// Z coordinate. /// The count of square neighbors. public int CountSquareNeighbours(int x, int z) { int count = 0; if (x <= 0 || x >= width - 1 || z <= 0 || z >= depth - 1) return 5; if (map[x - 1, z] == Corridor) count++; if (map[x + 1, z] == Corridor) count++; if (map[x, z + 1] == Corridor) count++; if (map[x, z - 1] == Corridor) count++; return count; } /// /// Counts the number of diagonal neighbors that are corridors. /// /// X coordinate. /// Z coordinate. /// The count of diagonal neighbors. public int CountDiagonalNeighbours(int x, int z) { int count = 0; if (x <= 0 || x >= width - 1 || z <= 0 || z >= depth - 1) return 5; if (map[x - 1, z - 1] == Corridor) count++; if (map[x + 1, z + 1] == Corridor) count++; if (map[x - 1, z + 1] == Corridor) count++; if (map[x + 1, z - 1] == Corridor) count++; return count; } /// /// Counts all neighbors (square + diagonal) that are corridors. /// /// X coordinate. /// Z coordinate. /// Total neighbor count. public int CountAllNeighbours(int x, int z) { return CountSquareNeighbours(x, z) + CountDiagonalNeighbours(x, z); } #endregion } }