Level Generator
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using System.Linq;
|
||||
|
||||
@@ -6,8 +6,6 @@ public class MapGenManager : MonoBehaviour
|
||||
{
|
||||
[Header("Room Prefabs")]
|
||||
[SerializeField] private List<GameObject> mapPrefab = new List<GameObject>();
|
||||
[SerializeField] private GameObject StartPoint;
|
||||
[SerializeField] private GameObject EndPoint;
|
||||
|
||||
[Header("Player")]
|
||||
[SerializeField] private GameObject Player;
|
||||
@@ -16,149 +14,190 @@ public class MapGenManager : MonoBehaviour
|
||||
[SerializeField] private GameObject CorridorStraight;
|
||||
[SerializeField] private GameObject CorridorStraightUnlit;
|
||||
[SerializeField] private GameObject DoorCorridor;
|
||||
/*[SerializeField] private GameObject CorridorL;
|
||||
[SerializeField] private GameObject CorridorT;
|
||||
[SerializeField] private GameObject CorridorCross;
|
||||
[SerializeField] private GameObject CorridorEnd;*/
|
||||
|
||||
[Header("Layout")]
|
||||
[SerializeField] private MapLayout layout;
|
||||
|
||||
[Header("Generation Settings")]
|
||||
[SerializeField] private int RoomDistance = 3;
|
||||
[SerializeField] private int minRoomsNumber = 3;
|
||||
[SerializeField] private int maxRoomsNumber = 7;
|
||||
|
||||
private List<Vector3> roomPositions = new List<Vector3>();
|
||||
private List<GameObject> placedRooms = new List<GameObject>();
|
||||
private Dictionary<Vector2Int, GameObject> gridToRoom = new();
|
||||
|
||||
void Start()
|
||||
private readonly Vector3 roomOriginOffset = Vector3.zero;
|
||||
|
||||
void Start() => GenerateFromLayout();
|
||||
|
||||
private void GenerateFromLayout()
|
||||
{
|
||||
MapGen();
|
||||
}
|
||||
|
||||
private void MapGen()
|
||||
{
|
||||
// Clear previous rooms and positions
|
||||
roomPositions.Clear();
|
||||
placedRooms.Clear();
|
||||
|
||||
// Add Start Point
|
||||
Vector3 startPos = new Vector3(0, 0, 0);
|
||||
GameObject startPoint = Instantiate(StartPoint, startPos, Quaternion.identity, transform);
|
||||
roomPositions.Add(startPos);
|
||||
placedRooms.Add(startPoint);
|
||||
startPoint.GetComponent<CreateEntrances>().SetEntrances(false, false, true, false);
|
||||
|
||||
// Instantiate the player at the starting position
|
||||
GameObject player = Instantiate(Player, new Vector3(startPos.x, 1, startPos.z - 5), Quaternion.identity, transform);
|
||||
|
||||
// Generate a random number of rooms
|
||||
int roomCount = Random.Range(minRoomsNumber, maxRoomsNumber);
|
||||
|
||||
// Place Generate Rooms
|
||||
for (int i = 0; i < roomCount; i++)
|
||||
if (layout == null || string.IsNullOrWhiteSpace(layout.grid))
|
||||
{
|
||||
GameObject roomPrefab = mapPrefab[Random.Range(0, mapPrefab.Count)];
|
||||
Vector3 roomPos = GetGridPosition(roomPrefab);
|
||||
GameObject room = Instantiate(roomPrefab, roomPos, Quaternion.identity, transform);
|
||||
placedRooms.Add(room);
|
||||
roomPositions.Add(roomPos);
|
||||
room.GetComponent<CreateEntrances>().SetEntrances(false, false, true, true);
|
||||
Debug.LogError("Layout asset není přiřazený nebo je prázdný!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Add End Point
|
||||
GameObject endPoint = Instantiate(EndPoint, GetGridPosition(EndPoint), Quaternion.identity, transform);
|
||||
roomPositions.Add(endPoint.transform.position);
|
||||
placedRooms.Add(endPoint);
|
||||
endPoint.GetComponent<CreateEntrances>().SetEntrances(false, false, false, false);
|
||||
gridToRoom.Clear();
|
||||
|
||||
// Create corridors between rooms
|
||||
for (int i = 0; i < roomPositions.Count - 1; i++)
|
||||
/* ---------- 0) VYTVOŘÍME SPAWN-ROOM ---------- */
|
||||
GameObject spawnPrefab = mapPrefab[0];
|
||||
PrefabSize spawnSizeComp = spawnPrefab.GetComponent<PrefabSize>();
|
||||
Vector3 cellSize = spawnSizeComp != null
|
||||
? new Vector3(spawnSizeComp.prefabSize.x, 0, spawnSizeComp.prefabSize.y)
|
||||
: new Vector3(10, 0, 10); // fallback
|
||||
|
||||
Vector3 spawnPos = roomOriginOffset;
|
||||
GameObject spawnRoom = Instantiate(spawnPrefab, spawnPos, Quaternion.identity, transform);
|
||||
gridToRoom[new Vector2Int(0, 0)] = spawnRoom;
|
||||
|
||||
// hráče necháme na spawnu
|
||||
if (Player != null)
|
||||
{
|
||||
Vector3 startRoomPos = roomPositions[i];
|
||||
PrefabSize startRoom = placedRooms[i].GetComponent<PrefabSize>();
|
||||
Vector3 endRoomPos = roomPositions[i + 1];
|
||||
PrefabSize endRoom = placedRooms[i + 1].GetComponent<PrefabSize>();
|
||||
Vector3 firstCorridorPos = new Vector3(
|
||||
startRoomPos.x,
|
||||
startRoomPos.y,
|
||||
startRoomPos.z + startRoom.prefabSize.y / 2
|
||||
);
|
||||
Vector3 lastCorridorPos = new Vector3(
|
||||
endRoomPos.x,
|
||||
endRoomPos.y,
|
||||
endRoomPos.z - endRoom.prefabSize.y / 2
|
||||
);
|
||||
CreateCorridor(firstCorridorPos, lastCorridorPos);
|
||||
Vector3 playerPos = spawnPos + new Vector3(0, 1, 3);
|
||||
Instantiate(Player, playerPos, Quaternion.identity, transform);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 GetGridPosition(GameObject roomPrefab)
|
||||
{
|
||||
Vector3 lastRoomPos = roomPositions[roomPositions.Count - 1];
|
||||
PrefabSize lastRoom = placedRooms[placedRooms.Count - 1].GetComponent<PrefabSize>();
|
||||
PrefabSize roomSize = roomPrefab.GetComponent<PrefabSize>();
|
||||
/* ---------- 1) PARSOVÁNÍ LAYOUTU ---------- */
|
||||
string[] lines = layout.grid
|
||||
.Split('\n')
|
||||
.Select(l => l.TrimEnd('\r'))
|
||||
.Where(l => !string.IsNullOrEmpty(l))
|
||||
.ToArray();
|
||||
|
||||
Vector3 roomPos = new Vector3(
|
||||
lastRoomPos.x,
|
||||
lastRoomPos.y - 0.01f,
|
||||
lastRoomPos.z + lastRoom.prefabSize.y / 2f + roomSize.prefabSize.y / 2f + RoomDistance
|
||||
);
|
||||
int rows = lines.Length;
|
||||
|
||||
return roomPos;
|
||||
}
|
||||
|
||||
private void CreateCorridor(Vector3 start, Vector3 end)
|
||||
{
|
||||
// Calculate the distance
|
||||
float distance = Vector3.Distance(start, end);
|
||||
PrefabSize corridorSize = CorridorStraight.GetComponent<PrefabSize>();
|
||||
PrefabSize corridorUnlitSize = CorridorStraightUnlit.GetComponent<PrefabSize>();
|
||||
PrefabSize doorSize = DoorCorridor.GetComponent<PrefabSize>();
|
||||
|
||||
// Calculate the number of corridors needed
|
||||
int corridorCount = Mathf.FloorToInt(distance / corridorSize.prefabSize.y);
|
||||
Debug.Log($"Creating {corridorCount} corridors from {start} to {end}");
|
||||
|
||||
// Create corridors
|
||||
//Start with door
|
||||
if (corridorCount > 0)
|
||||
/* ---------- 2) SMYČKA PŘES GRID ------------- */
|
||||
for (int z = 0; z < rows; z++)
|
||||
{
|
||||
Vector3 doorPos = new Vector3(
|
||||
start.x,
|
||||
start.y,
|
||||
start.z + doorSize.prefabSize.y * 0.5f
|
||||
);
|
||||
Quaternion doorRotation = Quaternion.Euler(0, 0, 0);
|
||||
GameObject doorCorridor = Instantiate(DoorCorridor, doorPos, doorRotation, transform);
|
||||
doorCorridor.GetComponent<DoorController>().OpenDoor();
|
||||
|
||||
|
||||
for (int i = 1; i < corridorCount; i++)
|
||||
string line = lines[rows - 1 - z]; // dolní řádek layoutu = nejnižší Z v textu
|
||||
for (int x = 0; x < line.Length; x++)
|
||||
{
|
||||
if (i % 2 != 0)
|
||||
char c = line[x];
|
||||
if (c == '-') continue; // prázdné místo
|
||||
|
||||
if (!char.IsDigit(c))
|
||||
{
|
||||
// Create straight corridor
|
||||
Vector3 pos = new Vector3(
|
||||
start.x,
|
||||
start.y,
|
||||
start.z + i * corridorSize.prefabSize.y + corridorSize.prefabSize.y * 0.5f
|
||||
);
|
||||
Quaternion rotation = Quaternion.Euler(0, 0, 0);
|
||||
GameObject corridor = Instantiate(CorridorStraight, pos, rotation, transform);
|
||||
Debug.LogWarning($"Neznámý znak {c} v layoutu – ignorováno.");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
int index = c - '0';
|
||||
if (index >= mapPrefab.Count)
|
||||
{
|
||||
// Create unlit corridor
|
||||
Vector3 pos = new Vector3(
|
||||
start.x,
|
||||
start.y,
|
||||
start.z + i * corridorUnlitSize.prefabSize.y + corridorUnlitSize.prefabSize.y * 0.5f
|
||||
);
|
||||
Quaternion rotation = Quaternion.Euler(0, 0, 0);
|
||||
GameObject corridorUnlit = Instantiate(CorridorStraightUnlit, pos, rotation, transform);
|
||||
Debug.LogWarning($"Index {index} mimo rozsah mapPrefab!");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
GameObject prefab = mapPrefab[index];
|
||||
|
||||
PrefabSize roomSize = prefab.GetComponent<PrefabSize>();
|
||||
Vector3 rCell = roomSize != null
|
||||
? new Vector3(roomSize.prefabSize.x, 0, roomSize.prefabSize.y)
|
||||
: cellSize; // použij spawn-size jako fallback
|
||||
|
||||
Vector3 worldPos = roomOriginOffset + new Vector3(
|
||||
x * (cellSize.x + RoomDistance),
|
||||
0,
|
||||
(z + 1) * (cellSize.z + RoomDistance));
|
||||
|
||||
GameObject room = Instantiate(prefab, worldPos, Quaternion.identity, transform);
|
||||
gridToRoom[new Vector2Int(x, z + 1)] = room;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 3) OTEVŘEME ZDI VŠEM MÍSTNOSTEM ---------- */
|
||||
foreach (var kvp in gridToRoom)
|
||||
{
|
||||
Vector2Int g = kvp.Key;
|
||||
RoomHandler rh = kvp.Value.GetComponent<RoomHandler>();
|
||||
|
||||
bool north = gridToRoom.ContainsKey(g + Vector2Int.left);
|
||||
bool south = gridToRoom.ContainsKey(g + Vector2Int.right);
|
||||
bool east = gridToRoom.ContainsKey(g + Vector2Int.up);
|
||||
bool west = gridToRoom.ContainsKey(g + Vector2Int.down);
|
||||
|
||||
rh.SetEntrances(northOpen: north,
|
||||
southOpen: south,
|
||||
eastOpen: east,
|
||||
westOpen: west);
|
||||
}
|
||||
|
||||
BuildCorridors();
|
||||
}
|
||||
|
||||
private void BuildCorridors()
|
||||
{
|
||||
// velikosti přímých dílů
|
||||
float straightLengthZ = CorridorStraight.GetComponent<PrefabSize>().prefabSize.y;
|
||||
float straightLengthX = CorridorStraight.GetComponent<PrefabSize>().prefabSize.x;
|
||||
|
||||
// Abychom každý pár řešili jen jednou, projdeme jen Right a Up souseda
|
||||
Vector2Int[] stepDirs = { Vector2Int.right, Vector2Int.up };
|
||||
|
||||
foreach (var kvp in gridToRoom)
|
||||
{
|
||||
Vector2Int cell = kvp.Key;
|
||||
GameObject roomA = kvp.Value;
|
||||
|
||||
foreach (Vector2Int dir in stepDirs)
|
||||
{
|
||||
Vector2Int neighKey = cell + dir;
|
||||
if (!gridToRoom.TryGetValue(neighKey, out GameObject roomB))
|
||||
continue; // není soused – žádná chodba
|
||||
|
||||
// 1) Urči směr v prostoru
|
||||
Vector3 axis, axisNeg; // +směr a −směr podél stejné osy
|
||||
float halfA, halfB; // půl šířky/hloubky pro start/end bod
|
||||
Quaternion corridorRot; // natočení pro koridor
|
||||
|
||||
if (dir == Vector2Int.right) // grid +X (svět +X)
|
||||
{
|
||||
axis = Vector3.right;
|
||||
axisNeg = Vector3.left;
|
||||
halfA = roomA.GetComponent<PrefabSize>().prefabSize.x * 0.5f;
|
||||
halfB = roomB.GetComponent<PrefabSize>().prefabSize.x * 0.5f;
|
||||
corridorRot = Quaternion.Euler(0, 90, 0); // koridor leží po X
|
||||
}
|
||||
else // dir == Vector2Int.up → svět +Z
|
||||
{
|
||||
axis = Vector3.forward;
|
||||
axisNeg = Vector3.back;
|
||||
halfA = roomA.GetComponent<PrefabSize>().prefabSize.y * 0.5f;
|
||||
halfB = roomB.GetComponent<PrefabSize>().prefabSize.y * 0.5f;
|
||||
corridorRot = Quaternion.identity; // prefab míří po +Z
|
||||
}
|
||||
|
||||
// 2) Vypočti start a end body (středy zdí)
|
||||
Vector3 startPos = roomA.transform.position + axis * halfA;
|
||||
Vector3 endPos = roomB.transform.position + axisNeg * halfB;
|
||||
|
||||
// 3) Vytvoř sekvenci dílů
|
||||
CreateStraightCorridor(startPos, endPos, axis, corridorRot,
|
||||
straightLengthZ, straightLengthX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Vytvoří přímý koridor od startu k endu podél 'axis'.
|
||||
private void CreateStraightCorridor(
|
||||
Vector3 start, Vector3 end, Vector3 axis, Quaternion rot,
|
||||
float stepLenZ, float stepLenX)
|
||||
{
|
||||
float fullDist = Vector3.Distance(start, end);
|
||||
float stepLen = Mathf.Approximately(Mathf.Abs(axis.z), 1f) ? stepLenZ : stepLenX;
|
||||
|
||||
int segmentCount = Mathf.Max(1, Mathf.FloorToInt(fullDist / stepLen));
|
||||
|
||||
// 0) dveřní díl
|
||||
Vector3 segPos = start + axis * (stepLen * 0.5f);
|
||||
GameObject door = Instantiate(DoorCorridor, segPos, rot, transform);
|
||||
door.GetComponent<DoorController>()?.OpenDoor(); // pokud existuje
|
||||
|
||||
// 1) zbytek – střídavě osvětlené / neosvětlené
|
||||
for (int i = 1; i < segmentCount; i++)
|
||||
{
|
||||
GameObject prefab = (i % 2 == 0) ? CorridorStraight : CorridorStraightUnlit;
|
||||
|
||||
segPos = start + axis * (i * stepLen + stepLen * 0.5f);
|
||||
Instantiate(prefab, segPos, rot, transform);
|
||||
}
|
||||
// If there is not enough space to create corridors, throw an exception
|
||||
else throw new System.Exception("Not enough space to create corridors");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user