diff --git a/Assets/_Project/Scripts/LevelGenerating/RoomType.cs b/Assets/_Project/Scripts/LevelGenerating/RoomType.cs index fc851aa..1638d42 100644 --- a/Assets/_Project/Scripts/LevelGenerating/RoomType.cs +++ b/Assets/_Project/Scripts/LevelGenerating/RoomType.cs @@ -4,6 +4,7 @@ namespace _Project.Scripts.LevelGenerating { Start, Corridor, + Undefined, Lift, Laboratory, Boss, diff --git a/Assets/_Project/Scripts/LevelGenerating/WallsGenerator.cs b/Assets/_Project/Scripts/LevelGenerating/WallsGenerator.cs index bb2774a..4ed12c6 100644 --- a/Assets/_Project/Scripts/LevelGenerating/WallsGenerator.cs +++ b/Assets/_Project/Scripts/LevelGenerating/WallsGenerator.cs @@ -122,27 +122,133 @@ namespace _Project.Scripts.LevelGenerating void TryPlaceRoom(Room corridor) { - - // Room lastCorridor = LevelManager.Instance.GetLastRoom(); - if (corridor != null && corridor.exits.Count == 1) - { - switch (corridor.exits.Last()) - { - case ExitsInRoomType.XAxisP: - { - if ((lengthFloor - (corridor.Position.x + corridorLength + lengthWallMin) > 0) - && (lengthFloor - (corridor.Position.y + corridorWigth + lengthWallMin) > 0)) - { - Room newRoom = GenerateRandomRoom(); - if() - } - - break; - } + // Базовая защита: если коридора нет или у него нет направления выхода + if (corridor == null || corridor.exits.Count == 0) return; + ExitsInRoomType corridorDirection = corridor.exits.Last(); + + // Создаем новую комнату со случайными размерами + Room newRoom = GenerateRandomRoom(); + newRoom.rt = RoomType.Undefined; + + Vector2 roomPos = Vector2.zero; + EntranceToRoomType entrance = EntranceToRoomType.Null; + + // 1. Стыкуем вход новой комнаты с выходом из коридора + switch (corridorDirection) + { + case ExitsInRoomType.XAxisP: // Коридор шел вправо (+X) + roomPos = new Vector2( + corridor.Position.x + corridor.Length, + corridor.Position.y + (corridor.Wigth - newRoom.Wigth) / 2f + ); + entrance = EntranceToRoomType.XAxisN; // Вход в комнату с левой стены (-X) + break; + + case ExitsInRoomType.XAxisN: // Коридор шел влево (-X) + roomPos = new Vector2( + corridor.Position.x - newRoom.Length, + corridor.Position.y + (corridor.Wigth - newRoom.Wigth) / 2f + ); + entrance = EntranceToRoomType.XAxisP; // Вход с правой стены (+X) + break; + + case ExitsInRoomType.ZAxisP: // Коридор шел вверх (+Z) + roomPos = new Vector2( + corridor.Position.x + (corridor.Length - newRoom.Length) / 2f, + corridor.Position.y + corridor.Wigth + ); + entrance = EntranceToRoomType.ZAxisN; // Вход с нижней стены (-Z) + break; + + case ExitsInRoomType.ZAxisN: // Коридор шел вниз (-Z) + roomPos = new Vector2( + corridor.Position.x + (corridor.Length - newRoom.Length) / 2f, + corridor.Position.y - newRoom.Wigth + ); + entrance = EntranceToRoomType.ZAxisP; // Вход с верхней стены (+Z) + break; + } + + // 2. Проверяем: влезает ли комната в границы и не накладывается ли на другие комнаты/коридоры + if (!IsAreaClear(roomPos, newRoom.Length, newRoom.Wigth)) + { + // Не влезла — эта ветка лабиринта затухает сама + return; + } + + // Если всё чисто, сохраняем параметры и добавляем в список + newRoom.Position = roomPos; + newRoom.entrance = entrance; + LevelManager.Rooms.Add(newRoom); + + // Визуализация новой комнаты (маркеры по углам) + Instantiate(GameObjectB, new Vector3(newRoom.Position.x, 0, newRoom.Position.y), Quaternion.identity); + Instantiate(GameObjectB, new Vector3(newRoom.Position.x + newRoom.Length, 0, newRoom.Position.y), Quaternion.identity); + Instantiate(GameObjectB, new Vector3(newRoom.Position.x + newRoom.Length, 0, newRoom.Position.y + newRoom.Wigth), Quaternion.identity); + Instantiate(GameObjectB, new Vector3(newRoom.Position.x, 0, newRoom.Position.y + newRoom.Wigth), Quaternion.identity); + + // 3. РЕКУРСИЯ: получаем 3 свободные стены (все кроме той, где вход) + List availableSides = GetThreeAvailableSides(entrance); + + // Перемешиваем стороны, чтобы ветвление шло в случайном порядке + availableSides = availableSides.OrderBy(x => Random.value).ToList(); + + foreach (var exitSide in availableSides) + { + // Шанс ветвления 65%: чтобы этаж не забивался сплошным ковром комнат, + // а оставались тупики и коридорные развилки + if (Random.value < 0.65f) + { + // Пытаемся построить коридор в эту сторону + Room nextCorridor = CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Wigth, exitSide); + + if (nextCorridor != null) + { + // Рекурсивный шаг: пытаемся пристроить комнату к концу нового коридора + TryPlaceRoom(nextCorridor); + } + } + } + } + + // Вспомогательный метод 1: возвращает 3 стены, исключая стену входа + List GetThreeAvailableSides(EntranceToRoomType entrance) + { + List sides = new List(); + + if (entrance != EntranceToRoomType.XAxisN) sides.Add(ExitsInRoomType.XAxisN); + if (entrance != EntranceToRoomType.XAxisP) sides.Add(ExitsInRoomType.XAxisP); + if (entrance != EntranceToRoomType.ZAxisN) sides.Add(ExitsInRoomType.ZAxisN); + if (entrance != EntranceToRoomType.ZAxisP) sides.Add(ExitsInRoomType.ZAxisP); + + return sides; + } + + // Вспомогательный метод 2: проверка на границы этажа и пересечение с существующими объектами + bool IsAreaClear(Vector2 pos, int length, int wigth) + { + // Проверка границ этажа [0 .. lengthFloor] + if (pos.x < 0 || pos.y < 0 || + pos.x + length > lengthFloor || + pos.y + wigth > lengthFloor) + { + return false; + } + + Rect newRect = new Rect(pos.x, pos.y, length, wigth); + + // Проверка наложения на все уже созданные комнаты и коридоры + foreach (var existing in LevelManager.Rooms) + { + Rect existingRect = new Rect(existing.Position.x, existing.Position.y, existing.Length, existing.Wigth); + if (newRect.Overlaps(existingRect)) + { + return false; } } + return true; } Room GenerateRandomRoom() {