This commit is contained in:
2026-07-04 07:11:09 +07:00
parent 531e28409a
commit 0745556ae6
6 changed files with 385824 additions and 88 deletions

View File

@@ -12,10 +12,7 @@
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="d308d1cb-09fc-4331-ba20-00f7b43d1576" name="Changes" comment=""> <list default="true" id="d308d1cb-09fc-4331-ba20-00f7b43d1576" name="Changes" comment="">
<change beforePath="$PROJECT_DIR$/.idea/.idea.BABA_YAGA/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.BABA_YAGA/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/.idea.BABA_YAGA/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.BABA_YAGA/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/End.prefab" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Prefabs/Environment/Hall/End.prefab" afterDir="false" /> <change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkSpawner.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkSpawner.cs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Presets/MazeRework.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Presets/MazeRework.asset" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scenes/Main Scene.unity" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scenes/Main Scene.unity" afterDir="false" />
<change beforePath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkGenerator.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/Baba_yaga/GameSetup/MazeRework/MazeReworkGenerator.cs" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />

File diff suppressed because it is too large Load Diff

View File

@@ -1,22 +1,37 @@
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Sirenix.OdinInspector;
namespace Baba_yaga.GameSetup.MazeRework.Animation namespace Baba_yaga.GameSetup.MazeRework.Animation
{ {
public enum RenderSweepStyle
{
RowByRow,
CenterOut,
RandomPop
}
public class MazeAnimator : MonoBehaviour public class MazeAnimator : MonoBehaviour
{ {
[Header("Animation Settings")] [FoldoutGroup("Algorithm Animation")]
[Tooltip("How many cell changes to process in a single frame (if stepDelay is 0).")] [Tooltip("How many cell changes to process in a single frame (if stepDelay is 0).")]
[Min(1)] [MinValue(1)]
public int cellsPerFrame = 1; // Default to 1 so you can see it clearly! public int cellsPerFrame = 1; // Default to 1 so you can see it clearly!
[FoldoutGroup("Algorithm Animation")]
[Tooltip("Delay in seconds between every single cell change. Set to > 0 to actually see the checking flashes!")] [Tooltip("Delay in seconds between every single cell change. Set to > 0 to actually see the checking flashes!")]
public float stepDelay = 0.05f; public float stepDelay = 0.05f;
[FoldoutGroup("Algorithm Animation")]
[Tooltip("Extra delay (in seconds) between major generation phases (like switching from Rooms to Carving).")] [Tooltip("Extra delay (in seconds) between major generation phases (like switching from Rooms to Carving).")]
public float delayBetweenPhases = 0.5f; public float delayBetweenPhases = 0.5f;
[FoldoutGroup("3D Render Phase")]
[Tooltip("How the final 3D prefabs pop into existence.")]
[EnumToggleButtons]
public RenderSweepStyle renderSweepStyle = RenderSweepStyle.CenterOut;
private Coroutine _animationRoutine; private Coroutine _animationRoutine;
public void AnimateGeneration( public void AnimateGeneration(
@@ -33,6 +48,8 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
_animationRoutine = StartCoroutine(AnimateRoutine(history, grid, spawner, yOffset, container, onComplete)); _animationRoutine = StartCoroutine(AnimateRoutine(history, grid, spawner, yOffset, container, onComplete));
} }
[FoldoutGroup("Debug Actions")]
[Button("Stop Animation", ButtonSizes.Medium), GUIColor(1f, 0.4f, 0.4f)]
public void StopAnimation() public void StopAnimation()
{ {
if (_animationRoutine != null) if (_animationRoutine != null)
@@ -122,37 +139,60 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
// --- Phase 2: Render 3D Map --- // --- Phase 2: Render 3D Map ---
spawner.isPreviewMode = false; spawner.isPreviewMode = false;
// Sweep across the grid and spawn the heavy 3D modular pieces List<Vector2Int> renderQueue = new List<Vector2Int>();
for (int z = 0; z < depth; z++) for (int z = 0; z < depth; z++)
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
renderQueue.Add(new Vector2Int(x, z));
}
}
if (renderSweepStyle == RenderSweepStyle.CenterOut)
{
Vector2 center = new Vector2(width / 2f, depth / 2f);
renderQueue.Sort((a, b) => Vector2.Distance(center, a).CompareTo(Vector2.Distance(center, b)));
}
else if (renderSweepStyle == RenderSweepStyle.RandomPop)
{
System.Random rng = new System.Random();
for (int i = 0; i < renderQueue.Count; i++)
{
int rand = rng.Next(i, renderQueue.Count);
var temp = renderQueue[i];
renderQueue[i] = renderQueue[rand];
renderQueue[rand] = temp;
}
}
// Sweep across the grid and spawn the heavy 3D modular pieces
foreach (var pt in renderQueue)
{
int x = pt.x;
int z = pt.y;
workingGrid[x, z] = finalGrid[x, z]; workingGrid[x, z] = finalGrid[x, z];
workingHighlights[x, z] = MazeCellHighlight.None; workingHighlights[x, z] = MazeCellHighlight.None;
// Only yield when we actually spawn a piece to create a cool sweep wave!
if (finalGrid[x, z] != MazeReworkCellType.Wall) if (finalGrid[x, z] != MazeReworkCellType.Wall)
{ {
// 1. Flash an Evaluating highlight to visualize "choosing" this cell
spawner.FlashHighlight(MazeCellHighlight.EvaluatingValid, x, z, yOffset, container); spawner.FlashHighlight(MazeCellHighlight.EvaluatingValid, x, z, yOffset, container);
if (stepDelay > 0f) if (stepDelay > 0f)
{ {
yield return new WaitForSeconds(stepDelay * 0.5f); // Short pause for the check yield return new WaitForSeconds(stepDelay * 0.5f);
} }
// 2. Spawn the actual piece
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container); spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
// Wait a tiny fraction of a second to create the sweeping wave effect
if (stepDelay > 0f) if (stepDelay > 0f)
{ {
yield return new WaitForSeconds(stepDelay * 0.5f); // faster than the algorithm checks yield return new WaitForSeconds(stepDelay * 0.5f);
} }
else else
{ {
processedThisFrame++; processedThisFrame++;
if (processedThisFrame >= cellsPerFrame * 2) // Twice as fast as algorithm phase if (processedThisFrame >= cellsPerFrame * 2)
{ {
yield return null; yield return null;
processedThisFrame = 0; processedThisFrame = 0;
@@ -161,11 +201,9 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
} }
else else
{ {
// Even if it's a wall, refresh it to clear the preview walls (if any)
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container); spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
} }
} }
}
_animationRoutine = null; _animationRoutine = null;
onComplete?.Invoke(); onComplete?.Invoke();

View File

@@ -1,4 +1,5 @@
using UnityEngine; using UnityEngine;
using Sirenix.OdinInspector;
using Baba_yaga.GameSetup.MazeRework.Algorithms; using Baba_yaga.GameSetup.MazeRework.Algorithms;
namespace Baba_yaga.GameSetup.MazeRework namespace Baba_yaga.GameSetup.MazeRework
@@ -20,51 +21,63 @@ namespace Baba_yaga.GameSetup.MazeRework
[CreateAssetMenu(fileName = "MazeReworkConfig", menuName = "BABA_YAGA/MazeRework/Config")] [CreateAssetMenu(fileName = "MazeReworkConfig", menuName = "BABA_YAGA/MazeRework/Config")]
public class MazeReworkConfig : ScriptableObject public class MazeReworkConfig : ScriptableObject
{ {
[Header("Algorithm")] [FoldoutGroup("Algorithm")]
[Tooltip("Which carving algorithm to use for generating the maze corridors.")] [Tooltip("Which carving algorithm to use for generating the maze corridors.")]
[EnumToggleButtons]
public MazeAlgorithmType algorithm = MazeAlgorithmType.DFSRecursive; public MazeAlgorithmType algorithm = MazeAlgorithmType.DFSRecursive;
[Header("Grid Dimensions")] [FoldoutGroup("Grid Dimensions")]
[Tooltip("Width of the maze grid. Best if odd to align with wall-corridor-wall patterning.")] [Tooltip("Width of the maze grid. Best if odd to align with wall-corridor-wall patterning.")]
[Min(5)] [MinValue(5)]
public int width = 21; public int width = 21;
[FoldoutGroup("Grid Dimensions")]
[Tooltip("Depth of the maze grid. Best if odd to align with wall-corridor-wall patterning.")] [Tooltip("Depth of the maze grid. Best if odd to align with wall-corridor-wall patterning.")]
[Min(5)] [MinValue(5)]
public int depth = 21; public int depth = 21;
[Header("Seeding")] [FoldoutGroup("Seeding")]
[Tooltip("If true, a random seed will be generated at runtime.")] [Tooltip("If true, a random seed will be generated at runtime.")]
public bool useRandomSeed = true; public bool useRandomSeed = true;
[FoldoutGroup("Seeding")]
[Tooltip("Seed used when useRandomSeed is false.")] [Tooltip("Seed used when useRandomSeed is false.")]
[HideIf("useRandomSeed")]
public int seed = 1337; public int seed = 1337;
[Header("Starting Location")] [FoldoutGroup("Starting Location")]
[Tooltip("Starting coordinates for the generator (usually odd numbers like 1, 1).")] [Tooltip("Starting coordinates for the generator (usually odd numbers like 1, 1).")]
public Vector2Int startLocation = new Vector2Int(1, 1); public Vector2Int startLocation = new Vector2Int(1, 1);
[Header("Rooms Configuration")] [FoldoutGroup("Rooms Configuration")]
[Tooltip("Whether to place open rooms in the maze before generating corridors.")] [Tooltip("Whether to place open rooms in the maze before generating corridors.")]
public bool generateRooms = true; public bool generateRooms = true;
[FoldoutGroup("Rooms Configuration")]
[Tooltip("Number of rooms to attempt to generate.")] [Tooltip("Number of rooms to attempt to generate.")]
[Min(0)] [ShowIf("generateRooms")]
[MinValue(0)]
public int roomCount = 3; public int roomCount = 3;
[FoldoutGroup("Rooms Configuration")]
[Tooltip("Minimum room size (width and height).")] [Tooltip("Minimum room size (width and height).")]
[ShowIf("generateRooms")]
public Vector2Int minRoomSize = new Vector2Int(3, 3); public Vector2Int minRoomSize = new Vector2Int(3, 3);
[FoldoutGroup("Rooms Configuration")]
[Tooltip("Maximum room size (width and height).")] [Tooltip("Maximum room size (width and height).")]
[ShowIf("generateRooms")]
public Vector2Int maxRoomSize = new Vector2Int(5, 5); public Vector2Int maxRoomSize = new Vector2Int(5, 5);
[Header("Maze Density & Loops")] [FoldoutGroup("Maze Density & Loops")]
[Tooltip("Probability (0 to 1) of carving extra doors for rooms to allow multiple entry points.")] [Tooltip("Probability (0 to 1) of carving extra doors for rooms to allow multiple entry points.")]
[Range(0f, 1f)] [ShowIf("generateRooms")]
[PropertyRange(0f, 1f)]
public float extraRoomDoorChance = 0.3f; public float extraRoomDoorChance = 0.3f;
[FoldoutGroup("Maze Density & Loops")]
[Tooltip("Probability (0 to 1) of removing dead-ends or carving random extra walls to introduce loops/alternative paths.")] [Tooltip("Probability (0 to 1) of removing dead-ends or carving random extra walls to introduce loops/alternative paths.")]
[Range(0f, 1f)] [PropertyRange(0f, 1f)]
public float loopChance = 0.1f; public float loopChance = 0.1f;
} }
} }

View File

@@ -12,28 +12,39 @@ namespace Baba_yaga.GameSetup.MazeRework
/// </summary> /// </summary>
public class MazeReworkManager : MonoBehaviour public class MazeReworkManager : MonoBehaviour
{ {
[Header("Configuration")] [FoldoutGroup("Setup")]
[Required]
[SerializeField] private MazeReworkConfig config; [SerializeField] private MazeReworkConfig config;
[Header("References")] [FoldoutGroup("Setup")]
[Required]
[SerializeField] private MazeReworkSpawner spawner; [SerializeField] private MazeReworkSpawner spawner;
[FoldoutGroup("Setup")]
[Required]
[SerializeField] private Transform mazeContainer; [SerializeField] private Transform mazeContainer;
[FoldoutGroup("Setup")]
[SerializeField] private MazeAnimator animator; [SerializeField] private MazeAnimator animator;
[Header("Animation")] [FoldoutGroup("Animation")]
[Tooltip("If true, visually animates the generation process step-by-step. (Best used with 1 floor)")] [Tooltip("If true, visually animates the generation process step-by-step. (Best used with 1 floor)")]
[SerializeField] private bool animateGeneration = false; [SerializeField] private bool animateGeneration = false;
[Header("Multi-floor Settings")] [FoldoutGroup("Multi-floor Settings")]
[Tooltip("Number of floors to generate.")] [Tooltip("Number of floors to generate.")]
[Min(1)] [MinValue(1)]
[SerializeField] private int floorCount = 1; [SerializeField] private int floorCount = 1;
[FoldoutGroup("Multi-floor Settings")]
[Tooltip("Physical height difference between adjacent floors.")] [Tooltip("Physical height difference between adjacent floors.")]
[ShowIf("@floorCount > 1")]
[SerializeField] private float floorHeight = 4.0f; [SerializeField] private float floorHeight = 4.0f;
[FoldoutGroup("Multi-floor Settings")]
[Tooltip("Number of staircase connections to generate between adjacent floors.")] [Tooltip("Number of staircase connections to generate between adjacent floors.")]
[Min(0)] [ShowIf("@floorCount > 1")]
[MinValue(0)]
[SerializeField] private int connectionsPerFloor = 2; [SerializeField] private int connectionsPerFloor = 2;
private List<MazeReworkCellType[,]> _grids = new List<MazeReworkCellType[,]>(); private List<MazeReworkCellType[,]> _grids = new List<MazeReworkCellType[,]>();
@@ -85,9 +96,9 @@ namespace Baba_yaga.GameSetup.MazeRework
/// <summary> /// <summary>
/// Generates the maze grid data using the rework generator and initializes the spawner. /// Generates the maze grid data using the rework generator and initializes the spawner.
/// Clears existing maze and generates a new one.
/// </summary> /// </summary>
[Button("Generate Maze", ButtonSizes.Large)] [Button("Generate Maze", ButtonSizes.Large)]
[ContextMenu("Generate Maze")]
public void GenerateAndSpawn() public void GenerateAndSpawn()
{ {
if (config == null) if (config == null)

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Sirenix.OdinInspector;
using Baba_yaga.GameSetup.MazeRework.Animation; using Baba_yaga.GameSetup.MazeRework.Animation;
namespace Baba_yaga.GameSetup.MazeRework namespace Baba_yaga.GameSetup.MazeRework
@@ -10,63 +11,129 @@ namespace Baba_yaga.GameSetup.MazeRework
/// </summary> /// </summary>
public class MazeReworkSpawner : MonoBehaviour public class MazeReworkSpawner : MonoBehaviour
{ {
[Header("Modular Hallway Prefabs")] [FoldoutGroup("Modular Hallway Prefabs")]
[FoldoutGroup("Modular Hallway Prefabs/Hall 'I' (Straight)")]
[Tooltip("Prefab for Hall 'I' (Straight connection - opposite paths).")] [Tooltip("Prefab for Hall 'I' (Straight connection - opposite paths).")]
[AssetsOnly]
public GameObject hallPrefab; public GameObject hallPrefab;
[FoldoutGroup("Modular Hallway Prefabs/Hall 'I' (Straight)")]
[AssetsOnly]
public GameObject[] hallPrefabs;
[FoldoutGroup("Modular Hallway Prefabs/HallDoubleRoom '+' (Crossroad)")]
[Tooltip("Prefab for HallDoubleRoom '+' (Crossroad connection - 4-way intersection).")] [Tooltip("Prefab for HallDoubleRoom '+' (Crossroad connection - 4-way intersection).")]
[AssetsOnly]
public GameObject hallDoubleRoomPrefab; public GameObject hallDoubleRoomPrefab;
[FoldoutGroup("Modular Hallway Prefabs/HallDoubleRoom '+' (Crossroad)")]
[AssetsOnly]
public GameObject[] hallDoubleRoomPrefabs;
[FoldoutGroup("Modular Hallway Prefabs/HallT '⊢' (T-Junction)")]
[Tooltip("Prefab for HallT '⊢' (T-Junction connection - 3-way intersection).")] [Tooltip("Prefab for HallT '⊢' (T-Junction connection - 3-way intersection).")]
[AssetsOnly]
public GameObject hallTPrefab; public GameObject hallTPrefab;
[FoldoutGroup("Modular Hallway Prefabs/HallT '⊢' (T-Junction)")]
[AssetsOnly]
public GameObject[] hallTPrefabs;
[FoldoutGroup("Modular Hallway Prefabs/Turn 'L' (Corner)")]
[Tooltip("Prefab for turn 'L' (Corner connection - 2 adjacent paths).")] [Tooltip("Prefab for turn 'L' (Corner connection - 2 adjacent paths).")]
[AssetsOnly]
public GameObject turnPrefab; public GameObject turnPrefab;
[FoldoutGroup("Modular Hallway Prefabs/Turn 'L' (Corner)")]
[AssetsOnly]
public GameObject[] turnPrefabs;
[FoldoutGroup("Modular Hallway Prefabs/U-Turn 'U' (Dead end)")]
[Tooltip("Prefab for U-Turn 'U' (Dead end - 1 path).")] [Tooltip("Prefab for U-Turn 'U' (Dead end - 1 path).")]
[AssetsOnly]
public GameObject uTurnPrefab; public GameObject uTurnPrefab;
[FoldoutGroup("Modular Hallway Prefabs/U-Turn 'U' (Dead end)")]
[AssetsOnly]
public GameObject[] uTurnPrefabs;
[Header("Special Modular Prefabs")] [FoldoutGroup("Special Modular Prefabs")]
[FoldoutGroup("Special Modular Prefabs/Beginning (Start)")]
[Tooltip("Prefab for the Beginning cell (player spawn point). Auto-rotates based on neighbors.")] [Tooltip("Prefab for the Beginning cell (player spawn point). Auto-rotates based on neighbors.")]
[AssetsOnly]
public GameObject beginningPrefab; public GameObject beginningPrefab;
[Tooltip("Prefab for the End cell (player exit point). Auto-rotates based on neighbors.")] [FoldoutGroup("Special Modular Prefabs/Beginning (Start)")]
public GameObject endPrefab; [AssetsOnly]
[Tooltip("Prefab for connecting to the next floor. Spawns on the lower floor and acts as a dead-end piece.")] public GameObject[] beginningPrefabs;
public GameObject stairPrefab;
[Header("Preview Mode Settings (Phase 1)")] [FoldoutGroup("Special Modular Prefabs/End (Exit)")]
[Tooltip("Prefab for the End cell (player exit point). Auto-rotates based on neighbors.")]
[AssetsOnly]
public GameObject endPrefab;
[FoldoutGroup("Special Modular Prefabs/End (Exit)")]
[AssetsOnly]
public GameObject[] endPrefabs;
[FoldoutGroup("Special Modular Prefabs/Stairs (Multi-floor)")]
[Tooltip("Prefab for connecting to the next floor. Spawns on the lower floor and acts as a dead-end piece.")]
[AssetsOnly]
public GameObject stairPrefab;
[FoldoutGroup("Special Modular Prefabs/Stairs (Multi-floor)")]
[AssetsOnly]
public GameObject[] stairPrefabs;
[FoldoutGroup("Preview Mode Settings")]
[Tooltip("If true, the spawner will only spawn simple preview blocks instead of full 3D modular pieces.")] [Tooltip("If true, the spawner will only spawn simple preview blocks instead of full 3D modular pieces.")]
public bool isPreviewMode = false; public bool isPreviewMode = false;
[FoldoutGroup("Preview Mode Settings")]
[Tooltip("Simple prefab to represent carved paths during the algorithm phase (e.g. a flat plane or basic cube).")] [Tooltip("Simple prefab to represent carved paths during the algorithm phase (e.g. a flat plane or basic cube).")]
[ShowIf("isPreviewMode")]
[AssetsOnly]
public GameObject previewPathPrefab; public GameObject previewPathPrefab;
[FoldoutGroup("Preview Mode Settings")]
[Tooltip("Simple prefab to represent walls during the algorithm phase (optional, can be left null).")] [Tooltip("Simple prefab to represent walls during the algorithm phase (optional, can be left null).")]
[ShowIf("isPreviewMode")]
[AssetsOnly]
public GameObject previewWallPrefab; public GameObject previewWallPrefab;
[Header("Highlight Prefabs (Animation Only)")] [FoldoutGroup("Highlight Prefabs (Animation Only)")]
[AssetsOnly]
public GameObject searchHeadPrefab; public GameObject searchHeadPrefab;
[FoldoutGroup("Highlight Prefabs (Animation Only)")]
[AssetsOnly]
public GameObject frontierPrefab; public GameObject frontierPrefab;
[FoldoutGroup("Highlight Prefabs (Animation Only)")]
[AssetsOnly]
public GameObject evaluatingPrefab; public GameObject evaluatingPrefab;
[Header("Rotation Offsets (Degrees)")] [FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to Hall 'I' prefab.")] [Tooltip("Rotation offset added to Hall 'I' prefab.")]
public float hallRotationOffset = 0f; public float hallRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to HallDoubleRoom '+' prefab.")] [Tooltip("Rotation offset added to HallDoubleRoom '+' prefab.")]
public float hallDoubleRoomRotationOffset = 0f; public float hallDoubleRoomRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to HallT '⊢' prefab.")] [Tooltip("Rotation offset added to HallT '⊢' prefab.")]
public float hallTRotationOffset = 0f; public float hallTRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to turn 'L' prefab.")] [Tooltip("Rotation offset added to turn 'L' prefab.")]
public float turnRotationOffset = 0f; public float turnRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to U-Turn 'U' prefab.")] [Tooltip("Rotation offset added to U-Turn 'U' prefab.")]
public float uTurnRotationOffset = 0f; public float uTurnRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to Beginning prefab.")] [Tooltip("Rotation offset added to Beginning prefab.")]
public float beginningRotationOffset = 0f; public float beginningRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to End prefab.")] [Tooltip("Rotation offset added to End prefab.")]
public float endRotationOffset = 0f; public float endRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to Stair prefab.")] [Tooltip("Rotation offset added to Stair prefab.")]
public float stairRotationOffset = 0f; public float stairRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Height offset added to Stair prefab.")] [Tooltip("Height offset added to Stair prefab.")]
public float stairHeightOffset = 0f; public float stairHeightOffset = 0f;
[Header("Spacing Settings")] [FoldoutGroup("Spacing Settings")]
[Tooltip("Physical distance between each grid cell center.")] [Tooltip("Physical distance between each grid cell center.")]
[MinValue(0.1f)]
public float spacing = 3.0f; public float spacing = 3.0f;
private struct SpawnedCellData private struct SpawnedCellData
@@ -236,15 +303,15 @@ namespace Baba_yaga.GameSetup.MazeRework
{ {
if (type == MazeReworkCellType.Start && beginningPrefab != null) if (type == MazeReworkCellType.Start && beginningPrefab != null)
{ {
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth); (_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetPrefab = beginningPrefab; targetPrefab = GetRandomPrefab(beginningPrefab, beginningPrefabs, x, z, yOffset);
targetRot = baseRot + beginningRotationOffset; targetRot = baseRot + beginningRotationOffset;
targetName = "Beginning"; targetName = "Beginning";
} }
else if (type == MazeReworkCellType.End && endPrefab != null) else if (type == MazeReworkCellType.End && endPrefab != null)
{ {
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth); (_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetPrefab = endPrefab; targetPrefab = GetRandomPrefab(endPrefab, endPrefabs, x, z, yOffset);
targetRot = baseRot + endRotationOffset; targetRot = baseRot + endRotationOffset;
targetName = "End"; targetName = "End";
} }
@@ -252,15 +319,15 @@ namespace Baba_yaga.GameSetup.MazeRework
{ {
if (stairPrefab != null) if (stairPrefab != null)
{ {
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth); (_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetPrefab = stairPrefab; targetPrefab = GetRandomPrefab(stairPrefab, stairPrefabs, x, z, yOffset);
targetRot = baseRot + stairRotationOffset; targetRot = baseRot + stairRotationOffset;
targetName = "StairConnection"; targetName = "StairConnection";
yOffset += stairHeightOffset; yOffset += stairHeightOffset;
} }
else else
{ {
(targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth); (targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetName = $"{type}"; targetName = $"{type}";
} }
} }
@@ -273,7 +340,7 @@ namespace Baba_yaga.GameSetup.MazeRework
} }
else else
{ {
(targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth); (targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetName = $"{type}"; targetName = $"{type}";
} }
} }
@@ -335,7 +402,18 @@ namespace Baba_yaga.GameSetup.MazeRework
return group; return group;
} }
private (GameObject, float) GetModularPrefabAndRotation(MazeReworkCellType[,] grid, int x, int z, int width, int depth) private GameObject GetRandomPrefab(GameObject single, GameObject[] array, int x, int z, float yOffset)
{
if (array != null && array.Length > 0)
{
int hash = (x * 73856093) ^ (z * 19349663) ^ (Mathf.RoundToInt(yOffset * 100f) * 83492791);
System.Random rng = new System.Random(hash);
return array[rng.Next(array.Length)];
}
return single;
}
private (GameObject, float) GetModularPrefabAndRotation(MazeReworkCellType[,] grid, int x, int z, int width, int depth, float yOffset)
{ {
bool top = IsPath(grid, x, z + 1, width, depth); bool top = IsPath(grid, x, z + 1, width, depth);
bool right = IsPath(grid, x + 1, z, width, depth); bool right = IsPath(grid, x + 1, z, width, depth);
@@ -351,32 +429,32 @@ namespace Baba_yaga.GameSetup.MazeRework
switch (mask) switch (mask)
{ {
// --- 1 open connection: U-Turn "U" --- // --- 1 open connection: U-Turn "U" ---
case 1: return (uTurnPrefab, 0f + uTurnRotationOffset); // Open to Top case 1: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 0f + uTurnRotationOffset); // Open to Top
case 2: return (uTurnPrefab, 90f + uTurnRotationOffset); // Open to Right case 2: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 90f + uTurnRotationOffset); // Open to Right
case 4: return (uTurnPrefab, 180f + uTurnRotationOffset); // Open to Bottom case 4: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 180f + uTurnRotationOffset); // Open to Bottom
case 8: return (uTurnPrefab, 270f + uTurnRotationOffset); // Open to Left case 8: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 270f + uTurnRotationOffset); // Open to Left
// --- 2 opposite open connections: Hall "I" --- // --- 2 opposite open connections: Hall "I" ---
case 5: return (hallPrefab, 0f + hallRotationOffset); // Open to Top & Bottom case 5: return (GetRandomPrefab(hallPrefab, hallPrefabs, x, z, yOffset), 0f + hallRotationOffset); // Open to Top & Bottom
case 10: return (hallPrefab, 90f + hallRotationOffset); // Open to Left & Right case 10: return (GetRandomPrefab(hallPrefab, hallPrefabs, x, z, yOffset), 90f + hallRotationOffset); // Open to Left & Right
// --- 2 adjacent open connections: turn "L" --- // --- 2 adjacent open connections: turn "L" ---
case 3: return (turnPrefab, 0f + turnRotationOffset); // Open to Top & Right case 3: return (GetRandomPrefab(turnPrefab, turnPrefabs, x, z, yOffset), 0f + turnRotationOffset); // Open to Top & Right
case 6: return (turnPrefab, 90f + turnRotationOffset); // Open to Right & Bottom case 6: return (GetRandomPrefab(turnPrefab, turnPrefabs, x, z, yOffset), 90f + turnRotationOffset); // Open to Right & Bottom
case 12: return (turnPrefab, 180f + turnRotationOffset); // Open to Bottom & Left case 12: return (GetRandomPrefab(turnPrefab, turnPrefabs, x, z, yOffset), 180f + turnRotationOffset); // Open to Bottom & Left
case 9: return (turnPrefab, 270f + turnRotationOffset); // Open to Left & Top case 9: return (GetRandomPrefab(turnPrefab, turnPrefabs, x, z, yOffset), 270f + turnRotationOffset); // Open to Left & Top
// --- 3 open connections: HallT "⊢" --- // --- 3 open connections: HallT "⊢" ---
case 11: return (hallTPrefab, 0f + hallTRotationOffset); // Open to Top, Right, Left (no Bottom) case 11: return (GetRandomPrefab(hallTPrefab, hallTPrefabs, x, z, yOffset), 0f + hallTRotationOffset); // Open to Top, Right, Left (no Bottom)
case 7: return (hallTPrefab, 90f + hallTRotationOffset); // Open to Top, Right, Bottom (no Left) case 7: return (GetRandomPrefab(hallTPrefab, hallTPrefabs, x, z, yOffset), 90f + hallTRotationOffset); // Open to Top, Right, Bottom (no Left)
case 14: return (hallTPrefab, 180f + hallTRotationOffset); // Open to Right, Bottom, Left (no Top) case 14: return (GetRandomPrefab(hallTPrefab, hallTPrefabs, x, z, yOffset), 180f + hallTRotationOffset); // Open to Right, Bottom, Left (no Top)
case 13: return (hallTPrefab, 270f + hallTRotationOffset); // Open to Bottom, Left, Top (no Right) case 13: return (GetRandomPrefab(hallTPrefab, hallTPrefabs, x, z, yOffset), 270f + hallTRotationOffset); // Open to Bottom, Left, Top (no Right)
// --- 4 open connections: HallDoubleRoom "+" --- // --- 4 open connections: HallDoubleRoom "+" ---
case 15: return (hallDoubleRoomPrefab, 0f + hallDoubleRoomRotationOffset); // Open in all 4 directions case 15: return (GetRandomPrefab(hallDoubleRoomPrefab, hallDoubleRoomPrefabs, x, z, yOffset), 0f + hallDoubleRoomRotationOffset); // Open in all 4 directions
// Fallback for isolated cells (0 connections) // Fallback for isolated cells (0 connections)
default: return (uTurnPrefab, 0f + uTurnRotationOffset); default: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 0f + uTurnRotationOffset);
} }
} }