diff --git a/.idea/.idea.BABA_YAGA/.idea/workspace.xml b/.idea/.idea.BABA_YAGA/.idea/workspace.xml index 565929da..cbe2246a 100644 --- a/.idea/.idea.BABA_YAGA/.idea/workspace.xml +++ b/.idea/.idea.BABA_YAGA/.idea/workspace.xml @@ -12,7 +12,9 @@ - + + + - - + {} + { + "isMigrated": true +} @@ -146,6 +148,8 @@ + + diff --git a/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkConfig.cs b/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkConfig.cs index d6993ee2..d73c8718 100644 --- a/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkConfig.cs +++ b/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkConfig.cs @@ -18,6 +18,12 @@ namespace Baba_yaga.GameSetup.MazeRework /// /// Configuration asset containing parameters for the reworked maze generation. /// + public enum FloorSizeMode + { + Manual, + Random + } + [CreateAssetMenu(fileName = "MazeReworkConfig", menuName = "BABA_YAGA/MazeRework/Config")] public class MazeReworkConfig : ScriptableObject { @@ -36,6 +42,22 @@ namespace Baba_yaga.GameSetup.MazeRework [MinValue(5)] public int depth = 21; + [FoldoutGroup("Grid Dimensions")] + [Tooltip("If true, allows you to vary the floor size across multiple floors.")] + public bool varyFloorSize = false; + + [FoldoutGroup("Grid Dimensions")] + [ShowIf("varyFloorSize")] + [Tooltip("Random will pick random sizes up to the max width/depth. Manual uses the list below.")] + [EnumToggleButtons] + public FloorSizeMode floorSizeMode = FloorSizeMode.Random; + + [FoldoutGroup("Grid Dimensions")] + [ShowIf("@varyFloorSize && floorSizeMode == FloorSizeMode.Manual")] + [ListDrawerSettings(ShowIndexLabels = true)] + [Tooltip("List of manual sizes for each floor (Index 0 = Floor 0, etc). Must be odd numbers >= 5.")] + public System.Collections.Generic.List manualFloorSizes = new System.Collections.Generic.List(); + [FoldoutGroup("Seeding")] [Tooltip("If true, a random seed will be generated at runtime.")] public bool useRandomSeed = true; diff --git a/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkGenerator.cs b/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkGenerator.cs index 1e2aa15a..5f5f6f8e 100644 --- a/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkGenerator.cs +++ b/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkGenerator.cs @@ -49,10 +49,21 @@ namespace Baba_yaga.GameSetup.MazeRework } private readonly MazeReworkConfig _config; + private readonly int _width; + private readonly int _depth; public MazeReworkGenerator(MazeReworkConfig config) { _config = config; + _width = config != null ? config.width : 21; + _depth = config != null ? config.depth : 21; + } + + public MazeReworkGenerator(MazeReworkConfig config, int width, int depth) + { + _config = config; + _width = width; + _depth = depth; } /// @@ -69,12 +80,12 @@ namespace Baba_yaga.GameSetup.MazeRework /// Generates a 2D layout of the maze of size config.width by config.depth using a specific seed. /// Generates the maze grid. /// - public MazeReworkCellType[,] Generate(int seed, Vector2Int? forcedStart = null, Vector2Int? forcedDirection = null) + public MazeReworkCellType[,] Generate(int seed, Vector2Int? forcedStart = null, Vector2Int? forcedDirection = null, Vector2Int? endBounds = null) { if (_config == null) return null; - int width = _config.width; - int depth = _config.depth; + int width = _width; + int depth = _depth; var grid = new MazeReworkCellType[width, depth]; // 1. Initialize all cells as Wall @@ -129,7 +140,7 @@ namespace Baba_yaga.GameSetup.MazeRework CarveLoops(grid, rng, width, depth); // 8. Place Start & End points - PlaceStartAndEnd(grid, rooms, width, depth, rng, forcedStart, forcedDirection, null); + PlaceStartAndEnd(grid, rooms, width, depth, rng, forcedStart, forcedDirection, null, endBounds); return grid; } @@ -149,12 +160,12 @@ namespace Baba_yaga.GameSetup.MazeRework return GenerateAnimated(seed); } - public (MazeReworkCellType[,] grid, List history) GenerateAnimated(int seed, Vector2Int? forcedStart = null, Vector2Int? forcedDirection = null) + public (MazeReworkCellType[,] grid, List history) GenerateAnimated(int seed, Vector2Int? forcedStart = null, Vector2Int? forcedDirection = null, Vector2Int? endBounds = null) { if (_config == null) return (null, null); - int width = _config.width; - int depth = _config.depth; + int width = _width; + int depth = _depth; var grid = new MazeReworkCellType[width, depth]; var history = new List(width * depth * 2); @@ -219,7 +230,7 @@ namespace Baba_yaga.GameSetup.MazeRework // 8. Place Start & End points (no highlighting needed for this step in animation) currentPhase = MazeAnimationPhase.StartEnd; - PlaceStartAndEnd(grid, rooms, width, depth, rng, forcedStart, forcedDirection, recordNoHighlight); + PlaceStartAndEnd(grid, rooms, width, depth, rng, forcedStart, forcedDirection, history, endBounds); return (grid, history); } @@ -469,9 +480,12 @@ namespace Baba_yaga.GameSetup.MazeRework } } - private void PlaceStartAndEnd(MazeReworkCellType[,] grid, List rooms, int width, int depth, System.Random rng, Vector2Int? forcedStart, Vector2Int? forcedDirection, - Action onCellChanged = null) + private void PlaceStartAndEnd(MazeReworkCellType[,] grid, List rooms, int width, int depth, System.Random rng, Vector2Int? forcedStart, Vector2Int? forcedDirection, List history = null, Vector2Int? endBounds = null) { + Action onCellChanged = history != null + ? (x, z, type) => history.Add(new MazeCellChange(x, z, type, MazeCellHighlight.None, MazeAnimationPhase.StartEnd)) + : (Action)null; + Vector2Int startPt = new Vector2Int(-1, -1); if (forcedStart.HasValue) @@ -480,7 +494,7 @@ namespace Baba_yaga.GameSetup.MazeRework } else { - startPt = FindDeadEnd(grid, width, depth, rng, new Vector2Int(-1, -1)); + startPt = FindDeadEnd(grid, width, depth, rng, new Vector2Int(-1, -1), endBounds); if (startPt.x == -1) { // Fallback to config start if no corridors exist @@ -493,17 +507,22 @@ namespace Baba_yaga.GameSetup.MazeRework grid[startPt.x, startPt.y] = MazeReworkCellType.Start; onCellChanged?.Invoke(startPt.x, startPt.y, MazeReworkCellType.Start); - Vector2Int endPt = FindDeadEnd(grid, width, depth, rng, startPt); + Vector2Int endPt = FindDeadEnd(grid, width, depth, rng, startPt, endBounds); if (endPt.x == -1) { // Fallback: just pick the furthest corridor cell from startPt - endPt = FindFurthestCorridor(grid, width, depth, startPt); + endPt = FindFurthestCorridor(grid, width, depth, startPt, endBounds); if (endPt.x == -1) { // Extreme fallback int ex = width - 2, ez = depth - 2; + if (endBounds.HasValue) + { + ex = endBounds.Value.x - 2; + ez = endBounds.Value.y - 2; + } EnsureValidOddCoordinates(width, depth, ref ex, ref ez); endPt = new Vector2Int(ex, ez); } @@ -518,14 +537,17 @@ namespace Baba_yaga.GameSetup.MazeRework EnforceSingleConnection(grid, endPt.x, endPt.y, null); } - private Vector2Int FindDeadEnd(MazeReworkCellType[,] grid, int width, int depth, System.Random rng, Vector2Int exclude) + private Vector2Int FindDeadEnd(MazeReworkCellType[,] grid, int width, int depth, System.Random rng, Vector2Int exclude, Vector2Int? bounds = null) { List deadEnds = new List(); List corridors = new List(); + + int maxW = bounds.HasValue ? Mathf.Min(width, bounds.Value.x) : width; + int maxD = bounds.HasValue ? Mathf.Min(depth, bounds.Value.y) : depth; - for (int z = 1; z < depth - 1; z++) + for (int z = 1; z < maxD - 1; z++) { - for (int x = 1; x < width - 1; x++) + for (int x = 1; x < maxW - 1; x++) { if (grid[x, z] == MazeReworkCellType.Corridor) { @@ -551,14 +573,17 @@ namespace Baba_yaga.GameSetup.MazeRework return new Vector2Int(-1, -1); } - private Vector2Int FindFurthestCorridor(MazeReworkCellType[,] grid, int width, int depth, Vector2Int from) + private Vector2Int FindFurthestCorridor(MazeReworkCellType[,] grid, int width, int depth, Vector2Int from, Vector2Int? bounds = null) { Vector2Int best = new Vector2Int(-1, -1); float maxDist = -1f; + + int maxW = bounds.HasValue ? Mathf.Min(width, bounds.Value.x) : width; + int maxD = bounds.HasValue ? Mathf.Min(depth, bounds.Value.y) : depth; - for (int z = 1; z < depth - 1; z++) + for (int z = 1; z < maxD - 1; z++) { - for (int x = 1; x < width - 1; x++) + for (int x = 1; x < maxW - 1; x++) { if (grid[x, z] == MazeReworkCellType.Corridor) { diff --git a/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkManager.cs b/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkManager.cs index 83a702e5..5a47d60c 100644 --- a/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkManager.cs +++ b/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkManager.cs @@ -122,34 +122,83 @@ namespace Baba_yaga.GameSetup.MazeRework ClearMaze(); if (animator != null) animator.StopAnimation(); - var generator = new MazeReworkGenerator(config); - if (animateGeneration && animator != null) { if (Application.isPlaying) { - StartCoroutine(GenerateAndSpawnAnimatedRoutine(generator)); + StartCoroutine(GenerateAndSpawnAnimatedRoutine()); } else { Debug.LogWarning("[MazeReworkManager] Animation is only supported in Play Mode. Falling back to instantaneous generation."); - GenerateInstantaneous(generator); + GenerateInstantaneous(); } } else { - GenerateInstantaneous(generator); + GenerateInstantaneous(); } } - private IEnumerator GenerateAndSpawnAnimatedRoutine(MazeReworkGenerator generator) + private void GetDynamicFloorSize(int floorIndex, int seed, out int width, out int depth) { + width = config.width; + depth = config.depth; + + if (config.varyFloorSize) + { + if (config.floorSizeMode == FloorSizeMode.Manual) + { + if (config.manualFloorSizes != null && floorIndex < config.manualFloorSizes.Count) + { + width = config.manualFloorSizes[floorIndex].x; + depth = config.manualFloorSizes[floorIndex].y; + } + } + else // Random + { + System.Random rng = new System.Random(seed); + // Generate random odd sizes between 5 and config.width/depth + int wRange = (config.width - 5) / 2; + int dRange = (config.depth - 5) / 2; + width = 5 + rng.Next(0, wRange + 1) * 2; + depth = 5 + rng.Next(0, dRange + 1) * 2; + } + + // Ensure they are odd and at least 5 + if (width % 2 == 0) width--; + if (depth % 2 == 0) depth--; + if (width < 5) width = 5; + if (depth < 5) depth = 5; + } + } + + private IEnumerator GenerateAndSpawnAnimatedRoutine() + { + int[] floorSeeds = new int[floorCount]; + Vector2Int[] floorSizes = new Vector2Int[floorCount]; + for (int i = 0; i < floorCount; i++) + { + floorSeeds[i] = config.useRandomSeed ? System.Guid.NewGuid().GetHashCode() : config.seed + i * 1000; + GetDynamicFloorSize(i, floorSeeds[i], out int fW, out int fD); + floorSizes[i] = new Vector2Int(fW, fD); + } + Vector2Int? nextStartPos = null; Vector2Int? nextStartDir = null; for (int i = 0; i < floorCount; i++) { - int seed = config.useRandomSeed ? System.Guid.NewGuid().GetHashCode() : config.seed + i * 1000; - var (grid, history) = generator.GenerateAnimated(seed, nextStartPos, nextStartDir); + int fWidth = floorSizes[i].x; + int fDepth = floorSizes[i].y; + var generator = new MazeReworkGenerator(config, fWidth, fDepth); + + Vector2Int? endBounds = null; + if (i < floorCount - 1) + { + endBounds = floorSizes[i + 1]; + } + + var (grid, history) = generator.GenerateAnimated(floorSeeds[i], nextStartPos, nextStartDir, endBounds); if (i > 0 && nextStartPos.HasValue) { @@ -159,9 +208,9 @@ namespace Baba_yaga.GameSetup.MazeRework if (i < floorCount - 1) { Vector2Int endPos = new Vector2Int(-1, -1); - for (int z = 0; z < config.depth; z++) + for (int z = 0; z < fDepth; z++) { - for (int x = 0; x < config.width; x++) + for (int x = 0; x < fWidth; x++) { if (grid[x, z] == MazeReworkCellType.End) { endPos = new Vector2Int(x, z); break; } } @@ -192,14 +241,32 @@ namespace Baba_yaga.GameSetup.MazeRework Debug.Log($"[MazeReworkManager] All floors animated! Beginning world position: {BeginningWorldPosition}"); } - private void GenerateInstantaneous(MazeReworkGenerator generator) + private void GenerateInstantaneous() { + int[] floorSeeds = new int[floorCount]; + Vector2Int[] floorSizes = new Vector2Int[floorCount]; + for (int i = 0; i < floorCount; i++) + { + floorSeeds[i] = config.useRandomSeed ? System.Guid.NewGuid().GetHashCode() : config.seed + i * 1000; + GetDynamicFloorSize(i, floorSeeds[i], out int fW, out int fD); + floorSizes[i] = new Vector2Int(fW, fD); + } + Vector2Int? nextStartPos = null; Vector2Int? nextStartDir = null; for (int i = 0; i < floorCount; i++) { - int seed = config.useRandomSeed ? System.Guid.NewGuid().GetHashCode() : config.seed + i * 1000; - var grid = generator.Generate(seed, nextStartPos, nextStartDir); + int fWidth = floorSizes[i].x; + int fDepth = floorSizes[i].y; + var generator = new MazeReworkGenerator(config, fWidth, fDepth); + + Vector2Int? endBounds = null; + if (i < floorCount - 1) + { + endBounds = floorSizes[i + 1]; + } + + var grid = generator.Generate(floorSeeds[i], nextStartPos, nextStartDir, endBounds); // If this is not the first floor, replace the Start with StairsDown to connect to the floor below if (i > 0 && nextStartPos.HasValue) @@ -207,13 +274,12 @@ namespace Baba_yaga.GameSetup.MazeRework grid[nextStartPos.Value.x, nextStartPos.Value.y] = MazeReworkCellType.StairsDown; } - // If there is a floor above this one, convert the End cell to a StairsUp if (i < floorCount - 1) { Vector2Int endPos = new Vector2Int(-1, -1); - for (int z = 0; z < config.depth; z++) + for (int z = 0; z < fDepth; z++) { - for (int x = 0; x < config.width; x++) + for (int x = 0; x < fWidth; x++) { if (grid[x, z] == MazeReworkCellType.End) {