diff --git a/.idea/.idea.HALLUCINATE/.idea/workspace.xml b/.idea/.idea.HALLUCINATE/.idea/workspace.xml
index 0400f241..8814200c 100644
--- a/.idea/.idea.HALLUCINATE/.idea/workspace.xml
+++ b/.idea/.idea.HALLUCINATE/.idea/workspace.xml
@@ -5,14 +5,19 @@
-
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -137,7 +142,7 @@
-
+
diff --git a/Assets/Prefabs/Maze.meta b/Assets/Prefabs/Maze.meta
new file mode 100644
index 00000000..09d6c092
--- /dev/null
+++ b/Assets/Prefabs/Maze.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0988e2233101908428f5f5334d85a1f7
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Prefabs/Maze/CorridorPrefab_.prefab b/Assets/Prefabs/Maze/CorridorPrefab_.prefab
new file mode 100644
index 00000000..92203547
--- /dev/null
+++ b/Assets/Prefabs/Maze/CorridorPrefab_.prefab
@@ -0,0 +1,114 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &7041334646084879511
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 8919327890245084656}
+ - component: {fileID: 8819792327415332675}
+ - component: {fileID: 4127344303633613435}
+ - component: {fileID: 67198264001523534}
+ m_Layer: 0
+ m_Name: CorridorPrefab_
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!4 &8919327890245084656
+Transform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7041334646084879511}
+ serializedVersion: 2
+ m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+ m_LocalPosition: {x: 70.81325, y: 0.00003, z: 73.80717}
+ m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
+ m_Children: []
+ m_Father: {fileID: 0}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &8819792327415332675
+MeshFilter:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7041334646084879511}
+ m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
+--- !u!23 &4127344303633613435
+MeshRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7041334646084879511}
+ m_Enabled: 1
+ m_CastShadows: 1
+ m_ReceiveShadows: 1
+ m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
+ m_MotionVectors: 1
+ m_LightProbeUsage: 1
+ m_ReflectionProbeUsage: 1
+ m_RayTracingMode: 2
+ m_RayTraceProcedural: 0
+ m_RayTracingAccelStructBuildFlagsOverride: 0
+ m_RayTracingAccelStructBuildFlags: 1
+ m_SmallMeshCulling: 1
+ m_ForceMeshLod: -1
+ m_MeshLodSelectionBias: 0
+ m_RenderingLayerMask: 1
+ m_RendererPriority: 0
+ m_Materials:
+ - {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2}
+ m_StaticBatchInfo:
+ firstSubMesh: 0
+ subMeshCount: 0
+ m_StaticBatchRoot: {fileID: 0}
+ m_ProbeAnchor: {fileID: 0}
+ m_LightProbeVolumeOverride: {fileID: 0}
+ m_ScaleInLightmap: 1
+ m_ReceiveGI: 1
+ m_PreserveUVs: 0
+ m_IgnoreNormalsForChartDetection: 0
+ m_ImportantGI: 0
+ m_StitchLightmapSeams: 1
+ m_SelectedEditorRenderState: 3
+ m_MinimumChartSize: 4
+ m_AutoUVMaxDistance: 0.5
+ m_AutoUVMaxAngle: 89
+ m_LightmapParameters: {fileID: 0}
+ m_GlobalIlluminationMeshLod: 0
+ m_SortingLayerID: 0
+ m_SortingLayer: 0
+ m_SortingOrder: 0
+ m_MaskInteraction: 0
+ m_AdditionalVertexStreams: {fileID: 0}
+--- !u!65 &67198264001523534
+BoxCollider:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 7041334646084879511}
+ m_Material: {fileID: 0}
+ m_IncludeLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ m_ExcludeLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ m_LayerOverridePriority: 0
+ m_IsTrigger: 0
+ m_ProvidesContacts: 0
+ m_Enabled: 1
+ serializedVersion: 3
+ m_Size: {x: 1, y: 1, z: 1}
+ m_Center: {x: 0, y: 0, z: 0}
diff --git a/Assets/Prefabs/Maze/CorridorPrefab_.prefab.meta b/Assets/Prefabs/Maze/CorridorPrefab_.prefab.meta
new file mode 100644
index 00000000..693a4212
--- /dev/null
+++ b/Assets/Prefabs/Maze/CorridorPrefab_.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4872dd25f62fbfa48b25a2b636aa6865
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Prefabs/Maze/ProcessingPrefab.prefab b/Assets/Prefabs/Maze/ProcessingPrefab.prefab
new file mode 100644
index 00000000..f06a7c7d
--- /dev/null
+++ b/Assets/Prefabs/Maze/ProcessingPrefab.prefab
@@ -0,0 +1,63 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1001 &8367681202885872253
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 4127344303633613435, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: 'm_Materials.Array.data[0]'
+ value:
+ objectReference: {fileID: 2100000, guid: c2e40fa84d53ccd428f640eac126b1fb, type: 2}
+ - target: {fileID: 7041334646084879511, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_Name
+ value: ProcessingPrefab
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
diff --git a/Assets/Prefabs/Maze/ProcessingPrefab.prefab.meta b/Assets/Prefabs/Maze/ProcessingPrefab.prefab.meta
new file mode 100644
index 00000000..cc0f2529
--- /dev/null
+++ b/Assets/Prefabs/Maze/ProcessingPrefab.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 1e8b6ed6b01405e4b9e358abc8f7a058
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Prefabs/Maze/WallPrefab.prefab b/Assets/Prefabs/Maze/WallPrefab.prefab
new file mode 100644
index 00000000..165b8b8e
--- /dev/null
+++ b/Assets/Prefabs/Maze/WallPrefab.prefab
@@ -0,0 +1,63 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1001 &7905038714086068258
+PrefabInstance:
+ m_ObjectHideFlags: 0
+ serializedVersion: 2
+ m_Modification:
+ serializedVersion: 3
+ m_TransformParent: {fileID: 0}
+ m_Modifications:
+ - target: {fileID: 4127344303633613435, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: 'm_Materials.Array.data[0]'
+ value:
+ objectReference: {fileID: 2100000, guid: b34b07a45ba63ce47896c9e674f3a7a7, type: 2}
+ - target: {fileID: 7041334646084879511, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_Name
+ value: WallPrefab
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalPosition.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalPosition.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalPosition.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalRotation.w
+ value: 1
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalRotation.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalRotation.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalRotation.z
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.x
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.y
+ value: 0
+ objectReference: {fileID: 0}
+ - target: {fileID: 8919327890245084656, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
+ propertyPath: m_LocalEulerAnglesHint.z
+ value: 0
+ objectReference: {fileID: 0}
+ m_RemovedComponents: []
+ m_RemovedGameObjects: []
+ m_AddedGameObjects: []
+ m_AddedComponents: []
+ m_SourcePrefab: {fileID: 100100000, guid: 4872dd25f62fbfa48b25a2b636aa6865, type: 3}
diff --git a/Assets/Prefabs/Maze/WallPrefab.prefab.meta b/Assets/Prefabs/Maze/WallPrefab.prefab.meta
new file mode 100644
index 00000000..4c364025
--- /dev/null
+++ b/Assets/Prefabs/Maze/WallPrefab.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: c49f25c5b1c3e4b43a2bc56717387124
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/GameSetup/Maze/Crawler.cs b/Assets/Scripts/GameSetup/Maze/Crawler.cs
deleted file mode 100644
index 62641f8d..00000000
--- a/Assets/Scripts/GameSetup/Maze/Crawler.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using UnityEngine;
-
-namespace Hallucinate.GameSetup.Maze
-{
- ///
- /// A maze generation algorithm that "crawls" through the grid in a semi-random walk.
- /// It creates long, winding corridors by moving vertically or horizontally.
- ///
- public class Crawler : Maze
- {
- ///
- /// Orchestrates the crawling generation.
- /// (Currently empty as per original procedural logic).
- ///
- public override void Generate()
- {
- // Implementation can be expanded as needed.
- }
-
- ///
- /// Performs a vertical crawl starting from a random X position at the bottom.
- ///
- protected void CrawlV()
- {
- bool done = false;
- int x = Random.Range(1, width - 1);
- int z = 1;
-
- while (!done)
- {
- map[x, z] = Corridor;
- if (Random.Range(0, 100) < 50)
- {
- x += Random.Range(-1, 2);
- }
- else
- {
- z += Random.Range(0, 2);
- }
-
- done |= (x < 1 || x >= width - 1 || z < 1 || z >= depth - 1);
- }
- }
-
- ///
- /// Performs a horizontal crawl starting from a random Z position at the left.
- ///
- protected void CrawlH()
- {
- bool done = false;
- int x = 1;
- int z = Random.Range(1, depth - 1);
-
- while (!done)
- {
- map[x, z] = Corridor;
- if (Random.Range(0, 100) < 50)
- {
- x += Random.Range(0, 2);
- }
- else
- {
- z += Random.Range(-1, 2);
- }
-
- done |= (x < 1 || x >= width - 1 || z < 1 || z >= depth - 1);
- }
- }
- }
-}
diff --git a/Assets/Scripts/GameSetup/Maze/Crawler.cs.meta b/Assets/Scripts/GameSetup/Maze/Crawler.cs.meta
deleted file mode 100644
index 76144d4b..00000000
--- a/Assets/Scripts/GameSetup/Maze/Crawler.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 7b5776943e6d841879f829c725bf4e6b
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Scripts/GameSetup/Maze/CrawlerAlgorithm.cs b/Assets/Scripts/GameSetup/Maze/CrawlerAlgorithm.cs
new file mode 100644
index 00000000..8fe9ba08
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/CrawlerAlgorithm.cs
@@ -0,0 +1,75 @@
+using System.Collections;
+using UnityEngine;
+
+namespace Hallucinate.GameSetup.Maze
+{
+ public class CrawlerAlgorithm : IMazeAlgorithm
+ {
+ private const int CrawlChance = 50;
+ private const int MinBoundary = 1;
+
+ public void Generate(MazeGrid grid)
+ {
+ CrawlV(grid, 0);
+ CrawlH(grid, 0);
+ }
+
+ public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
+ {
+ yield return CrawlV(grid, interval);
+ yield return CrawlH(grid, interval);
+ }
+
+ private IEnumerator CrawlV(MazeGrid grid, float interval)
+ {
+ bool done = false;
+ int x = Random.Range(MinBoundary, grid.Width - MinBoundary);
+ int z = MinBoundary;
+
+ while (!done)
+ {
+ grid.SetCell(x, z, MazeCellType.Processing);
+ if (interval > 0) yield return new WaitForSeconds(interval);
+
+ grid.SetCell(x, z, MazeCellType.Corridor);
+
+ if (Random.Range(0, 100) < CrawlChance)
+ {
+ x += Random.Range(-1, 2);
+ }
+ else
+ {
+ z += Random.Range(0, 2);
+ }
+
+ done |= (x < MinBoundary || x >= grid.Width - MinBoundary || z < MinBoundary || z >= grid.Depth - MinBoundary);
+ }
+ }
+
+ private IEnumerator CrawlH(MazeGrid grid, float interval)
+ {
+ bool done = false;
+ int x = MinBoundary;
+ int z = Random.Range(MinBoundary, grid.Depth - MinBoundary);
+
+ while (!done)
+ {
+ grid.SetCell(x, z, MazeCellType.Processing);
+ if (interval > 0) yield return new WaitForSeconds(interval);
+
+ grid.SetCell(x, z, MazeCellType.Corridor);
+
+ if (Random.Range(0, 100) < CrawlChance)
+ {
+ x += Random.Range(0, 2);
+ }
+ else
+ {
+ z += Random.Range(-1, 2);
+ }
+
+ done |= (x < MinBoundary || x >= grid.Width - MinBoundary || z < MinBoundary || z >= grid.Depth - MinBoundary);
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/CrawlerAlgorithm.cs.meta b/Assets/Scripts/GameSetup/Maze/CrawlerAlgorithm.cs.meta
new file mode 100644
index 00000000..0fd697d8
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/CrawlerAlgorithm.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: bd419f9be92beac48b6f551063165e1f
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/Extensions.cs b/Assets/Scripts/GameSetup/Maze/Extensions.cs
index bdb306b1..e3c09f4c 100644
--- a/Assets/Scripts/GameSetup/Maze/Extensions.cs
+++ b/Assets/Scripts/GameSetup/Maze/Extensions.cs
@@ -2,19 +2,13 @@ using System.Collections.Generic;
namespace Hallucinate.GameSetup.Maze.Extensions
{
- ///
- /// Provides utility extension methods for maze generation algorithms.
- ///
- public static class Extensions
+ public static class ListExtensions
{
private static System.Random _rng = new System.Random();
///
- /// Shuffles the elements of an using the Fisher-Yates algorithm.
- /// This is used to randomize directions for maze generation.
+ /// Shuffles a list using the Fisher-Yates algorithm.
///
- /// The type of elements in the list.
- /// The list to shuffle.
public static void Shuffle(this IList list)
{
int n = list.Count;
diff --git a/Assets/Scripts/GameSetup/Maze/Extensions.cs.meta b/Assets/Scripts/GameSetup/Maze/Extensions.cs.meta
index 14d44730..cbbc6316 100644
--- a/Assets/Scripts/GameSetup/Maze/Extensions.cs.meta
+++ b/Assets/Scripts/GameSetup/Maze/Extensions.cs.meta
@@ -1,11 +1,2 @@
fileFormatVersion: 2
-guid: 7d9791b1b03c14f16a245b2d4577c5f9
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
+guid: 7d9791b1b03c14f16a245b2d4577c5f9
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/Interfaces.meta b/Assets/Scripts/GameSetup/Maze/Interfaces.meta
new file mode 100644
index 00000000..6d0164e9
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/Interfaces.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 6e1bb9cd9af7ffe40ad1a740c3c30dd6
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Scripts/GameSetup/Maze/Interfaces/IMazeAlgorithm.cs b/Assets/Scripts/GameSetup/Maze/Interfaces/IMazeAlgorithm.cs
new file mode 100644
index 00000000..8687135c
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/Interfaces/IMazeAlgorithm.cs
@@ -0,0 +1,19 @@
+namespace Hallucinate.GameSetup.Maze
+{
+ ///
+ /// Interface for all maze generation algorithms.
+ /// Supports both immediate and step-by-step (animated) generation.
+ ///
+ public interface IMazeAlgorithm
+ {
+ ///
+ /// Generates the maze immediately in one frame.
+ ///
+ void Generate(MazeGrid grid);
+
+ ///
+ /// Generates the maze step-by-step for visualization.
+ ///
+ System.Collections.IEnumerator GenerateStepByStep(MazeGrid grid, float interval);
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/Interfaces/IMazeAlgorithm.cs.meta b/Assets/Scripts/GameSetup/Maze/Interfaces/IMazeAlgorithm.cs.meta
new file mode 100644
index 00000000..ac465940
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/Interfaces/IMazeAlgorithm.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 46b6a7796ba3c494581e4dcb884da064
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/MapLocation.cs b/Assets/Scripts/GameSetup/Maze/MapLocation.cs
new file mode 100644
index 00000000..b2eeefdb
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MapLocation.cs
@@ -0,0 +1,32 @@
+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;
+ }
+
+ // Static predefined directions to eliminate magic numbers in algorithms
+ public static MapLocation Right => new MapLocation(1, 0);
+ public static MapLocation Left => new MapLocation(-1, 0);
+ public static MapLocation Up => new MapLocation(0, 1);
+ public static MapLocation Down => new MapLocation(0, -1);
+
+ ///
+ /// Returns a list of all 4 cardinal directions.
+ ///
+ public static System.Collections.Generic.List Directions => new System.Collections.Generic.List
+ {
+ Right, Up, Left, Down
+ };
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/MapLocation.cs.meta b/Assets/Scripts/GameSetup/Maze/MapLocation.cs.meta
new file mode 100644
index 00000000..8fab4430
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MapLocation.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 987a7c46c96326a44b3a5f179fe61161
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/Maze.cs b/Assets/Scripts/GameSetup/Maze/Maze.cs
deleted file mode 100644
index f2f5f8ad..00000000
--- a/Assets/Scripts/GameSetup/Maze/Maze.cs
+++ /dev/null
@@ -1,178 +0,0 @@
-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
- }
-}
diff --git a/Assets/Scripts/GameSetup/Maze/Maze.cs.meta b/Assets/Scripts/GameSetup/Maze/Maze.cs.meta
deleted file mode 100644
index 1fefe103..00000000
--- a/Assets/Scripts/GameSetup/Maze/Maze.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 1039d646c358a4bd5ac697b0446a2f7e
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Scripts/GameSetup/Maze/MazeCellType.cs b/Assets/Scripts/GameSetup/Maze/MazeCellType.cs
new file mode 100644
index 00000000..f3ff132a
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeCellType.cs
@@ -0,0 +1,16 @@
+namespace Hallucinate.GameSetup.Maze
+{
+ ///
+ /// Defines the state of each cell in the maze.
+ /// Used to replace magic numbers and drive visual changes.
+ ///
+ public enum MazeCellType
+ {
+ Wall, // Solid block
+ Corridor, // Finalized path
+ Processing, // Currently being evaluated by algorithm (Debug)
+ Path, // Temporary path (e.g., Wilson's crawler)
+ Start, // Entry point
+ End // Exit point
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/MazeCellType.cs.meta b/Assets/Scripts/GameSetup/Maze/MazeCellType.cs.meta
new file mode 100644
index 00000000..87631d50
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeCellType.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f54ef08fa4922eb4a968d46c7aa71faf
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/MazeGrid.cs b/Assets/Scripts/GameSetup/Maze/MazeGrid.cs
new file mode 100644
index 00000000..cb386259
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeGrid.cs
@@ -0,0 +1,71 @@
+using System;
+using UnityEngine;
+
+namespace Hallucinate.GameSetup.Maze
+{
+ ///
+ /// Holds the logical state of the maze grid.
+ /// Notifies listeners whenever a cell changes to trigger visual updates.
+ ///
+ public class MazeGrid
+ {
+ public int Width { get; }
+ public int Depth { get; }
+
+ private readonly MazeCellType[,] _cells;
+
+ ///
+ /// Event fired when a cell's type is changed.
+ /// Useful for the Renderer to trigger animations/FX.
+ ///
+ public event Action OnCellChanged;
+
+ public MazeGrid(int width, int depth)
+ {
+ Width = width;
+ Depth = depth;
+ _cells = new MazeCellType[width, depth];
+
+ // Initialize all as walls
+ for (int z = 0; z < depth; z++)
+ for (int x = 0; x < width; x++)
+ _cells[x, z] = MazeCellType.Wall;
+ }
+
+ public void SetCell(int x, int z, MazeCellType type)
+ {
+ if (IsInBounds(x, z))
+ {
+ if (_cells[x, z] != type)
+ {
+ _cells[x, z] = type;
+ OnCellChanged?.Invoke(x, z, type);
+ }
+ }
+ }
+
+ public MazeCellType GetCell(int x, int z)
+ {
+ if (IsInBounds(x, z))
+ return _cells[x, z];
+ return MazeCellType.Wall; // Treat out of bounds as walls
+ }
+
+ public bool IsInBounds(int x, int z)
+ {
+ return x >= 0 && x < Width && z >= 0 && z < Depth;
+ }
+
+ public int CountSquareNeighbours(int x, int z, MazeCellType targetType)
+ {
+ int count = 0;
+ if (x <= 0 || x >= Width - 1 || z <= 0 || z >= Depth - 1) return 5;
+
+ if (GetCell(x - 1, z) == targetType) count++;
+ if (GetCell(x + 1, z) == targetType) count++;
+ if (GetCell(x, z + 1) == targetType) count++;
+ if (GetCell(x, z - 1) == targetType) count++;
+ return count;
+ }
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/MazeGrid.cs.meta b/Assets/Scripts/GameSetup/Maze/MazeGrid.cs.meta
new file mode 100644
index 00000000..f918ca79
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeGrid.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: a1a7a252ff0b1014a9690f08897e2e59
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/MazeManager.cs b/Assets/Scripts/GameSetup/Maze/MazeManager.cs
new file mode 100644
index 00000000..6a8c130d
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeManager.cs
@@ -0,0 +1,81 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Hallucinate.GameSetup.Maze
+{
+ ///
+ /// Central controller for the Maze system.
+ /// Manages algorithm selection, debug speed, and regeneration.
+ ///
+ public class MazeManager : MonoBehaviour
+ {
+ public enum AlgorithmType { Recursive, Wilsons, Prims, Crawler }
+
+ [Header("System Settings")]
+ [SerializeField] private AlgorithmType selectedAlgorithm;
+ [SerializeField] private int width = 30;
+ [SerializeField] private int depth = 30;
+
+ [Header("Debug Settings")]
+ [SerializeField] private bool debugMode = true;
+ [Range(0.001f, 0.5f)]
+ [SerializeField] private float visualizationInterval = 0.05f;
+
+ [Header("References")]
+ [SerializeField] private MazeRenderer mazeRenderer;
+ [SerializeField] private Transform mazeContainer;
+
+ private MazeGrid _grid;
+ private Coroutine _generationCoroutine;
+
+ private void Start()
+ {
+ Regenerate();
+ }
+
+ private void Update()
+ {
+ if (Input.GetKeyDown(KeyCode.R))
+ {
+ Regenerate();
+ }
+ }
+
+ [ContextMenu("Regenerate")]
+ public void Regenerate()
+ {
+ if (_generationCoroutine != null)
+ {
+ StopCoroutine(_generationCoroutine);
+ }
+
+ mazeRenderer.Clear();
+ _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);
+ }
+ }
+
+ 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()
+ };
+ }
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/MazeManager.cs.meta b/Assets/Scripts/GameSetup/Maze/MazeManager.cs.meta
new file mode 100644
index 00000000..b11f7944
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeManager.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 3607adabe0c29c34591af73b414eb17a
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/MazeRenderer.cs b/Assets/Scripts/GameSetup/Maze/MazeRenderer.cs
new file mode 100644
index 00000000..5f77e8eb
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeRenderer.cs
@@ -0,0 +1,102 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Hallucinate.GameSetup.Maze
+{
+ ///
+ /// Responsible for the visual representation of the maze.
+ /// Handles spawning, pooling, and animations.
+ ///
+ public class MazeRenderer : MonoBehaviour
+ {
+ [SerializeField] private MazeVisualProfile visualProfile;
+
+ private readonly Dictionary _spawnedCells = new Dictionary();
+ 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()
+ {
+ // IMPORTANT: Stop all running animations to prevent accessing destroyed objects
+ 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);
+
+ // Remove old visual if exists
+ if (_spawnedCells.TryGetValue(pos, out GameObject oldObj))
+ {
+ Destroy(oldObj);
+ _spawnedCells.Remove(pos);
+ }
+
+ GameObject prefab = visualProfile.GetPrefab(type);
+ if (prefab == null) return;
+
+ Vector3 worldPos = new Vector3(x * visualProfile.scale, 0, z * visualProfile.scale);
+ GameObject newObj = Instantiate(prefab, worldPos, Quaternion.identity, _container);
+ newObj.transform.localScale = Vector3.one * visualProfile.scale;
+ _spawnedCells[pos] = newObj;
+
+ if (animate)
+ {
+ StartCoroutine(AnimateCell(newObj.transform));
+ }
+ }
+
+ private IEnumerator AnimateCell(Transform target)
+ {
+ if (target == null) yield break;
+
+ float duration = visualProfile.animationDuration;
+ float elapsed = 0;
+ Vector3 finalScale = target.localScale;
+ target.localScale = Vector3.zero;
+
+ while (elapsed < duration)
+ {
+ // Extra safety check in case the object is destroyed mid-animation
+ if (target == null) yield break;
+
+ elapsed += Time.deltaTime;
+ float t = elapsed / duration;
+ float s = Mathf.Sin(t * Mathf.PI * 0.5f);
+ target.localScale = finalScale * s;
+ yield return null;
+ }
+
+ if (target != null)
+ {
+ target.localScale = finalScale;
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/MazeRenderer.cs.meta b/Assets/Scripts/GameSetup/Maze/MazeRenderer.cs.meta
new file mode 100644
index 00000000..ab28d9fa
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeRenderer.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f30df611110713742ab984f5bead5d88
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/MazeVisualProfile.cs b/Assets/Scripts/GameSetup/Maze/MazeVisualProfile.cs
new file mode 100644
index 00000000..362aa0ca
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeVisualProfile.cs
@@ -0,0 +1,34 @@
+using UnityEngine;
+
+namespace Hallucinate.GameSetup.Maze
+{
+ [CreateAssetMenu(fileName = "MazeVisualProfile", menuName = "Hallucinate/Maze/Visual Profile")]
+ public class MazeVisualProfile : ScriptableObject
+ {
+ [Header("Prefabs")]
+ public GameObject wallPrefab;
+ public GameObject corridorPrefab;
+ public GameObject processingPrefab;
+ public GameObject pathPrefab;
+ public GameObject startPrefab;
+ public GameObject endPrefab;
+
+ [Header("Visualization Settings")]
+ public float scale = 1f;
+ public float animationDuration = 0.25f;
+
+ public GameObject GetPrefab(MazeCellType type)
+ {
+ return type switch
+ {
+ MazeCellType.Wall => wallPrefab,
+ MazeCellType.Corridor => corridorPrefab,
+ MazeCellType.Processing => processingPrefab,
+ MazeCellType.Path => pathPrefab,
+ MazeCellType.Start => startPrefab,
+ MazeCellType.End => endPrefab,
+ _ => null
+ };
+ }
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/MazeVisualProfile.cs.meta b/Assets/Scripts/GameSetup/Maze/MazeVisualProfile.cs.meta
new file mode 100644
index 00000000..d0f6dbb7
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/MazeVisualProfile.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: d3ff96571406a624381b7b0e596a4d1b
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/Prims.cs b/Assets/Scripts/GameSetup/Maze/Prims.cs
deleted file mode 100644
index 40d7fe29..00000000
--- a/Assets/Scripts/GameSetup/Maze/Prims.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-using System.Collections.Generic;
-using UnityEngine;
-
-namespace Hallucinate.GameSetup.Maze
-{
- ///
- /// Implements a simplified version of Prim's algorithm for maze generation.
- /// It picks walls at random and converts them into corridors if they only have one corridor neighbor.
- ///
- public class Prims : Maze
- {
- ///
- /// Generates the maze using Prim's algorithm logic.
- ///
- public override void Generate()
- {
- int x = 2;
- int z = 2;
-
- map[x, z] = Corridor;
-
- List walls = new List
- {
- new MapLocation(x + 1, z),
- new MapLocation(x - 1, z),
- new MapLocation(x, z + 1),
- new MapLocation(x, z - 1)
- };
-
- int countloops = 0;
- while (walls.Count > 0 && countloops < 5000)
- {
- int rwall = Random.Range(0, walls.Count);
- x = walls[rwall].x;
- z = walls[rwall].z;
- walls.RemoveAt(rwall);
-
- if (CountSquareNeighbours(x, z) == 1)
- {
- map[x, z] = Corridor;
- walls.Add(new MapLocation(x + 1, z));
- walls.Add(new MapLocation(x - 1, z));
- walls.Add(new MapLocation(x, z + 1));
- walls.Add(new MapLocation(x, z - 1));
- }
-
- countloops++;
- }
- }
- }
-}
diff --git a/Assets/Scripts/GameSetup/Maze/Prims.cs.meta b/Assets/Scripts/GameSetup/Maze/Prims.cs.meta
deleted file mode 100644
index 14552764..00000000
--- a/Assets/Scripts/GameSetup/Maze/Prims.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: f12a5f6746a454e08a295f64a34f5dcf
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Scripts/GameSetup/Maze/PrimsAlgorithm.cs b/Assets/Scripts/GameSetup/Maze/PrimsAlgorithm.cs
new file mode 100644
index 00000000..78ecafa3
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/PrimsAlgorithm.cs
@@ -0,0 +1,95 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Hallucinate.GameSetup.Maze
+{
+ public class PrimsAlgorithm : IMazeAlgorithm
+ {
+ private const int InitialX = 2;
+ private const int InitialZ = 2;
+ private const int MaxIterations = 10000;
+ private const int TargetCorridorNeighbours = 1;
+
+ public void Generate(MazeGrid grid)
+ {
+ int x = InitialX;
+ int z = InitialZ;
+ grid.SetCell(x, z, MazeCellType.Corridor);
+
+ List walls = GetNeighbouringWalls(grid, x, z);
+
+ int iterations = 0;
+ while (walls.Count > 0 && iterations < MaxIterations)
+ {
+ int rIndex = Random.Range(0, walls.Count);
+ MapLocation w = walls[rIndex];
+ walls.RemoveAt(rIndex);
+
+ if (grid.CountSquareNeighbours(w.x, w.z, MazeCellType.Corridor) == TargetCorridorNeighbours)
+ {
+ grid.SetCell(w.x, w.z, MazeCellType.Corridor);
+ walls.AddRange(GetNeighbouringWalls(grid, w.x, w.z));
+ }
+ iterations++;
+ }
+ }
+
+ public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
+ {
+ int x = InitialX;
+ int z = InitialZ;
+ grid.SetCell(x, z, MazeCellType.Corridor);
+ yield return new WaitForSeconds(interval);
+
+ List walls = GetNeighbouringWalls(grid, x, z);
+
+ foreach(var w in walls) grid.SetCell(w.x, w.z, MazeCellType.Processing);
+
+ int iterations = 0;
+ while (walls.Count > 0 && iterations < MaxIterations)
+ {
+ int rIndex = Random.Range(0, walls.Count);
+ MapLocation w = walls[rIndex];
+ walls.RemoveAt(rIndex);
+
+ 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);
+
+ var newWalls = GetNeighbouringWalls(grid, w.x, w.z);
+ foreach(var nw in newWalls)
+ {
+ if (grid.GetCell(nw.x, nw.z) == MazeCellType.Wall)
+ {
+ grid.SetCell(nw.x, nw.z, MazeCellType.Processing);
+ walls.Add(nw);
+ }
+ }
+ }
+ else
+ {
+ if(grid.GetCell(w.x, w.z) == MazeCellType.Processing)
+ grid.SetCell(w.x, w.z, MazeCellType.Wall);
+ }
+ iterations++;
+ }
+ }
+
+ private List GetNeighbouringWalls(MazeGrid grid, int x, int z)
+ {
+ List neighbours = new List();
+ foreach (var dir in MapLocation.Directions)
+ {
+ int nx = x + dir.x;
+ int nz = z + dir.z;
+ if (grid.IsInBounds(nx, nz) && grid.GetCell(nx, nz) == MazeCellType.Wall)
+ {
+ neighbours.Add(new MapLocation(nx, nz));
+ }
+ }
+ return neighbours;
+ }
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/PrimsAlgorithm.cs.meta b/Assets/Scripts/GameSetup/Maze/PrimsAlgorithm.cs.meta
new file mode 100644
index 00000000..842f4524
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/PrimsAlgorithm.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: edcdd3c0aa9656a4797b83cc675aa629
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/Recursive.cs b/Assets/Scripts/GameSetup/Maze/Recursive.cs
deleted file mode 100644
index 7c9d0084..00000000
--- a/Assets/Scripts/GameSetup/Maze/Recursive.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using Hallucinate.GameSetup.Maze.Extensions;
-using UnityEngine;
-
-namespace Hallucinate.GameSetup.Maze
-{
- ///
- /// A recursive backtracker algorithm for maze generation.
- /// It explores the grid randomly and backtracks when it reaches a dead end.
- ///
- public class Recursive : Maze
- {
- ///
- /// Entry point for the recursive generation.
- /// Starts from a fixed position (5, 5).
- ///
- public override void Generate()
- {
- Generate(5, 5);
- }
-
- ///
- /// Internal recursive method that carves corridors by exploring neighbors in a random order.
- ///
- /// The current X coordinate.
- /// The current Z coordinate.
- protected void Generate(int x, int z)
- {
- if (CountSquareNeighbours(x, z) >= 2) return;
-
- map[x, z] = Corridor;
-
- directions.Shuffle();
-
- Generate(x + directions[0].x, z + directions[0].z);
- Generate(x + directions[1].x, z + directions[1].z);
- Generate(x + directions[2].x, z + directions[2].z);
- Generate(x + directions[3].x, z + directions[3].z);
- }
- }
-}
diff --git a/Assets/Scripts/GameSetup/Maze/Recursive.cs.meta b/Assets/Scripts/GameSetup/Maze/Recursive.cs.meta
deleted file mode 100644
index 4bb0e7cf..00000000
--- a/Assets/Scripts/GameSetup/Maze/Recursive.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 33bbdb95ccc4b4577a62495732a02d3e
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Scripts/GameSetup/Maze/RecursiveAlgorithm.cs b/Assets/Scripts/GameSetup/Maze/RecursiveAlgorithm.cs
new file mode 100644
index 00000000..f050852a
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/RecursiveAlgorithm.cs
@@ -0,0 +1,69 @@
+using System.Collections;
+using System.Collections.Generic;
+using Hallucinate.GameSetup.Maze.Extensions;
+using UnityEngine;
+
+namespace Hallucinate.GameSetup.Maze
+{
+ public class RecursiveAlgorithm : IMazeAlgorithm
+ {
+ private const int StartX = 5;
+ private const int StartZ = 5;
+ private const int DeadEndNeighbourThreshold = 2;
+
+ private readonly List _directions = MapLocation.Directions;
+
+ public void Generate(MazeGrid grid)
+ {
+ GenerateRecursive(grid, StartX, StartZ);
+ }
+
+ public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
+ {
+ yield return GenerateRecursiveStepByStep(grid, StartX, StartZ, interval);
+ }
+
+ private void GenerateRecursive(MazeGrid grid, int x, int z)
+ {
+ if (grid.CountSquareNeighbours(x, z, MazeCellType.Corridor) >= DeadEndNeighbourThreshold) return;
+
+ grid.SetCell(x, z, MazeCellType.Corridor);
+
+ List shuffledDirs = new List(_directions);
+ shuffledDirs.Shuffle();
+
+ foreach (var dir in shuffledDirs)
+ {
+ int nx = x + dir.x;
+ int nz = z + dir.z;
+ if (grid.IsInBounds(nx, nz))
+ {
+ GenerateRecursive(grid, nx, nz);
+ }
+ }
+ }
+
+ private IEnumerator GenerateRecursiveStepByStep(MazeGrid grid, int x, int z, float interval)
+ {
+ if (grid.CountSquareNeighbours(x, z, MazeCellType.Corridor) >= DeadEndNeighbourThreshold) yield break;
+
+ grid.SetCell(x, z, MazeCellType.Processing);
+ if (interval > 0) yield return new WaitForSeconds(interval);
+
+ grid.SetCell(x, z, MazeCellType.Corridor);
+
+ List shuffledDirs = new List(_directions);
+ shuffledDirs.Shuffle();
+
+ foreach (var dir in shuffledDirs)
+ {
+ int nx = x + dir.x;
+ int nz = z + dir.z;
+ if (grid.IsInBounds(nx, nz))
+ {
+ yield return GenerateRecursiveStepByStep(grid, nx, nz, interval);
+ }
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/RecursiveAlgorithm.cs.meta b/Assets/Scripts/GameSetup/Maze/RecursiveAlgorithm.cs.meta
new file mode 100644
index 00000000..2b10f9d6
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/RecursiveAlgorithm.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 2460c0e9379da9741b3d3387aa6c7a8e
\ No newline at end of file
diff --git a/Assets/Scripts/GameSetup/Maze/Wilsons.cs b/Assets/Scripts/GameSetup/Maze/Wilsons.cs
deleted file mode 100644
index b7f2ae8f..00000000
--- a/Assets/Scripts/GameSetup/Maze/Wilsons.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using System.Collections.Generic;
-using UnityEngine;
-
-namespace Hallucinate.GameSetup.Maze
-{
- ///
- /// Implements Wilson's algorithm for generating a Uniform Spanning Tree of the grid.
- /// It uses loop-erased random walks to connect unvisited cells to the existing maze.
- ///
- public class Wilsons : Maze
- {
- private List _notUsed = new List();
-
- ///
- /// Generates the maze using Wilson's algorithm logic.
- ///
- public override void Generate()
- {
- // Create a starting cell
- int x = Random.Range(2, width - 1);
- int z = Random.Range(2, depth - 1);
- map[x, z] = Path;
-
- while (GetAvailableCells() > 1)
- {
- RandomWalk();
- }
- }
-
- ///
- /// Counts how many neighbors are already part of the finalized "Path".
- ///
- private int CountSquareMazeNeighbours(int x, int z)
- {
- int count = 0;
- for (int d = 0; d < directions.Count; d++)
- {
- int nx = x + directions[d].x;
- int nz = z + directions[d].z;
-
- if (map[nx, nz] == Path)
- {
- count++;
- }
- }
-
- return count;
- }
-
- ///
- /// Scans the grid for cells that are not yet connected to the maze.
- ///
- /// The number of available (unused) cells.
- private int GetAvailableCells()
- {
- _notUsed.Clear();
- for (int z = 1; z < depth - 1; z++)
- {
- for (int x = 1; x < width - 1; x++)
- {
- if (CountSquareMazeNeighbours(x, z) == 0)
- {
- _notUsed.Add(new MapLocation(x, z));
- }
- }
- }
-
- return _notUsed.Count;
- }
-
- ///
- /// Performs a random walk from an unused cell until it hits the existing maze.
- ///
- private void RandomWalk()
- {
- List inWalk = new List();
- int rStartIndex = Random.Range(0, _notUsed.Count);
-
- int cx = _notUsed[rStartIndex].x;
- int cz = _notUsed[rStartIndex].z;
-
- inWalk.Add(new MapLocation(cx, cz));
-
- int loopCount = 0;
- bool validPath = false;
-
- while (cx > 0 && cx < width - 1 && cz > 0 && cz < depth - 1 && loopCount < 5000 && !validPath)
- {
- map[cx, cz] = Corridor;
-
- if (CountSquareMazeNeighbours(cx, cz) > 1)
- {
- break;
- }
-
- int rd = Random.Range(0, directions.Count);
- int nx = cx + directions[rd].x;
- int nz = cz + directions[rd].z;
-
- if (CountSquareNeighbours(nx, nz) < 2)
- {
- cx = nx;
- cz = nz;
- inWalk.Add(new MapLocation(cx, cz));
- }
-
- validPath = CountSquareMazeNeighbours(cx, cz) == 1;
- loopCount++;
- }
-
- if (validPath)
- {
- map[cx, cz] = Corridor;
- Debug.Log("Path Found");
-
- foreach (MapLocation m in inWalk)
- {
- map[m.x, m.z] = Path;
- }
- inWalk.Clear();
- }
- else
- {
- foreach (MapLocation m in inWalk)
- {
- map[m.x, m.z] = Wall;
- }
- inWalk.Clear();
- }
- }
- }
-}
diff --git a/Assets/Scripts/GameSetup/Maze/Wilsons.cs.meta b/Assets/Scripts/GameSetup/Maze/Wilsons.cs.meta
deleted file mode 100644
index 54e9fd95..00000000
--- a/Assets/Scripts/GameSetup/Maze/Wilsons.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 502e6aa24e7de43dfb6d20ecd0745176
-MonoImporter:
- externalObjects: {}
- serializedVersion: 2
- defaultReferences: []
- executionOrder: 0
- icon: {instanceID: 0}
- userData:
- assetBundleName:
- assetBundleVariant:
diff --git a/Assets/Scripts/GameSetup/Maze/WilsonsAlgorithm.cs b/Assets/Scripts/GameSetup/Maze/WilsonsAlgorithm.cs
new file mode 100644
index 00000000..c7eeb746
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/WilsonsAlgorithm.cs
@@ -0,0 +1,118 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Hallucinate.GameSetup.Maze
+{
+ public class WilsonsAlgorithm : IMazeAlgorithm
+ {
+ private const int MinBoundary = 2;
+ private const int MaxIterationSafety = 5000;
+ private const int TargetPathNeighbours = 1;
+
+ private readonly List _directions = new List()
+ {
+ new MapLocation(1, 0), new MapLocation(0, 1), new MapLocation(-1, 0), new MapLocation(0, -1)
+ };
+
+ public void Generate(MazeGrid grid)
+ {
+ int x = Random.Range(MinBoundary, grid.Width - MinBoundary);
+ int z = Random.Range(MinBoundary, grid.Depth - MinBoundary);
+ grid.SetCell(x, z, MazeCellType.Corridor);
+
+ while (GetAvailableCells(grid).Count > 1)
+ {
+ PerformRandomWalk(grid, null, 0);
+ }
+ }
+
+ public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
+ {
+ int x = Random.Range(MinBoundary, grid.Width - MinBoundary);
+ int z = Random.Range(MinBoundary, grid.Depth - MinBoundary);
+ grid.SetCell(x, z, MazeCellType.Corridor);
+ yield return new WaitForSeconds(interval);
+
+ while (true)
+ {
+ var available = GetAvailableCells(grid);
+ if (available.Count <= 1) break;
+
+ yield return PerformRandomWalk(grid, available, interval);
+ }
+ }
+
+ private List GetAvailableCells(MazeGrid grid)
+ {
+ List available = new List();
+ for (int z = 1; z < grid.Depth - 1; z++)
+ {
+ for (int x = 1; x < grid.Width - 1; x++)
+ {
+ if (CountPathNeighbours(grid, x, z) == 0)
+ available.Add(new MapLocation(x, z));
+ }
+ }
+ return available;
+ }
+
+ private int CountPathNeighbours(MazeGrid grid, int x, int z)
+ {
+ int count = 0;
+ foreach (var d in _directions)
+ {
+ if (grid.GetCell(x + d.x, z + d.z) == MazeCellType.Corridor) count++;
+ }
+ return count;
+ }
+
+ private IEnumerator PerformRandomWalk(MazeGrid grid, List available, float interval)
+ {
+ List inWalk = new List();
+ int rStart = Random.Range(0, available.Count);
+ int cx = available[rStart].x;
+ int cz = available[rStart].z;
+
+ inWalk.Add(new MapLocation(cx, cz));
+ bool pathFound = false;
+
+ int safety = 0;
+ while (grid.IsInBounds(cx, cz) && !pathFound && safety < MaxIterationSafety)
+ {
+ grid.SetCell(cx, cz, MazeCellType.Processing);
+ if (interval > 0) yield return new WaitForSeconds(interval);
+
+ if (CountPathNeighbours(grid, cx, cz) > 1) break;
+
+ int rd = Random.Range(0, _directions.Count);
+ int nx = cx + _directions[rd].x;
+ int nz = cz + _directions[rd].z;
+
+ if (grid.CountSquareNeighbours(nx, nz, MazeCellType.Processing) < 2)
+ {
+ cx = nx;
+ cz = nz;
+ inWalk.Add(new MapLocation(cx, cz));
+ }
+
+ pathFound = CountPathNeighbours(grid, cx, cz) == TargetPathNeighbours;
+ safety++;
+ }
+
+ if (pathFound)
+ {
+ foreach (var m in inWalk)
+ {
+ grid.SetCell(m.x, m.z, MazeCellType.Corridor);
+ if (interval > 0) yield return new WaitForSeconds(interval * 0.5f);
+ }
+ }
+ else
+ {
+ foreach (var m in inWalk)
+ grid.SetCell(m.x, m.z, MazeCellType.Wall);
+ }
+ }
+ }
+}
diff --git a/Assets/Scripts/GameSetup/Maze/WilsonsAlgorithm.cs.meta b/Assets/Scripts/GameSetup/Maze/WilsonsAlgorithm.cs.meta
new file mode 100644
index 00000000..40e0edb0
--- /dev/null
+++ b/Assets/Scripts/GameSetup/Maze/WilsonsAlgorithm.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 61156f8986612ca49a0672ad5542380f
\ No newline at end of file
diff --git a/Assets/Settings/Project Setting/DefaultMazeProfile.asset b/Assets/Settings/Project Setting/DefaultMazeProfile.asset
new file mode 100644
index 00000000..f5ff2597
--- /dev/null
+++ b/Assets/Settings/Project Setting/DefaultMazeProfile.asset
@@ -0,0 +1,22 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: d3ff96571406a624381b7b0e596a4d1b, type: 3}
+ m_Name: DefaultMazeProfile
+ m_EditorClassIdentifier: Assembly-CSharp::Hallucinate.GameSetup.Maze.MazeVisualProfile
+ wallPrefab: {fileID: 0}
+ corridorPrefab: {fileID: 0}
+ processingPrefab: {fileID: 0}
+ pathPrefab: {fileID: 0}
+ startPrefab: {fileID: 0}
+ endPrefab: {fileID: 0}
+ scale: 1
+ animationDuration: 0.25
diff --git a/Assets/Settings/Project Setting/DefaultMazeProfile.asset.meta b/Assets/Settings/Project Setting/DefaultMazeProfile.asset.meta
new file mode 100644
index 00000000..6a36cba0
--- /dev/null
+++ b/Assets/Settings/Project Setting/DefaultMazeProfile.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 15b745b0bb979b84ea937c679ee0f1ed
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant: