168 lines
5.6 KiB
C#
168 lines
5.6 KiB
C#
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
|
|
public class MapGenerator : MonoBehaviour
|
|
{
|
|
private static readonly Vector2Int[] directions = {
|
|
new Vector2Int(0, 1), // up
|
|
new Vector2Int(1, 0), // right
|
|
new Vector2Int(0, -1), // down
|
|
new Vector2Int(-1, 0), // left
|
|
};
|
|
|
|
public static void Generate(Tile[,] tiles, GameObject[] prefabs, int width, int height, int seed)
|
|
{
|
|
Random.InitState(seed);
|
|
Dictionary<(int, int), List<int>> connections = new();
|
|
|
|
// 1. Minimum spanning tree connection graph
|
|
var visited = new HashSet<(int, int)>();
|
|
var edges = new List<(int x, int y, int dir)>();
|
|
int startX = Random.Range(0, width);
|
|
int startY = Random.Range(0, height);
|
|
visited.Add((startX, startY));
|
|
AddEdges(startX, startY, visited, width, height, edges);
|
|
|
|
while (visited.Count < width * height && edges.Count > 0)
|
|
{
|
|
int idx = Random.Range(0, edges.Count);
|
|
var (x, y, dir) = edges[idx];
|
|
edges.RemoveAt(idx);
|
|
|
|
int nx = x + directions[dir].x;
|
|
int ny = y + directions[dir].y;
|
|
if (nx < 0 || nx >= width || ny < 0 || ny >= height || visited.Contains((nx, ny)))
|
|
continue;
|
|
|
|
visited.Add((nx, ny));
|
|
AddEdges(nx, ny, visited, width, height, edges);
|
|
AddConnection(connections, x, y, dir);
|
|
AddConnection(connections, nx, ny, (dir + 2) % 4); // Opposite direction
|
|
}
|
|
|
|
float offsetX = -((width - 1) / 2f);
|
|
float offsetY = ((height - 1) / 2f);
|
|
|
|
// 2. Create Tiles and save the solution
|
|
for (int x = 0; x < width; x++)
|
|
{
|
|
for (int y = 0; y < height; y++)
|
|
{
|
|
var dirList = connections.ContainsKey((x, y)) ? connections[(x, y)] : new List<int>();
|
|
string type = GetTileType(dirList);
|
|
int rotation = GetRotation(dirList, type);
|
|
|
|
GameObject prefab = FindPrefab(prefabs, type);
|
|
GameObject tileObj = GameObject.Instantiate(prefab);
|
|
tileObj.transform.position = new Vector2(offsetX + x, offsetY - y);
|
|
|
|
Tile tile = tileObj.GetComponent<Tile>();
|
|
tile.X = x;
|
|
tile.Y = y;
|
|
|
|
tile.baseConnections = GetBaseConnections(type);
|
|
tile.graphicRotationOffset = GetGraphicOffset(type);
|
|
|
|
tile.ApplyRotation(rotation);
|
|
tile.SolutionRotation = rotation;
|
|
|
|
tile.SetConnectionState(true); // Set as connected texture (green)
|
|
|
|
tiles[x, y] = tile;
|
|
}
|
|
}
|
|
|
|
// 3. Shuffle (random rotation)
|
|
foreach (var tile in tiles)
|
|
{
|
|
if (!tile.locked)
|
|
tile.RandomRotate();
|
|
|
|
tile.SetConnectionState(false); // Set as disconnected texture (black)
|
|
}
|
|
}
|
|
|
|
private static void AddEdges(int x, int y, HashSet<(int, int)> visited, int width, int height, List<(int, int, int)> edges)
|
|
{
|
|
for (int dir = 0; dir < 4; dir++)
|
|
{
|
|
int nx = x + directions[dir].x;
|
|
int ny = y + directions[dir].y;
|
|
if (nx >= 0 && nx < width && ny >= 0 && ny < height && !visited.Contains((nx, ny)))
|
|
edges.Add((x, y, dir));
|
|
}
|
|
}
|
|
|
|
private static void AddConnection(Dictionary<(int, int), List<int>> map, int x, int y, int dir)
|
|
{
|
|
var key = (x, y);
|
|
if (!map.ContainsKey(key))
|
|
map[key] = new List<int>();
|
|
map[key].Add(dir);
|
|
}
|
|
|
|
private static string GetTileType(List<int> dirs)
|
|
{
|
|
switch (dirs.Count)
|
|
{
|
|
case 1: return "Node";
|
|
case 2:
|
|
if ((dirs[0] + 2) % 4 == dirs[1]) return "Straight";
|
|
else return "Corner";
|
|
case 3: return "TriCorner";
|
|
case 4: return "Node";
|
|
default: return "Node";
|
|
}
|
|
}
|
|
|
|
private static int GetRotation(List<int> dirs, string type)
|
|
{
|
|
dirs.Sort();
|
|
switch (type)
|
|
{
|
|
case "Node":
|
|
return dirs.Count > 0 ? dirs[0] : 0;
|
|
case "Straight":
|
|
return dirs.Contains(0) && dirs.Contains(2) ? 0 : 1;
|
|
case "Corner":
|
|
if (dirs.Contains(0) && dirs.Contains(1)) return 0;
|
|
if (dirs.Contains(1) && dirs.Contains(2)) return 1;
|
|
if (dirs.Contains(2) && dirs.Contains(3)) return 2;
|
|
return 3;
|
|
case "TriCorner":
|
|
for (int i = 0; i < 4; i++)
|
|
if (!dirs.Contains(i)) return i;
|
|
return 0;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
private static GameObject FindPrefab(GameObject[] prefabs, string type)
|
|
{
|
|
foreach (var p in prefabs)
|
|
{
|
|
if (p.name.Contains(type))
|
|
return p;
|
|
}
|
|
Debug.LogError($"No prefab found for type: {type}");
|
|
return prefabs[0];
|
|
}
|
|
|
|
private static int[] GetBaseConnections(string type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case "Straight": return new int[] { 3, 1 }; // left and right
|
|
case "Corner": return new int[] { 3, 0 }; // left and up
|
|
case "TriCorner": return new int[] { 3, 0, 1 }; // left, up, and right
|
|
case "Node": return new int[] { 0 }; // up
|
|
default: return new int[0];
|
|
}
|
|
}
|
|
|
|
private static int GetGraphicOffset(string type)
|
|
{
|
|
return 0; // No offset needed as the texture direction is consistent
|
|
}
|
|
}
|