using System.Collections.Generic; using UnityEngine; using System.Linq; public class MapGenManager : MonoBehaviour { [Header("Room Prefabs")] [SerializeField] private List mapPrefab = new List(); [Header("Player")] [SerializeField] private GameObject Player; [Header("Corridor Prefabs")] [SerializeField] private GameObject CorridorStraight; [SerializeField] private GameObject CorridorStraightUnlit; [SerializeField] private GameObject DoorCorridor; [Header("Layout")] [SerializeField] private MapLayout layout; [Header("Generation Settings")] [SerializeField] private int RoomDistance = 3; private Dictionary gridToRoom = new(); private readonly Vector3 roomOriginOffset = Vector3.zero; void Start() => GenerateFromLayout(); private void GenerateFromLayout() { if (layout == null || string.IsNullOrWhiteSpace(layout.grid)) { Debug.LogError("Layout asset není přiřazený nebo je prázdný!"); return; } gridToRoom.Clear(); /* ---------- 0) VYTVOŘÍME SPAWN-ROOM ---------- */ GameObject spawnPrefab = mapPrefab[0]; PrefabSize spawnSizeComp = spawnPrefab.GetComponent(); 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 playerPos = spawnPos + new Vector3(0, 1, 3); Instantiate(Player, playerPos, Quaternion.identity, transform); } /* ---------- 1) PARSOVÁNÍ LAYOUTU ---------- */ string[] lines = layout.grid .Split('\n') .Select(l => l.TrimEnd('\r')) .Where(l => !string.IsNullOrEmpty(l)) .ToArray(); int rows = lines.Length; /* ---------- 2) SMYČKA PŘES GRID ------------- */ for (int z = 0; z < rows; z++) { string line = lines[rows - 1 - z]; // dolní řádek layoutu = nejnižší Z v textu for (int x = 0; x < line.Length; x++) { char c = line[x]; if (c == '-') continue; // prázdné místo if (!char.IsDigit(c)) { Debug.LogWarning($"Neznámý znak {c} v layoutu – ignorováno."); continue; } int index = c - '0'; if (index >= mapPrefab.Count) { Debug.LogWarning($"Index {index} mimo rozsah mapPrefab!"); continue; } GameObject prefab = mapPrefab[index]; PrefabSize roomSize = prefab.GetComponent(); 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(); 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.y; float straightLengthX = CorridorStraight.GetComponent().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.x * 0.5f; halfB = roomB.GetComponent().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.y * 0.5f; halfB = roomB.GetComponent().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()?.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); } } }