Path Generator
unknown
plain_text
a year ago
14 kB
9
Indexable
using System.Collections.Generic;
using UnityEngine;
public class PathGenerator : MonoBehaviour
{
public int baseWidth = 10;
public int baseHeight = 10;
public GameObject wallPrefab;
public GameObject startPointPrefab;
public GameObject endPointPrefab;
public float complexity = 1f;
public GameObject secondaryPathPrefab;
public GameObject secondaryStartPointPrefab;
public GameObject secondaryEndPointPrefab;
public GameObject pathPrefab;
public GameObject waterPrefab;
public GameObject[] randomDecorations;
public int decorationRadiusFromEndPoints = 3;
public int pathSeparation = 4;
public int decorRatio = 10;
public int Prev = 25;
public int NumberOfSpawnPoints;
public int AddedGC;
public int currentWaterLayers;
private int level = 1;
private int width;
private int height;
private int[,] map;
private int visitedCells = 0;
private int secondaryVisitedCells = 0;
public Vector2Int startPoint;
public Vector2Int endPoint;
private Vector2Int secondaryStartPoint;
private Vector2Int secondaryEndPoint;
private const int MaxStackSize = 10000;
private HashSet<Vector2Int> instantiatedPathPositions;
private HashSet<Vector2Int> wallPositions;
private HashSet<Vector2Int> decoratedWallPositions;
private List<Vector2Int> secondaryPaths = new List<Vector2Int>();
public Vector2Int preStartPoint;
public Material[] sky;
public GameObject rain;
void Start()
{
width = baseWidth;
height = baseHeight;
GeneratePath();
DrawPath();
int ran = Random.Range(0, sky.Length);
if (ran == 8)
{
rain.SetActive(true);
}
else
{
rain.SetActive(false);
}
RenderSettings.skybox = sky[ran];
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
LevelUp();
}
}
public void LevelUp()
{
level++;
width = baseWidth + level - 1;
height = baseHeight + level - 1;
CleanupScene();
GeneratePath();
DrawPath();
if (level % 15 == 0 && secondaryPaths.Count < 4)
{
GenerateSecondaryPath();
}
GameObject[] spawnPoints = GameObject.FindGameObjectsWithTag("Spawns");
NumberOfSpawnPoints = spawnPoints.Length;
int ran = Random.Range(0, sky.Length);
if (ran == 8)
{
rain.SetActive(true);
}
else
{
rain.SetActive(false);
}
RenderSettings.skybox = sky[ran];
}
void GeneratePath()
{
InitializePath();
int totalBlocks = width * height;
int decorationBlocks = Mathf.FloorToInt(totalBlocks / decorRatio);
int minVertices = Mathf.FloorToInt((totalBlocks - decorationBlocks) / 2f);
if (level > 1)
{
minVertices = Prev;
}
else
{
minVertices = Mathf.FloorToInt((totalBlocks - decorationBlocks) / 2f);
}
int maxVertices = Mathf.FloorToInt(totalBlocks / 2f);
Prev = maxVertices;
GeneratePathStructure(minVertices, maxVertices);
}
void InitializePath()
{
map = new int[width * 2 + 1, height * 2 + 1];
visitedCells = 0;
secondaryVisitedCells = 0;
instantiatedPathPositions = new HashSet<Vector2Int>();
wallPositions = new HashSet<Vector2Int>();
decoratedWallPositions = new HashSet<Vector2Int>();
}
void GeneratePathStructure(int minVertices, int maxVertices)
{
Stack<Vector2Int> stack = new Stack<Vector2Int>();
List<Vector2Int> path = new List<Vector2Int>();
Vector2Int currentCell = new Vector2Int(1, 1);
map[currentCell.x, currentCell.y] = 1;
path.Add(currentCell);
visitedCells++;
int targetVertices = Random.Range(minVertices, maxVertices + 1);
while (visitedCells < targetVertices)
{
List<Vector2Int> neighbors = GetUnvisitedNeighbors(currentCell);
if (neighbors.Count > 0)
{
Vector2Int chosenNeighbor = neighbors[Random.Range(0, neighbors.Count)];
if (Random.value < complexity && stack.Count < MaxStackSize)
{
stack.Push(currentCell);
}
RemoveWall(currentCell, chosenNeighbor);
currentCell = chosenNeighbor;
map[currentCell.x, currentCell.y] = 1;
path.Add(currentCell);
visitedCells++;
instantiatedPathPositions.Add(currentCell);
}
else if (stack.Count > 0)
{
currentCell = stack.Pop();
}
else
{
break;
}
}
while (visitedCells < targetVertices)
{
List<Vector2Int> additionalNeighbors = GetUnvisitedNeighbors(currentCell);
if (additionalNeighbors.Count > 0)
{
Vector2Int chosenNeighbor = additionalNeighbors[Random.Range(0, additionalNeighbors.Count)];
RemoveWall(currentCell, chosenNeighbor);
currentCell = chosenNeighbor;
map[currentCell.x, currentCell.y] = 1;
path.Add(currentCell);
visitedCells++;
instantiatedPathPositions.Add(currentCell);
}
else
{
break;
}
}
if (path.Count >= 2)
{
preStartPoint = path[path.Count - 2];
startPoint = path[path.Count - 1];
}
else
{
preStartPoint = Vector2Int.zero;
startPoint = path[path.Count - 1];
}
endPoint = path[0];
}
void GenerateSecondaryPath()
{
Vector2Int newSecondaryStart = FindSuitableStartPoint();
if (newSecondaryStart != Vector2Int.zero)
{
CreateSecondaryPath(newSecondaryStart);
secondaryPaths.Add(newSecondaryStart);
}
}
Vector2Int FindSuitableStartPoint()
{
List<Vector2Int> possibleStartPoints = new List<Vector2Int>();
Vector2Int startPoint = new Vector2Int(Random.Range(2, width * 2 - 1), Random.Range(2, height * 2 - 1));
if (!secondaryPaths.Contains(startPoint) && map[startPoint.x, startPoint.y] == 0)
{
return startPoint;
}
return Vector2Int.zero;
}
void CreateSecondaryPath(Vector2Int start, int depth = 0)
{
const int MaxDepth = 500;
if (depth > MaxDepth)
{
return;
}
Vector2Int currentSecondaryCell = start;
List<Vector2Int> secondaryPath = new List<Vector2Int>();
secondaryPath.Add(currentSecondaryCell);
secondaryVisitedCells++;
while (true)
{
List<Vector2Int> secondaryNeighbors = GetUnvisitedNeighbors(currentSecondaryCell);
if (secondaryNeighbors.Count > 0)
{
Vector2Int chosenSecondaryNeighbor = secondaryNeighbors[Random.Range(0, secondaryNeighbors.Count)];
RemoveWall(currentSecondaryCell, chosenSecondaryNeighbor);
currentSecondaryCell = chosenSecondaryNeighbor;
map[currentSecondaryCell.x, currentSecondaryCell.y] = 1;
secondaryPath.Add(currentSecondaryCell);
secondaryVisitedCells++;
instantiatedPathPositions.Add(currentSecondaryCell);
if (secondaryPath.Count > 1 && !secondaryPath.Contains(endPoint))
{
secondaryEndPoint = secondaryPath[secondaryPath.Count - 1];
break;
}
}
else
{
break;
}
}
if (secondaryPath.Count <= 1)
{
CreateSecondaryPath(start, depth + 1);
}
else
{
secondaryStartPoint = secondaryPath[0];
}
}
List<Vector2Int> GetUnvisitedNeighbors(Vector2Int cell)
{
List<Vector2Int> neighbors = new List<Vector2Int>();
if (cell.x > 1 && map[cell.x - 2, cell.y] == 0) neighbors.Add(new Vector2Int(cell.x - 2, cell.y));
if (cell.x < width * 2 - 1 && map[cell.x + 2, cell.y] == 0) neighbors.Add(new Vector2Int(cell.x + 2, cell.y));
if (cell.y > 1 && map[cell.x, cell.y - 2] == 0) neighbors.Add(new Vector2Int(cell.x, cell.y - 2));
if (cell.y < height * 2 - 1 && map[cell.x, cell.y + 2] == 0) neighbors.Add(new Vector2Int(cell.x, cell.y + 2));
return neighbors;
}
void RemoveWall(Vector2Int current, Vector2Int neighbor)
{
Vector2Int wallPosition = current + (neighbor - current) / 2;
map[wallPosition.x, wallPosition.y] = 1;
instantiatedPathPositions.Add(wallPosition);
}
void DrawPath()
{
HashSet<Vector2Int> instantiatedPositions = new HashSet<Vector2Int>();
for (int x = 0; x < width * 2 + 1; x++)
{
for (int y = 0; y < height * 2 + 1; y++)
{
Vector2Int position = new Vector2Int(x, y);
if (map[x, y] == 0)
{
Instantiate(wallPrefab, new Vector3(x, 0, y), Quaternion.identity, transform);
wallPositions.Add(position);
}
else if (instantiatedPositions.Add(position))
{
Instantiate(pathPrefab, new Vector3(x, 0, y), Quaternion.identity, transform);
}
}
}
List<Vector2Int> decorationCandidates = new List<Vector2Int>(wallPositions);
decorationCandidates.RemoveAll(pos =>
Vector2Int.Distance(pos, startPoint) <= decorationRadiusFromEndPoints ||
Vector2Int.Distance(pos, endPoint) <= decorationRadiusFromEndPoints ||
Vector2Int.Distance(pos, secondaryStartPoint) <= decorationRadiusFromEndPoints ||
Vector2Int.Distance(pos, secondaryEndPoint) <= decorationRadiusFromEndPoints);
int numDecorations = Mathf.Min(decorationCandidates.Count, Mathf.FloorToInt((width * height) / decorRatio));
for (int i = 0; i < numDecorations; i++)
{
Vector2Int decorationPosition = decorationCandidates[Random.Range(0, decorationCandidates.Count)];
Instantiate(randomDecorations[Random.Range(0, randomDecorations.Length)], new Vector3(decorationPosition.x, 0, decorationPosition.y), Quaternion.identity, transform);
decorationCandidates.Remove(decorationPosition);
}
Instantiate(startPointPrefab, new Vector3(startPoint.x, 0, startPoint.y), Quaternion.identity, transform);
Vector2Int[] directions = { Vector2Int.up, Vector2Int.down, Vector2Int.left, Vector2Int.right };
Vector2Int? adjacentPathBlock = null;
foreach (Vector2Int direction in directions)
{
Vector2Int adjacentPosition = endPoint + direction;
if (map[adjacentPosition.x, adjacentPosition.y] == 1)
{
adjacentPathBlock = adjacentPosition;
break;
}
}
if (adjacentPathBlock.HasValue)
{
Vector3 directionToPathBlock = new Vector3(adjacentPathBlock.Value.x - endPoint.x, 0, adjacentPathBlock.Value.y - endPoint.y);
Quaternion rotationToFacePathBlock = Quaternion.LookRotation(directionToPathBlock);
float yRotation = rotationToFacePathBlock.eulerAngles.y;
float snappedYRotation = Mathf.Round(yRotation / 90f) * 90f;
GameObject endPointObject = Instantiate(endPointPrefab, new Vector3(endPoint.x, 0, endPoint.y), Quaternion.identity, transform);
endPointObject.transform.rotation = Quaternion.Euler(0, snappedYRotation, 0);
}
else
{
Instantiate(endPointPrefab, new Vector3(endPoint.x, 0, endPoint.y), Quaternion.identity, transform);
}
if (secondaryStartPoint != Vector2Int.zero && secondaryEndPoint != Vector2Int.zero)
{
Instantiate(secondaryEndPointPrefab, new Vector3(secondaryEndPoint.x, 0, secondaryEndPoint.y), Quaternion.identity, transform);
}
currentWaterLayers = 1 + (level - 1) / 10;
DrawWaterLayers(currentWaterLayers);
}
void DrawWaterLayers(int layers)
{
int mapWidth = width * 2 + 1;
int mapHeight = height * 2 + 1;
for (int layer = 0; layer < layers; layer++)
{
for (int x = -1 - layer; x <= mapWidth + layer; x++)
{
for (int y = -1 - layer; y <= mapHeight + layer; y++)
{
if (x == -1 - layer || x == mapWidth + layer || y == -1 - layer || y == mapHeight + layer)
{
Vector3 waterPosition = new Vector3(x, 0, y);
Instantiate(waterPrefab, waterPosition, Quaternion.identity, transform);
}
}
}
}
}
void CleanupScene()
{
foreach (Transform child in transform)
{
Destroy(child.gameObject);
}
instantiatedPathPositions.Clear();
wallPositions.Clear();
decoratedWallPositions.Clear();
}
}
Editor is loading...