This commit is contained in:
2026-07-04 01:51:03 +07:00
parent 0b98175ece
commit 4e4b990f8c
1670 changed files with 5035 additions and 679869 deletions

View File

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

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 30892b1102feb6841a9288ddb11ef50d

View File

@@ -0,0 +1,514 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Baba_yaga.GameSetup.MazeRework
{
/// <summary>
/// Logical cell types for the reworked maze.
/// </summary>
public enum MazeReworkCellType
{
Wall,
Corridor,
Room,
Start,
End,
StairsUp,
StairsDown
}
/// <summary>
/// Standalone generator class that generates an x * y maze using a MazeReworkConfig object.
/// Returns a 2D array of MazeReworkCellType with no legacy dependencies.
/// </summary>
public class MazeReworkGenerator
{
public struct Room
{
public int x;
public int z;
public int width;
public int depth;
public bool isConnected;
public bool Overlaps(Room other, int padding)
{
return x - padding < other.x + other.width &&
x + width + padding > other.x &&
z - padding < other.z + other.depth &&
z + depth + padding > other.z;
}
public Vector2Int GetCenter()
{
return new Vector2Int(x + width / 2, z + depth / 2);
}
}
private readonly MazeReworkConfig _config;
public MazeReworkGenerator(MazeReworkConfig config)
{
_config = config;
}
/// <summary>
/// Generates a 2D layout of the maze of size config.width by config.depth using the default config seed.
/// </summary>
public MazeReworkCellType[,] Generate()
{
if (_config == null) return null;
int seed = _config.useRandomSeed ? System.DateTime.Now.Millisecond + System.Threading.Thread.CurrentThread.ManagedThreadId : _config.seed;
return Generate(seed);
}
/// <summary>
/// Generates a 2D layout of the maze of size config.width by config.depth using a specific seed.
/// </summary>
public MazeReworkCellType[,] Generate(int seed)
{
if (_config == null) return null;
int width = _config.width;
int depth = _config.depth;
var grid = new MazeReworkCellType[width, depth];
// 1. Initialize all cells as Wall
for (int z = 0; z < depth; z++)
{
for (int x = 0; x < width; x++)
{
grid[x, z] = MazeReworkCellType.Wall;
}
}
System.Random rng = new System.Random(seed);
// 2. Generate Rooms
List<Room> rooms = GenerateRooms(grid, width, depth, rng);
// 3. Setup Visited tracking array
bool[,] visited = new bool[width, depth];
InitializeVisitedMap(grid, visited, rooms, width, depth);
// 4. Select starting coordinates
int startX = _config.startLocation.x;
int startZ = _config.startLocation.y;
EnsureValidOddCoordinates(width, depth, ref startX, ref startZ);
// 5. Carve Corridors recursively using Step-by-2 Recursive Backtracking
visited[startX, startZ] = true;
grid[startX, startZ] = MazeReworkCellType.Corridor;
CarveFrom(startX, startZ, grid, visited, rooms, rng, width, depth);
// 6. Hunt & Kill scan to connect isolated rooms/corridors
EnsureAllConnected(grid, visited, rooms, rng, width, depth);
// 7. Carve optional loops/alternative paths
CarveLoops(grid, rng, width, depth);
// 8. Place Start & End points
PlaceStartAndEnd(grid, rooms, width, depth);
return grid;
}
#region Internal Generation Logic
private List<Room> GenerateRooms(MazeReworkCellType[,] grid, int width, int depth, System.Random rng)
{
List<Room> rooms = new List<Room>();
if (!_config.generateRooms) return rooms;
for (int i = 0; i < _config.roomCount; i++)
{
int minW = Mathf.Max(3, _config.minRoomSize.x);
int maxW = Mathf.Max(minW, _config.maxRoomSize.x);
int minH = Mathf.Max(3, _config.minRoomSize.y);
int maxH = Mathf.Max(minH, _config.maxRoomSize.y);
int rw = 2 * (rng.Next(minW / 2, maxW / 2 + 1)) + 1;
int rh = 2 * (rng.Next(minH / 2, maxH / 2 + 1)) + 1;
int maxX = (width - rw - 1) / 2;
int maxZ = (depth - rh - 1) / 2;
if (maxX < 1 || maxZ < 1) continue;
int rx = 2 * rng.Next(0, maxX) + 1;
int rz = 2 * rng.Next(0, maxZ) + 1;
Room newRoom = new Room { x = rx, z = rz, width = rw, depth = rh, isConnected = false };
bool overlaps = false;
foreach (var r in rooms)
{
if (newRoom.Overlaps(r, 1))
{
overlaps = true;
break;
}
}
if (!overlaps)
{
rooms.Add(newRoom);
// Carve room cells
for (int z = rz; z < rz + rh; z++)
{
for (int x = rx; x < rx + rw; x++)
{
grid[x, z] = MazeReworkCellType.Room;
}
}
}
}
return rooms;
}
private void InitializeVisitedMap(MazeReworkCellType[,] grid, bool[,] visited, List<Room> rooms, int width, int depth)
{
foreach (var r in rooms)
{
for (int z = r.z; z < r.z + r.depth; z++)
{
for (int x = r.x; x < r.x + r.width; x++)
{
visited[x, z] = true;
}
}
}
}
private void CarveFrom(int cx, int cz, MazeReworkCellType[,] grid, bool[,] visited, List<Room> rooms, System.Random rng, int width, int depth)
{
Vector2Int[] dirs = new Vector2Int[4]
{
new Vector2Int(2, 0),
new Vector2Int(-2, 0),
new Vector2Int(0, 2),
new Vector2Int(0, -2)
};
for (int i = 3; i > 0; i--)
{
int j = rng.Next(i + 1);
var temp = dirs[i];
dirs[i] = dirs[j];
dirs[j] = temp;
}
for (int i = 0; i < 4; i++)
{
int nx = cx + dirs[i].x;
int nz = cz + dirs[i].y;
int wx = cx + dirs[i].x / 2;
int wz = cz + dirs[i].y / 2;
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1)
{
if (!visited[nx, nz])
{
grid[wx, wz] = MazeReworkCellType.Corridor;
grid[nx, nz] = MazeReworkCellType.Corridor;
visited[wx, wz] = true;
visited[nx, nz] = true;
CarveFrom(nx, nz, grid, visited, rooms, rng, width, depth);
}
else if (grid[nx, nz] == MazeReworkCellType.Room)
{
int roomIndex = FindRoomIndex(rooms, nx, nz);
if (roomIndex >= 0)
{
var room = rooms[roomIndex];
if (!room.isConnected)
{
grid[wx, wz] = MazeReworkCellType.Corridor;
visited[wx, wz] = true;
room.isConnected = true;
rooms[roomIndex] = room;
}
else if (rng.NextDouble() < _config.extraRoomDoorChance)
{
if (grid[wx, wz] == MazeReworkCellType.Wall)
{
grid[wx, wz] = MazeReworkCellType.Corridor;
visited[wx, wz] = true;
}
}
}
}
}
}
}
private void EnsureAllConnected(MazeReworkCellType[,] grid, bool[,] visited, List<Room> rooms, System.Random rng, int width, int depth)
{
for (int z = 1; z < depth - 1; z += 2)
{
for (int x = 1; x < width - 1; x += 2)
{
if (!visited[x, z])
{
Vector2Int[] dirs = new Vector2Int[4]
{
new Vector2Int(2, 0),
new Vector2Int(-2, 0),
new Vector2Int(0, 2),
new Vector2Int(0, -2)
};
for (int i = 3; i > 0; i--)
{
int j = rng.Next(i + 1);
var temp = dirs[i];
dirs[i] = dirs[j];
dirs[j] = temp;
}
bool connected = false;
for (int i = 0; i < 4; i++)
{
int nx = x + dirs[i].x;
int nz = z + dirs[i].y;
int wx = x + dirs[i].x / 2;
int wz = z + dirs[i].y / 2;
if (nx > 0 && nx < width - 1 && nz > 0 && nz < depth - 1)
{
if (visited[nx, nz])
{
grid[wx, wz] = MazeReworkCellType.Corridor;
grid[x, z] = MazeReworkCellType.Corridor;
visited[wx, wz] = true;
visited[x, z] = true;
connected = true;
break;
}
}
}
if (connected)
{
CarveFrom(x, z, grid, visited, rooms, rng, width, depth);
}
else
{
CarveFrom(x, z, grid, visited, rooms, rng, width, depth);
}
}
}
}
for (int i = 0; i < rooms.Count; i++)
{
var room = rooms[i];
if (!room.isConnected)
{
ForceConnectRoom(grid, room, visited, rng, width, depth);
room.isConnected = true;
rooms[i] = room;
}
}
}
private void ForceConnectRoom(MazeReworkCellType[,] grid, Room room, bool[,] visited, System.Random rng, int width, int depth)
{
int[] sides = new int[] { 0, 1, 2, 3 };
for (int i = 3; i > 0; i--)
{
int j = rng.Next(i + 1);
int temp = sides[i];
sides[i] = sides[j];
sides[j] = temp;
}
foreach (int side in sides)
{
if (side == 0)
{
int z = room.z + room.depth - 1;
if (z + 2 < depth - 1)
{
int x = room.x + 2 * rng.Next(0, room.width / 2);
grid[x, z + 1] = MazeReworkCellType.Corridor;
visited[x, z + 1] = true;
return;
}
}
else if (side == 1)
{
int z = room.z;
if (z - 2 > 0)
{
int x = room.x + 2 * rng.Next(0, room.width / 2);
grid[x, z - 1] = MazeReworkCellType.Corridor;
visited[x, z - 1] = true;
return;
}
}
else if (side == 2)
{
int x = room.x;
if (x - 2 > 0)
{
int z = room.z + 2 * rng.Next(0, room.depth / 2);
grid[x - 1, z] = MazeReworkCellType.Corridor;
visited[x - 1, z] = true;
return;
}
}
else if (side == 3)
{
int x = room.x + room.width - 1;
if (x + 2 < width - 1)
{
int z = room.z + 2 * rng.Next(0, room.depth / 2);
grid[x + 1, z] = MazeReworkCellType.Corridor;
visited[x + 1, z] = true;
return;
}
}
}
}
private void CarveLoops(MazeReworkCellType[,] grid, System.Random rng, int width, int depth)
{
if (_config.loopChance <= 0f) return;
for (int z = 1; z < depth - 1; z++)
{
for (int x = 1; x < width - 1; x++)
{
bool isHorizontalWall = (x % 2 == 0 && z % 2 != 0);
bool isVerticalWall = (x % 2 != 0 && z % 2 == 0);
if (!isHorizontalWall && !isVerticalWall) continue;
if (grid[x, z] == MazeReworkCellType.Wall)
{
if (isHorizontalWall)
{
if (IsPathCell(grid[x - 1, z]) && IsPathCell(grid[x + 1, z]))
{
if (rng.NextDouble() < _config.loopChance)
{
grid[x, z] = MazeReworkCellType.Corridor;
}
}
}
else
{
if (IsPathCell(grid[x, z - 1]) && IsPathCell(grid[x, z + 1]))
{
if (rng.NextDouble() < _config.loopChance)
{
grid[x, z] = MazeReworkCellType.Corridor;
}
}
}
}
}
}
}
private void PlaceStartAndEnd(MazeReworkCellType[,] grid, List<Room> rooms, int width, int depth)
{
if (rooms != null && rooms.Count > 0)
{
var startRoom = rooms[0];
var startPt = startRoom.GetCenter();
grid[startPt.x, startPt.y] = MazeReworkCellType.Start;
var endRoom = rooms[rooms.Count - 1];
var endPt = endRoom.GetCenter();
if (endPt == startPt && rooms.Count > 1)
{
endRoom = rooms[1];
endPt = endRoom.GetCenter();
}
grid[endPt.x, endPt.y] = MazeReworkCellType.End;
}
else
{
int sx = _config.startLocation.x;
int sz = _config.startLocation.y;
EnsureValidOddCoordinates(width, depth, ref sx, ref sz);
grid[sx, sz] = MazeReworkCellType.Start;
int ex = width - 2;
int ez = depth - 2;
EnsureValidOddCoordinates(width, depth, ref ex, ref ez);
if (grid[ex, ez] == MazeReworkCellType.Wall)
{
bool found = false;
for (int r = 1; r < Mathf.Max(width, depth) && !found; r++)
{
for (int dx = -r; dx <= r && !found; dx++)
{
for (int dz = -r; dz <= r && !found; dz++)
{
int tx = ex + dx;
int tz = ez + dz;
if (tx >= 0 && tx < width && tz >= 0 && tz < depth && IsPathCell(grid[tx, tz]))
{
ex = tx;
ez = tz;
found = true;
}
}
}
}
}
if (ex != sx || ez != sz)
{
grid[ex, ez] = MazeReworkCellType.End;
}
}
}
#endregion
#region Helper Functions
private void EnsureValidOddCoordinates(int width, int depth, ref int x, ref int z)
{
if (x < 1) x = 1;
if (x >= width - 1) x = width - 2;
if (x % 2 == 0) x--;
if (z < 1) z = 1;
if (z >= depth - 1) z = depth - 2;
if (z % 2 == 0) z--;
}
private int FindRoomIndex(List<Room> rooms, int x, int z)
{
for (int i = 0; i < rooms.Count; i++)
{
var r = rooms[i];
if (x >= r.x && x < r.x + r.width && z >= r.z && z < r.z + r.depth)
{
return i;
}
}
return -1;
}
private bool IsPathCell(MazeReworkCellType type)
{
return type == MazeReworkCellType.Corridor ||
type == MazeReworkCellType.Room ||
type == MazeReworkCellType.Start ||
type == MazeReworkCellType.End ||
type == MazeReworkCellType.StairsUp ||
type == MazeReworkCellType.StairsDown;
}
#endregion
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 389ebe530f56f834cafe0199c9e75c90

View File

@@ -0,0 +1,188 @@
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
namespace Baba_yaga.GameSetup.MazeRework
{
/// <summary>
/// Manager script that coordinates generating the 2D maze grid layout and spawning prefabs.
/// Completely independent of the legacy maze system and renderer.
/// </summary>
public class MazeReworkManager : MonoBehaviour
{
[Header("Configuration")]
[SerializeField] private MazeReworkConfig config;
[Header("References")]
[SerializeField] private MazeReworkSpawner spawner;
[SerializeField] private Transform mazeContainer;
[Header("Multi-floor Settings")]
[Tooltip("Number of floors to generate.")]
[Min(1)]
[SerializeField] private int floorCount = 1;
[Tooltip("Physical height difference between adjacent floors.")]
[SerializeField] private float floorHeight = 4.0f;
[Tooltip("Number of staircase connections to generate between adjacent floors.")]
[Min(0)]
[SerializeField] private int connectionsPerFloor = 2;
private List<MazeReworkCellType[,]> _grids = new List<MazeReworkCellType[,]>();
private void Start()
{
GenerateAndSpawn();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.R))
{
GenerateAndSpawn();
}
}
/// <summary>
/// Clears all previously spawned maze elements inside the target container.
/// Works in both Play Mode and Edit Mode (deep cleanup).
/// </summary>
[Button("Clear Maze", ButtonSizes.Large)]
[ContextMenu("Clear Maze")]
public void ClearMaze()
{
if (spawner != null)
{
spawner.Clear();
}
_grids.Clear();
// Perform deep hierarchy scan in the container to destroy untracked objects
Transform container = mazeContainer != null ? mazeContainer : transform;
for (int i = container.childCount - 1; i >= 0; i--)
{
var child = container.GetChild(i).gameObject;
if (Application.isPlaying)
Destroy(child);
else
DestroyImmediate(child);
}
}
/// <summary>
/// Generates the maze grid data using the rework generator and initializes the spawner.
/// </summary>
[Button("Generate Maze", ButtonSizes.Large)]
[ContextMenu("Generate Maze")]
public void GenerateAndSpawn()
{
if (config == null)
{
Debug.LogError("MazeReworkManager: Config is not assigned!", this);
return;
}
if (spawner == null)
{
Debug.LogError("MazeReworkManager: Spawner is not assigned!", this);
return;
}
if (mazeContainer == null)
{
mazeContainer = this.transform;
}
// Clear any previously spawned maze objects
ClearMaze();
var generator = new MazeReworkGenerator(config);
// Generate each floor using the configuration
for (int i = 0; i < floorCount; i++)
{
int seed = config.useRandomSeed ? Random.Range(0, 1000000) : config.seed + i * 1000;
var grid = generator.Generate(seed);
_grids.Add(grid);
}
// Connect floors with staircases if multiple floors are present
if (floorCount > 1)
{
GenerateConnections();
}
// Spawn prefabs for all floors
for (int i = 0; i < floorCount; i++)
{
float yOffset = i * floorHeight;
spawner.Spawn(_grids[i], yOffset, mazeContainer);
}
}
private void GenerateConnections()
{
int seed = config.useRandomSeed ? System.DateTime.Now.Millisecond : config.seed;
System.Random rng = new System.Random(seed);
for (int i = 0; i < floorCount - 1; i++)
{
var currentFloor = _grids[i];
var nextFloor = _grids[i + 1];
List<Vector2Int> possibleConnections = new List<Vector2Int>();
int width = config.width;
int depth = config.depth;
for (int z = 1; z < depth - 1; z++)
{
for (int x = 1; x < width - 1; x++)
{
// A staircase requires path cells (corridors or rooms) to exist at the exact same x, z on both floors
bool isCurrentFloorPath = IsPathCell(currentFloor[x, z]);
bool isNextFloorPath = IsPathCell(nextFloor[x, z]);
if (isCurrentFloorPath && isNextFloorPath)
{
possibleConnections.Add(new Vector2Int(x, z));
}
}
}
// Shuffle connections
for (int k = possibleConnections.Count - 1; k > 0; k--)
{
int idx = rng.Next(k + 1);
var temp = possibleConnections[k];
possibleConnections[k] = possibleConnections[idx];
possibleConnections[idx] = temp;
}
int connectionsMade = 0;
foreach (Vector2Int pos in possibleConnections)
{
if (connectionsMade >= connectionsPerFloor) break;
int x = pos.x;
int z = pos.y;
// Set stair cells (stairs up on lower floor, stairs down on upper floor)
currentFloor[x, z] = MazeReworkCellType.StairsUp;
nextFloor[x, z] = MazeReworkCellType.StairsDown;
connectionsMade++;
}
}
}
private bool IsPathCell(MazeReworkCellType type)
{
return type == MazeReworkCellType.Corridor ||
type == MazeReworkCellType.Room ||
type == MazeReworkCellType.Start ||
type == MazeReworkCellType.End;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e30aa4eff6d79394ea1a19fe77e97b1e

View File

@@ -0,0 +1,171 @@
using System.Collections.Generic;
using UnityEngine;
namespace Baba_yaga.GameSetup.MazeRework
{
/// <summary>
/// Spawns the modular prefabs (U-Turn "U", turn "L", Hall "I", HallT "⊢", HallDoubleRoom "+")
/// based purely on neighbor connectivity. Wall cells spawn nothing.
/// </summary>
public class MazeReworkSpawner : MonoBehaviour
{
[Header("Modular Hallway Prefabs")]
[Tooltip("Prefab for Hall 'I' (Straight connection - opposite paths).")]
public GameObject hallPrefab;
[Tooltip("Prefab for HallDoubleRoom '+' (Crossroad connection - 4-way intersection).")]
public GameObject hallDoubleRoomPrefab;
[Tooltip("Prefab for HallT '⊢' (T-Junction connection - 3-way intersection).")]
public GameObject hallTPrefab;
[Tooltip("Prefab for turn 'L' (Corner connection - 2 adjacent paths).")]
public GameObject turnPrefab;
[Tooltip("Prefab for U-Turn 'U' (Dead end - 1 path).")]
public GameObject uTurnPrefab;
[Header("Rotation Offsets (Degrees)")]
[Tooltip("Rotation offset added to Hall 'I' prefab.")]
public float hallRotationOffset = 0f;
[Tooltip("Rotation offset added to HallDoubleRoom '+' prefab.")]
public float hallDoubleRoomRotationOffset = 0f;
[Tooltip("Rotation offset added to HallT '⊢' prefab.")]
public float hallTRotationOffset = 0f;
[Tooltip("Rotation offset added to turn 'L' prefab.")]
public float turnRotationOffset = 0f;
[Tooltip("Rotation offset added to U-Turn 'U' prefab.")]
public float uTurnRotationOffset = 0f;
[Header("Spacing Settings")]
[Tooltip("Physical distance between each grid cell center.")]
public float spacing = 3.0f;
private readonly List<GameObject> _spawnedObjects = new List<GameObject>();
private void Start()
{
ValidatePrefabs();
}
private void ValidatePrefabs()
{
if (hallPrefab == null || hallDoubleRoomPrefab == null || hallTPrefab == null || turnPrefab == null || uTurnPrefab == null)
{
Debug.LogWarning("<b>[MazeReworkSpawner]</b> One or more modular hallway prefabs are not assigned in the Inspector! Please assign your Hall, HallDoubleRoom, HallT, turn, and U-Turn prefabs.", this);
}
}
/// <summary>
/// Clears all spawned assets.
/// </summary>
public void Clear()
{
foreach (var obj in _spawnedObjects)
{
if (obj == null) continue;
if (Application.isPlaying)
Destroy(obj);
else
DestroyImmediate(obj);
}
_spawnedObjects.Clear();
}
/// <summary>
/// Spawns the modular prefabs based on the generated 2D grid array.
/// </summary>
public void Spawn(MazeReworkCellType[,] grid, float yOffset, Transform container)
{
if (grid == null) return;
ValidatePrefabs();
int width = grid.GetLength(0);
int depth = grid.GetLength(1);
for (int z = 0; z < depth; z++)
{
for (int x = 0; x < width; x++)
{
MazeReworkCellType type = grid[x, z];
// Wall cells spawn nothing
if (type == MazeReworkCellType.Wall)
{
continue;
}
// Evaluate connectivity of path cells to select and rotate the modular hallway prefab
(GameObject modularPrefab, float yRotation) = GetModularPrefabAndRotation(grid, x, z, width, depth);
if (modularPrefab != null)
{
SpawnPrefab(modularPrefab, x, yOffset, z, yRotation, container, $"{type}");
}
}
}
}
private void SpawnPrefab(GameObject prefab, int x, float y, int z, float yRotation, Transform container, string namePrefix)
{
Vector3 localPosition = new Vector3(x * spacing, y, z * spacing);
GameObject spawnedObj = Instantiate(prefab, container != null ? container : transform);
spawnedObj.transform.localPosition = localPosition;
spawnedObj.transform.localRotation = Quaternion.Euler(0f, yRotation, 0f);
spawnedObj.name = $"{namePrefix}_{x}_{z}";
_spawnedObjects.Add(spawnedObj);
}
private (GameObject, float) GetModularPrefabAndRotation(MazeReworkCellType[,] grid, int x, int z, int width, int depth)
{
bool top = IsPath(grid, x, z + 1, width, depth);
bool right = IsPath(grid, x + 1, z, width, depth);
bool bottom = IsPath(grid, x, z - 1, width, depth);
bool left = IsPath(grid, x - 1, z, width, depth);
int mask = 0;
if (top) mask += 1;
if (right) mask += 2;
if (bottom) mask += 4;
if (left) mask += 8;
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
// --- 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
// --- 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
// --- 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)
// --- 4 open connections: HallDoubleRoom "+" ---
case 15: return (hallDoubleRoomPrefab, 0f + hallDoubleRoomRotationOffset); // Open in all 4 directions
// Fallback for isolated cells (0 connections)
default: return (uTurnPrefab, 0f + uTurnRotationOffset);
}
}
private bool IsPath(MazeReworkCellType[,] grid, int x, int z, int width, int depth)
{
if (x < 0 || x >= width || z < 0 || z >= depth) return false;
MazeReworkCellType type = grid[x, z];
return type == MazeReworkCellType.Corridor ||
type == MazeReworkCellType.Room ||
type == MazeReworkCellType.Start ||
type == MazeReworkCellType.End ||
type == MazeReworkCellType.StairsUp ||
type == MazeReworkCellType.StairsDown;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8d9d9bca23a6e664fa3f01d404f31beb