This commit is contained in:
2026-06-09 22:48:04 +07:00
parent 1c8544d383
commit 435fbccad5
5 changed files with 193 additions and 1 deletions

View File

@@ -0,0 +1,152 @@
using System.Collections;
using System.Collections.Generic;
using Hallucinate.GameSetup.Maze.Extensions;
using Hallucinate.GameSetup.Maze.Native;
using UnityEngine;
namespace Hallucinate.GameSetup.Maze
{
/// <summary>
/// Advanced generator that combines C++ Native Noise with a Recursive Backtracking algorithm.
/// Creates a hybrid layout of large rooms and chaotic corridors.
/// </summary>
public class NoiseRecursiveGenerator : IMazeAlgorithm
{
private readonly List<MapLocation> _directions = MapLocation.Directions;
private float[] _noiseMap;
private int _seed = 1337;
// Thresholds
private const float RoomThreshold = 0.5f;
private const float CorridorThreshold = -0.3f;
private const int DeadEndNeighbourThreshold = 2;
public void Generate(MazeGrid grid)
{
InitializeNoise(grid);
// Step 1: Pre-place rooms based on noise peaks
for (int z = 0; z < grid.Depth; z++)
{
for (int x = 0; x < grid.Width; x++)
{
float noise = GetNoiseAt(x, z, grid.Width);
if (noise > RoomThreshold)
{
grid.SetCell(x, z, MazeCellType.Corridor);
}
}
}
// Step 2: Run recursive carving in the "connectable" zones
// We start from a few points to ensure coverage
for (int i = 0; i < 5; i++)
{
int startX = Random.Range(1, grid.Width - 1);
int startZ = Random.Range(1, grid.Depth - 1);
GenerateRecursive(grid, startX, startZ);
}
}
public IEnumerator GenerateStepByStep(MazeGrid grid, float interval)
{
InitializeNoise(grid);
// Visual feedback for noise pre-placement
for (int z = 0; z < grid.Depth; z++)
{
for (int x = 0; x < grid.Width; x++)
{
float noise = GetNoiseAt(x, z, grid.Width);
if (noise > RoomThreshold)
{
grid.SetCell(x, z, MazeCellType.Processing);
}
}
if (z % 5 == 0) yield return null;
}
for (int z = 0; z < grid.Depth; z++)
{
for (int x = 0; x < grid.Width; x++)
{
if (grid.GetCell(x, z) == MazeCellType.Processing)
grid.SetCell(x, z, MazeCellType.Corridor);
}
}
yield return GenerateRecursiveStepByStep(grid, 5, 5, interval);
}
private void InitializeNoise(MazeGrid grid)
{
_noiseMap = new float[grid.Width * grid.Depth];
using (var provider = new NativeNoiseProvider(_seed, 0.05f))
{
if (provider.IsInitialized)
{
provider.FillBuffer(0, 0, grid.Width, grid.Depth, _noiseMap);
}
else
{
// Fallback to Unity Perlin
for (int z = 0; z < grid.Depth; z++)
{
for (int x = 0; x < grid.Width; x++)
{
_noiseMap[z * grid.Width + x] = Mathf.PerlinNoise(x * 0.1f, z * 0.1f) * 2f - 1f;
}
}
}
}
}
private float GetNoiseAt(int x, int z, int width)
{
if (_noiseMap == null) return 0f;
return _noiseMap[z * width + x];
}
private void GenerateRecursive(MazeGrid grid, int x, int z)
{
// Boundary and Noise check
if (!grid.IsInBounds(x, z)) return;
if (GetNoiseAt(x, z, grid.Width) < CorridorThreshold) return;
if (grid.GetCell(x, z) == MazeCellType.Corridor) return;
if (grid.CountSquareNeighbours(x, z, MazeCellType.Corridor) >= DeadEndNeighbourThreshold) return;
grid.SetCell(x, z, MazeCellType.Corridor);
List<MapLocation> shuffledDirs = new List<MapLocation>(_directions);
shuffledDirs.Shuffle();
foreach (var dir in shuffledDirs)
{
GenerateRecursive(grid, x + dir.x, z + dir.z);
}
}
private IEnumerator GenerateRecursiveStepByStep(MazeGrid grid, int x, int z, float interval)
{
if (!grid.IsInBounds(x, z)) yield break;
if (GetNoiseAt(x, z, grid.Width) < CorridorThreshold) yield break;
if (grid.GetCell(x, z) == MazeCellType.Corridor) yield break;
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<MapLocation> shuffledDirs = new List<MapLocation>(_directions);
shuffledDirs.Shuffle();
foreach (var dir in shuffledDirs)
{
yield return GenerateRecursiveStepByStep(grid, x + dir.x, z + dir.z, interval);
}
}
}
}