From ba83e64b8d966320858592b4297f8d48412f1b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20P=C4=9Bnkava?= Date: Mon, 30 Jun 2025 16:28:30 +0200 Subject: [PATCH] room Gen, doors --- .../Prefabs/Corridors/Corridor_Door.prefab | 4 + .../Assets/Prefabs/Scripts/DoorController.cs | 5 + .../Assets/Prefabs/Scripts/RoomHandler.cs | 31 ++ .../Assets/Scripts/MapGen/MapGenManager.cs | 310 +++++++++--------- 4 files changed, 188 insertions(+), 162 deletions(-) diff --git a/3D blobici/Assets/Prefabs/Corridors/Corridor_Door.prefab b/3D blobici/Assets/Prefabs/Corridors/Corridor_Door.prefab index 0dee6d5..b689f9b 100644 --- a/3D blobici/Assets/Prefabs/Corridors/Corridor_Door.prefab +++ b/3D blobici/Assets/Prefabs/Corridors/Corridor_Door.prefab @@ -8,6 +8,10 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: -600122568662034771, guid: 1a5d554c0c76caf4195cae47e098b79d, type: 3} + propertyPath: prefabSize.x + value: 10 + objectReference: {fileID: 0} - target: {fileID: 3479177569595356638, guid: 1a5d554c0c76caf4195cae47e098b79d, type: 3} propertyPath: m_LocalPosition.x value: 20 diff --git a/3D blobici/Assets/Prefabs/Scripts/DoorController.cs b/3D blobici/Assets/Prefabs/Scripts/DoorController.cs index 466f65b..ee38a43 100644 --- a/3D blobici/Assets/Prefabs/Scripts/DoorController.cs +++ b/3D blobici/Assets/Prefabs/Scripts/DoorController.cs @@ -5,6 +5,11 @@ public class DoorController : MonoBehaviour [SerializeField] private Animator doorLAnimator; [SerializeField] private Animator doorRAnimator; + public void Start() + { + //OpenDoor(); + } + public void OpenDoor() { doorLAnimator.SetTrigger("Open"); diff --git a/3D blobici/Assets/Prefabs/Scripts/RoomHandler.cs b/3D blobici/Assets/Prefabs/Scripts/RoomHandler.cs index e44ef56..0888776 100644 --- a/3D blobici/Assets/Prefabs/Scripts/RoomHandler.cs +++ b/3D blobici/Assets/Prefabs/Scripts/RoomHandler.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using UnityEngine; /// @@ -6,11 +7,24 @@ using UnityEngine; /// public class RoomHandler : MonoBehaviour { + [Header("Doors")] [SerializeField] private GameObject wallNorth; [SerializeField] private GameObject wallSouth; [SerializeField] private GameObject wallEast; [SerializeField] private GameObject wallWest; + public enum Side + { + North, + South, + East, + West + } + + private readonly Dictionary doors = new(); + + public void RegisterDoor(Side dir, DoorAnimation doorAnim) => doors[dir] = doorAnim; + /// /// Creates entrances to corridors leading to other rooms /// @@ -25,4 +39,21 @@ public class RoomHandler : MonoBehaviour wallEast.SetActive(!eastOpen); wallWest.SetActive(!westOpen); } + + public void ToggleAllDoors() + { + foreach (DoorAnimation door in doors.Values) + { + door.ToggleDoor(); + } + } + + public void SetDoorState(Side dir, bool open) + { + if (doors.TryGetValue(dir, out DoorAnimation da)) + { + da.ToggleDoor(); + Debug.Log("Door " + dir + " is now " + (open ? "open" : "closed")); + } + } } diff --git a/3D blobici/Assets/Scripts/MapGen/MapGenManager.cs b/3D blobici/Assets/Scripts/MapGen/MapGenManager.cs index 3eea9eb..14ed977 100644 --- a/3D blobici/Assets/Scripts/MapGen/MapGenManager.cs +++ b/3D blobici/Assets/Scripts/MapGen/MapGenManager.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; -using UnityEngine; using System.Linq; -using System.Runtime.CompilerServices; +using UnityEngine; public class MapGenManager : MonoBehaviour { @@ -24,12 +23,9 @@ public class MapGenManager : MonoBehaviour [SerializeField] private int RoomDistance = 3; private readonly Dictionary gridToRoom = new(); - private readonly Vector3 roomOriginOffset = Vector3.zero; - void Start() => GenerateFromLayout(); - private void GenerateFromLayout() { if (layout == null || string.IsNullOrWhiteSpace(layout.grid)) @@ -37,228 +33,218 @@ public class MapGenManager : MonoBehaviour Debug.LogError("Layout asset není přiřazený nebo je prázdný!"); return; } - gridToRoom.Clear(); /* ----------- Create a spawn room ----------- */ GameObject spawnPrefab = mapPrefab[0]; Vector3 cellSize = GetPrefabXZ(spawnPrefab); - /* ---------- Text layout to grid ---------- */ - string[] lines = layout.grid - .Split('\n') - .Select(line => line.TrimEnd('\r')) - .Where(line => !string.IsNullOrWhiteSpace(line)) - .ToArray(); - - - Vector2 firstRoomPos = GetFirstOrLastRoom(lines); - int bottomRowIdx = (int)firstRoomPos.y; - int spawnGridX = (int)firstRoomPos.x; - - /* ---------- Create spawn room properly ---------- */ - Vector3 spawnPos = roomOriginOffset + new Vector3( - spawnGridX * (cellSize.x + RoomDistance), // X - 0, - 0); + string[] lines = layout.grid.Split('\n') + .Select(l => l.TrimEnd('\r')) + .Where(l => !string.IsNullOrWhiteSpace(l)) + .ToArray(); + Vector2 first = GetFirstOrLastRoom(lines); + int bottomRow = (int)first.y; + int spawnX = (int)first.x; + Vector3 spawnPos = new Vector3(spawnX * (cellSize.x + RoomDistance), 0, 0); GameObject spawnRoom = Instantiate(spawnPrefab, spawnPos, Quaternion.identity, transform); - gridToRoom[new Vector2Int(spawnGridX, 0)] = spawnRoom; + gridToRoom[new Vector2Int(spawnX, 0)] = spawnRoom; - /* ---------- Instantiate player ---------- */ + + /* ----------- Spawn the player ----------- */ if (Player) { - Vector3 playerPos = spawnPos + new Vector3(0, 1, 3); - GameObject playerInstance = Instantiate(Player, playerPos, Quaternion.identity, transform); - Transform controllerObj = playerInstance.transform.Find("Player"); - if (controllerObj != null) - { - controllerObj.tag = "Player"; - } - } - else - { - Debug.LogWarning("Player prefab není přiřazený, hráč nebude umístěn do mapy."); + GameObject p = Instantiate(Player, spawnPos + new Vector3(0, 1, 3), Quaternion.identity, transform); + Transform inner = p.transform.Find("Player"); + if (inner) inner.tag = "Player"; } - /* ---------- Build the rest of rooms ---------- */ + /* ----------- Build rooms ----------- */ + BuildRooms(lines, bottomRow, cellSize); - BuildRooms(lines, bottomRowIdx, cellSize); - - /* ---------- Open walls based on aproximity to other rooms ---------- */ - foreach (var keyValuePair in gridToRoom) + /* ----------- Set entrances ----------- */ + foreach (var kv in gridToRoom) { - Vector2Int g = keyValuePair.Key; - RoomHandler rh = keyValuePair.Value.GetComponent(); - + Vector2Int g = kv.Key; + RoomHandler rh = kv.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); + rh.SetEntrances(north, south, east, west); } - /* ---------- 5) CHODBY ---------- */ + /* ----------- Build corridors ----------- */ BuildCorridors(); + + + /* ----------- Toggle all doors ----------- */ + foreach (var keyValuePair in gridToRoom) + { + RoomHandler rh = keyValuePair.Value.GetComponent(); + rh.ToggleAllDoors(); + } } - /// - /// Build corridors between rooms - /// - /// + /* ============================================================ */ + /* CORRIDORS */ + /* ============================================================ */ private void BuildCorridors() { - float straightZ = CorridorStraight.GetComponent().prefabSize.y; - float straightX = CorridorStraight.GetComponent().prefabSize.x; - Vector2Int[] stepDirs = { Vector2Int.right, Vector2Int.up }; + // Jediné dva směry, které musíme zkontrolovat z každé místnosti (right/up) + Vector2Int[] directions = { Vector2Int.right, Vector2Int.up }; + + // Délky prefebů – podél X a Z osy + float straightLenX = CorridorStraight.GetComponent().prefabSize.x; + float straightLenZ = CorridorStraight.GetComponent().prefabSize.y; + float doorLenX = DoorCorridor.GetComponent().prefabSize.x; + float doorLenZ = DoorCorridor.GetComponent().prefabSize.y; foreach (var kv in gridToRoom) { Vector2Int cell = kv.Key; GameObject roomA = kv.Value; - foreach (Vector2Int dir in stepDirs) + foreach (Vector2Int dir in directions) { Vector2Int nKey = cell + dir; - if (!gridToRoom.TryGetValue(nKey, out GameObject roomB)) continue; - - Vector3 axis, axisNeg; - float halfA, halfB; - Quaternion rot; + if (!gridToRoom.TryGetValue(nKey, out GameObject roomB)) continue; // žádná sousední místnost + // Geometrie pro daný směr + Vector3 axis; float lenStraight, lenDoor; Quaternion rot; if (dir == Vector2Int.right) { - axis = Vector3.right; axisNeg = Vector3.left; - halfA = GetPrefabXZ(roomA).x * 0.5f; - halfB = GetPrefabXZ(roomB).x * 0.5f; + axis = Vector3.right; + lenStraight = straightLenX; + lenDoor = doorLenX; rot = Quaternion.Euler(0, 90, 0); } - else + else // Vector2Int.up { - axis = Vector3.forward; axisNeg = Vector3.back; - halfA = GetPrefabXZ(roomA).z * 0.5f; - halfB = GetPrefabXZ(roomB).z * 0.5f; + axis = Vector3.forward; + lenStraight = straightLenZ; + lenDoor = doorLenZ; rot = Quaternion.identity; } - Vector3 start = roomA.transform.position + axis * halfA; - Vector3 end = roomB.transform.position + axisNeg * halfB; + // Pozice stěn (počítáme od středu místnosti k jejímu okraji) + float halfA = Vector3.Scale(GetPrefabXZ(roomA), axis).magnitude * 0.5f; + float halfB = Vector3.Scale(GetPrefabXZ(roomB), axis).magnitude * 0.5f; + Vector3 wallA = roomA.transform.position + axis * halfA; + Vector3 wallB = roomB.transform.position - axis * halfB; - CreateStraightCorridor(start, end, axis, rot, straightZ, straightX); + // DVEŘE – pivot dveří do středu úsečky mezi okraji stěn + Vector3 doorPos = (wallA + wallB) * 0.5f; + GameObject doorGO = Instantiate(DoorCorridor, doorPos, rot, transform); + DoorAnimation anim = doorGO.GetComponent(); + + // REGISTRACE do obou místností + RoomHandler rhA = roomA.GetComponent(); + RoomHandler rhB = roomB.GetComponent(); + if (dir == Vector2Int.right) + { + rhA.RegisterDoor(RoomHandler.Side.East, anim); + rhB.RegisterDoor(RoomHandler.Side.West, anim); + } + else + { + rhA.RegisterDoor(RoomHandler.Side.North, anim); + rhB.RegisterDoor(RoomHandler.Side.South, anim); + } + + // ROVNÉ SEGMENTY z obou stran dveří + Vector3 doorEdgeA = doorPos - axis * (lenDoor * 0.5f); + Vector3 doorEdgeB = doorPos + axis * (lenDoor * 0.5f); + + PlaceStraightSegments(doorEdgeA, wallA, -axis, rot, lenStraight); + PlaceStraightSegments(doorEdgeB, wallB, axis, rot, lenStraight); } } } - /// - /// Build all rooms based on the layout grid + /// Vyplní úsek mezi startEdge (hrana dveří nebo předchozího dílu) + /// a wallEdge (vnější hrana stěny místnosti) rovnými segmenty tak, + /// aby žádný segment nepřečníval do stěny. /// - /// - /// - /// + private void PlaceStraightSegments( + Vector3 startEdge, + Vector3 wallEdge, + Vector3 direction, // normalizovaný (+/- axis) + Quaternion rot, + float len) // délka STANDARDNÍHO rovného segmentu + { + const float EPS = 0.01f; // ≈1 cm tolerance + float dist = Vector3.Distance(startEdge, wallEdge); + if (dist < EPS) return; // nic netřeba + + int fullCount = Mathf.FloorToInt(dist / len); + float remainder = dist - fullCount * len; // 0 .. len + + // -------- 1) CELÉ segmenty -------- + Vector3 firstPivot = startEdge + direction * (len * 0.5f); // hrana sedí na startEdge + for (int i = 0; i < fullCount; i++) + { + Vector3 pos = firstPivot + direction * (i * len); + GameObject prefab = (i % 2 == 0) ? CorridorStraight : CorridorStraightUnlit; + Instantiate(prefab, pos, rot, transform); + } + + // -------- 2) POSLEDNÍ ZKRÁCENÝ segment (pokud je třeba) -------- + if (remainder > EPS) // zbylo něco > 1 cm + { + // pivot tak, aby přední hrana nepřesáhla wallEdge + Vector3 remPivot = wallEdge - direction * (remainder * 0.5f); + GameObject last = Instantiate(CorridorStraightUnlit, remPivot, rot, transform); + + // zmenšíme délku po místní ose Z (prefab je "dlouhý" po Z) + Vector3 sc = last.transform.localScale; + sc.z *= remainder / len; // poměr 0 .. 1 + last.transform.localScale = sc; + } + } + + /* ============================================================ */ + /* ROOMS */ + /* ============================================================ */ private void BuildRooms(string[] lines, int bottomRowIdx, Vector3 cellSize) { - int rows = lines.Length; - - for (int rowsIter = 0; rowsIter < rows; rowsIter++) + for (int r = 0; r < lines.Length; r++) { - string line = lines[rowsIter]; - int gridZ = bottomRowIdx - rowsIter + 1; - + string line = lines[r]; + int gridZ = bottomRowIdx - r + 1; for (int x = 0; x < line.Length; x++) { char ch = line[x]; - if (ch == '-') continue; - if (!char.IsDigit(ch)) - { - Debug.LogWarning($"Neznámý znak '{ch}' v layoutu – ignoruji."); - continue; - } - + if (ch == '-' || !char.IsDigit(ch)) continue; int idx = ch - '0'; - if (idx >= mapPrefab.Count) - { - Debug.LogWarning($"Index {idx} mimo rozsah mapPrefab!"); - continue; - } - - GameObject prefab = mapPrefab[idx]; - Vector3 worldPos = roomOriginOffset + new Vector3( - x * (cellSize.x + RoomDistance), - 0, - gridZ * (cellSize.z + RoomDistance)); - - GameObject room = Instantiate(prefab, worldPos, Quaternion.identity, transform); + if (idx >= mapPrefab.Count) continue; + Vector3 pos = new Vector3(x * (cellSize.x + RoomDistance), 0, gridZ * (cellSize.z + RoomDistance)); + GameObject room = Instantiate(mapPrefab[idx], pos, Quaternion.identity, transform); gridToRoom[new Vector2Int(x, gridZ)] = room; } } } - /// - /// Returns the (x, y) coordinates of the room with closest aproximity to spawn or the furthest aproximity to spawn - /// - /// - /// - /// Vector2(x, y) where x is the line index and y is the column index - private Vector2 GetFirstOrLastRoom(string[] lines, bool last = false) - { - int colIdx = -1; - int spawnGridX = 0; - - int rows = lines.Length; - - for (int rowsIter = rows - 1; rowsIter >= 0; rowsIter--) - { - string line = lines[rowsIter]; - for (int c = 0; c < line.Length; c++) - { - if (char.IsDigit(line[c])) - { - colIdx = rowsIter; - spawnGridX = c; - break; - } - } - if (colIdx != -1) break; - } - if (colIdx == -1) - { - Debug.LogError("Layout neobsahuje žádnou číslici (místnost)!"); - return Vector2.zero; - } - - return new Vector2(spawnGridX, colIdx); - } - - private void CreateStraightCorridor( - Vector3 start, Vector3 end, Vector3 axis, Quaternion rot, - float stepLenZ, float stepLenX) - { - float dist = Vector3.Distance(start, end); - float step = Mathf.Approximately(Mathf.Abs(axis.z), 1f) ? stepLenZ : stepLenX; - int count = Mathf.Max(1, Mathf.FloorToInt(dist / step)); - - Vector3 segPos = start + axis * (step * 0.5f); - var door = Instantiate(DoorCorridor, segPos, rot, transform); - door.GetComponent()?.ToggleDoor(); - - for (int i = 1; i < count; i++) - { - GameObject prefab = (i % 2 == 0) ? CorridorStraight : CorridorStraightUnlit; - segPos = start + axis * (i * step + step * 0.5f); - Instantiate(prefab, segPos, rot, transform); - } - } - - /// - /// Returns the size of a prefab room - /// - /// Choose a prefab from available ones - /// Size of the prefab as Vector3 + /* ============================================================ */ + /* HELPERS */ + /* ============================================================ */ private static Vector3 GetPrefabXZ(GameObject prefab) { var ps = prefab.GetComponent(); return ps ? new Vector3(ps.prefabSize.x, 0, ps.prefabSize.y) : new Vector3(10, 0, 10); } + + private Vector2 GetFirstOrLastRoom(string[] lines) + { + for (int r = lines.Length - 1; r >= 0; r--) + { + string l = lines[r]; + int c = l.ToCharArray().ToList().FindIndex(char.IsDigit); + if (c != -1) return new Vector2(c, r); + } + Debug.LogError("Layout neobsahuje žádnou číslici (místnost)!"); + return Vector2.zero; + } }