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

@@ -1,22 +1,37 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
namespace Baba_yaga.GameSetup.MazeRework.Animation
{
public enum RenderSweepStyle
{
RowByRow,
CenterOut,
RandomPop
}
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).")]
[Min(1)]
[MinValue(1)]
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!")]
public float stepDelay = 0.05f;
[FoldoutGroup("Algorithm Animation")]
[Tooltip("Extra delay (in seconds) between major generation phases (like switching from Rooms to Carving).")]
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;
public void AnimateGeneration(
@@ -33,6 +48,8 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
_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()
{
if (_animationRoutine != null)
@@ -122,49 +139,70 @@ namespace Baba_yaga.GameSetup.MazeRework.Animation
// --- Phase 2: Render 3D Map ---
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 x = 0; x < width; x++)
{
workingGrid[x, z] = finalGrid[x, z];
workingHighlights[x, z] = MazeCellHighlight.None;
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];
workingHighlights[x, z] = MazeCellHighlight.None;
if (finalGrid[x, z] != MazeReworkCellType.Wall)
{
spawner.FlashHighlight(MazeCellHighlight.EvaluatingValid, x, z, yOffset, container);
// Only yield when we actually spawn a piece to create a cool sweep wave!
if (finalGrid[x, z] != MazeReworkCellType.Wall)
if (stepDelay > 0f)
{
// 1. Flash an Evaluating highlight to visualize "choosing" this cell
spawner.FlashHighlight(MazeCellHighlight.EvaluatingValid, x, z, yOffset, container);
if (stepDelay > 0f)
{
yield return new WaitForSeconds(stepDelay * 0.5f); // Short pause for the check
}
// 2. Spawn the actual piece
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
// Wait a tiny fraction of a second to create the sweeping wave effect
if (stepDelay > 0f)
{
yield return new WaitForSeconds(stepDelay * 0.5f); // faster than the algorithm checks
}
else
{
processedThisFrame++;
if (processedThisFrame >= cellsPerFrame * 2) // Twice as fast as algorithm phase
{
yield return null;
processedThisFrame = 0;
}
}
yield return new WaitForSeconds(stepDelay * 0.5f);
}
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
if (stepDelay > 0f)
{
yield return new WaitForSeconds(stepDelay * 0.5f);
}
else
{
// Even if it's a wall, refresh it to clear the preview walls (if any)
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
processedThisFrame++;
if (processedThisFrame >= cellsPerFrame * 2)
{
yield return null;
processedThisFrame = 0;
}
}
}
else
{
spawner.RefreshCell(workingGrid, workingHighlights, x, z, yOffset, container);
}
}
_animationRoutine = null;

View File

@@ -1,4 +1,5 @@
using UnityEngine;
using Sirenix.OdinInspector;
using Baba_yaga.GameSetup.MazeRework.Algorithms;
namespace Baba_yaga.GameSetup.MazeRework
@@ -20,51 +21,63 @@ namespace Baba_yaga.GameSetup.MazeRework
[CreateAssetMenu(fileName = "MazeReworkConfig", menuName = "BABA_YAGA/MazeRework/Config")]
public class MazeReworkConfig : ScriptableObject
{
[Header("Algorithm")]
[FoldoutGroup("Algorithm")]
[Tooltip("Which carving algorithm to use for generating the maze corridors.")]
[EnumToggleButtons]
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.")]
[Min(5)]
[MinValue(5)]
public int width = 21;
[FoldoutGroup("Grid Dimensions")]
[Tooltip("Depth of the maze grid. Best if odd to align with wall-corridor-wall patterning.")]
[Min(5)]
[MinValue(5)]
public int depth = 21;
[Header("Seeding")]
[FoldoutGroup("Seeding")]
[Tooltip("If true, a random seed will be generated at runtime.")]
public bool useRandomSeed = true;
[FoldoutGroup("Seeding")]
[Tooltip("Seed used when useRandomSeed is false.")]
[HideIf("useRandomSeed")]
public int seed = 1337;
[Header("Starting Location")]
[FoldoutGroup("Starting Location")]
[Tooltip("Starting coordinates for the generator (usually odd numbers like 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.")]
public bool generateRooms = true;
[FoldoutGroup("Rooms Configuration")]
[Tooltip("Number of rooms to attempt to generate.")]
[Min(0)]
[ShowIf("generateRooms")]
[MinValue(0)]
public int roomCount = 3;
[FoldoutGroup("Rooms Configuration")]
[Tooltip("Minimum room size (width and height).")]
[ShowIf("generateRooms")]
public Vector2Int minRoomSize = new Vector2Int(3, 3);
[FoldoutGroup("Rooms Configuration")]
[Tooltip("Maximum room size (width and height).")]
[ShowIf("generateRooms")]
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.")]
[Range(0f, 1f)]
[ShowIf("generateRooms")]
[PropertyRange(0f, 1f)]
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.")]
[Range(0f, 1f)]
[PropertyRange(0f, 1f)]
public float loopChance = 0.1f;
}
}

View File

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

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
using Baba_yaga.GameSetup.MazeRework.Animation;
namespace Baba_yaga.GameSetup.MazeRework
@@ -10,63 +11,129 @@ namespace Baba_yaga.GameSetup.MazeRework
/// </summary>
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).")]
[AssetsOnly]
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).")]
[AssetsOnly]
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).")]
[AssetsOnly]
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).")]
[AssetsOnly]
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).")]
[AssetsOnly]
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.")]
[AssetsOnly]
public GameObject beginningPrefab;
[FoldoutGroup("Special Modular Prefabs/Beginning (Start)")]
[AssetsOnly]
public GameObject[] beginningPrefabs;
[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;
[Header("Preview Mode Settings (Phase 1)")]
[FoldoutGroup("Preview Mode Settings")]
[Tooltip("If true, the spawner will only spawn simple preview blocks instead of full 3D modular pieces.")]
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).")]
[ShowIf("isPreviewMode")]
[AssetsOnly]
public GameObject previewPathPrefab;
[FoldoutGroup("Preview Mode Settings")]
[Tooltip("Simple prefab to represent walls during the algorithm phase (optional, can be left null).")]
[ShowIf("isPreviewMode")]
[AssetsOnly]
public GameObject previewWallPrefab;
[Header("Highlight Prefabs (Animation Only)")]
[FoldoutGroup("Highlight Prefabs (Animation Only)")]
[AssetsOnly]
public GameObject searchHeadPrefab;
[FoldoutGroup("Highlight Prefabs (Animation Only)")]
[AssetsOnly]
public GameObject frontierPrefab;
[FoldoutGroup("Highlight Prefabs (Animation Only)")]
[AssetsOnly]
public GameObject evaluatingPrefab;
[Header("Rotation Offsets (Degrees)")]
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to Hall 'I' prefab.")]
public float hallRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to HallDoubleRoom '+' prefab.")]
public float hallDoubleRoomRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to HallT '⊢' prefab.")]
public float hallTRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to turn 'L' prefab.")]
public float turnRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to U-Turn 'U' prefab.")]
public float uTurnRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to Beginning prefab.")]
public float beginningRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to End prefab.")]
public float endRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Rotation offset added to Stair prefab.")]
public float stairRotationOffset = 0f;
[FoldoutGroup("Offsets (Rotation & Height)")]
[Tooltip("Height offset added to Stair prefab.")]
public float stairHeightOffset = 0f;
[Header("Spacing Settings")]
[FoldoutGroup("Spacing Settings")]
[Tooltip("Physical distance between each grid cell center.")]
[MinValue(0.1f)]
public float spacing = 3.0f;
private struct SpawnedCellData
@@ -236,15 +303,15 @@ namespace Baba_yaga.GameSetup.MazeRework
{
if (type == MazeReworkCellType.Start && beginningPrefab != null)
{
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
targetPrefab = beginningPrefab;
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetPrefab = GetRandomPrefab(beginningPrefab, beginningPrefabs, x, z, yOffset);
targetRot = baseRot + beginningRotationOffset;
targetName = "Beginning";
}
else if (type == MazeReworkCellType.End && endPrefab != null)
{
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
targetPrefab = endPrefab;
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetPrefab = GetRandomPrefab(endPrefab, endPrefabs, x, z, yOffset);
targetRot = baseRot + endRotationOffset;
targetName = "End";
}
@@ -252,15 +319,15 @@ namespace Baba_yaga.GameSetup.MazeRework
{
if (stairPrefab != null)
{
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
targetPrefab = stairPrefab;
(_, float baseRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetPrefab = GetRandomPrefab(stairPrefab, stairPrefabs, x, z, yOffset);
targetRot = baseRot + stairRotationOffset;
targetName = "StairConnection";
yOffset += stairHeightOffset;
}
else
{
(targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
(targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetName = $"{type}";
}
}
@@ -273,7 +340,7 @@ namespace Baba_yaga.GameSetup.MazeRework
}
else
{
(targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth);
(targetPrefab, targetRot) = GetModularPrefabAndRotation(grid, x, z, width, depth, yOffset);
targetName = $"{type}";
}
}
@@ -335,7 +402,18 @@ namespace Baba_yaga.GameSetup.MazeRework
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 right = IsPath(grid, x + 1, z, width, depth);
@@ -351,32 +429,32 @@ namespace Baba_yaga.GameSetup.MazeRework
switch (mask)
{
// --- 1 open connection: U-Turn "U" ---
case 1: return (uTurnPrefab, 0f + uTurnRotationOffset); // Open to Top
case 2: return (uTurnPrefab, 90f + uTurnRotationOffset); // Open to Right
case 4: return (uTurnPrefab, 180f + uTurnRotationOffset); // Open to Bottom
case 8: return (uTurnPrefab, 270f + uTurnRotationOffset); // Open to Left
case 1: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 0f + uTurnRotationOffset); // Open to Top
case 2: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 90f + uTurnRotationOffset); // Open to Right
case 4: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 180f + uTurnRotationOffset); // Open to Bottom
case 8: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 270f + uTurnRotationOffset); // Open to Left
// --- 2 opposite open connections: Hall "I" ---
case 5: return (hallPrefab, 0f + hallRotationOffset); // Open to Top & Bottom
case 10: return (hallPrefab, 90f + hallRotationOffset); // Open to Left & Right
case 5: return (GetRandomPrefab(hallPrefab, hallPrefabs, x, z, yOffset), 0f + hallRotationOffset); // Open to Top & Bottom
case 10: return (GetRandomPrefab(hallPrefab, hallPrefabs, x, z, yOffset), 90f + hallRotationOffset); // Open to Left & Right
// --- 2 adjacent open connections: turn "L" ---
case 3: return (turnPrefab, 0f + turnRotationOffset); // Open to Top & Right
case 6: return (turnPrefab, 90f + turnRotationOffset); // Open to Right & Bottom
case 12: return (turnPrefab, 180f + turnRotationOffset); // Open to Bottom & Left
case 9: return (turnPrefab, 270f + turnRotationOffset); // Open to Left & Top
case 3: return (GetRandomPrefab(turnPrefab, turnPrefabs, x, z, yOffset), 0f + turnRotationOffset); // Open to Top & Right
case 6: return (GetRandomPrefab(turnPrefab, turnPrefabs, x, z, yOffset), 90f + turnRotationOffset); // Open to Right & Bottom
case 12: return (GetRandomPrefab(turnPrefab, turnPrefabs, x, z, yOffset), 180f + turnRotationOffset); // Open to Bottom & Left
case 9: return (GetRandomPrefab(turnPrefab, turnPrefabs, x, z, yOffset), 270f + turnRotationOffset); // Open to Left & Top
// --- 3 open connections: HallT "⊢" ---
case 11: return (hallTPrefab, 0f + hallTRotationOffset); // Open to Top, Right, Left (no Bottom)
case 7: return (hallTPrefab, 90f + hallTRotationOffset); // Open to Top, Right, Bottom (no Left)
case 14: return (hallTPrefab, 180f + hallTRotationOffset); // Open to Right, Bottom, Left (no Top)
case 13: return (hallTPrefab, 270f + hallTRotationOffset); // Open to Bottom, Left, Top (no Right)
case 11: return (GetRandomPrefab(hallTPrefab, hallTPrefabs, x, z, yOffset), 0f + hallTRotationOffset); // Open to Top, Right, Left (no Bottom)
case 7: return (GetRandomPrefab(hallTPrefab, hallTPrefabs, x, z, yOffset), 90f + hallTRotationOffset); // Open to Top, Right, Bottom (no Left)
case 14: return (GetRandomPrefab(hallTPrefab, hallTPrefabs, x, z, yOffset), 180f + hallTRotationOffset); // Open to Right, Bottom, Left (no Top)
case 13: return (GetRandomPrefab(hallTPrefab, hallTPrefabs, x, z, yOffset), 270f + hallTRotationOffset); // Open to Bottom, Left, Top (no Right)
// --- 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)
default: return (uTurnPrefab, 0f + uTurnRotationOffset);
default: return (GetRandomPrefab(uTurnPrefab, uTurnPrefabs, x, z, yOffset), 0f + uTurnRotationOffset);
}
}