using System; using System.Collections.Generic; using System.ComponentModel.Design.Serialization; using System.Linq; using UnityEngine; using Random = UnityEngine.Random; namespace _Project.Scripts.LevelGenerating { public class WallsGenerator : MonoBehaviour { [SerializeField] private int floorsCount; [SerializeField] private int lengthWallMin; [SerializeField] private int lengthWallMax; [SerializeField] private int lengthStartRoom; [SerializeField] private int lengthFloor; [SerializeField] private int corridorLength; [SerializeField] private int corridorWigth; [SerializeField] private GameObject GameObjectA; [SerializeField] private GameObject GameObjectB; private int RoomCount; private LevelManager levelManager; void Start() { levelManager = LevelManager.Instance; GenerateFloor(); } void GenerateFloor() { CreateStartRoom(); Instantiate(GameObjectA, new Vector3(0,-1,0), Quaternion.identity); foreach (var room in levelManager.GetRooms()) { float x = room.Position.x; float z = room.Position.y; // В Vector2 ось Y отвечает за Z в 3D пространстве Unity float length = room.Length; float width = room.Width; // 4 угла комнаты: // 1. Нижний левый (X, Z) Instantiate(GameObjectB, new Vector3(x, 0, z), Quaternion.identity); // 2. Нижний правый (X + Length, Z) Instantiate(GameObjectB, new Vector3(x + length, 0, z), Quaternion.identity); // 3. Верхний правый (X + Length, Z + Width) Instantiate(GameObjectB, new Vector3(x + length, 0, z + width), Quaternion.identity); // 4. Верхний левый (X, Z + Width) Instantiate(GameObjectB, new Vector3(x, 0, z + width), Quaternion.identity); } } Room CreateCorridor(Vector2 posRoom, int Length, int Wigth, ExitsInRoomType exitType) { Vector2 corridorPos = Vector2.zero; int cLength = 0; int cWidth = 0; EntranceToRoomType entranceToRoomType = EntranceToRoomType.Null; List exitsInRoomType = new List(); switch (exitType) { // Выход направо (+X) case ExitsInRoomType.XAxisP: // Начинается у правой стены комнаты (posRoom.x + Length) // Центрируем коридор по высоте/оси Z: смещаем на половину разницы ширин exitsInRoomType.Add (ExitsInRoomType.XAxisP); entranceToRoomType = EntranceToRoomType.XAxisN; corridorPos = new Vector2( posRoom.x + Length, posRoom.y + (Wigth - corridorWigth) / 2f ); cLength = corridorLength; cWidth = corridorWigth; break; // Выход налево (-X) case ExitsInRoomType.XAxisN: // Начинается слева от комнаты, отступая на длину коридора exitsInRoomType .Add (ExitsInRoomType.XAxisN); entranceToRoomType = EntranceToRoomType.XAxisP; corridorPos = new Vector2( posRoom.x - corridorLength, posRoom.y + (Wigth - corridorWigth) / 2f ); cLength = corridorLength; cWidth = corridorWigth; break; // Выход вперед/вверх (+Z / в Vector2 это Y) case ExitsInRoomType.ZAxisP: entranceToRoomType = EntranceToRoomType.ZAxisN; exitsInRoomType.Add (ExitsInRoomType.ZAxisP); // Начинается у верхней стены комнаты (posRoom.y + Wigth) // Центрируем коридор по горизонтали/оси X: corridorPos = new Vector2( posRoom.x + (Length - corridorWigth) / 2f, posRoom.y + Wigth ); // По оси X коридор узкий, по оси Z — длинный: cLength = corridorWigth; cWidth = corridorLength; break; // Выход назад/вниз (-Z / в Vector2 это Y) case ExitsInRoomType.ZAxisN: entranceToRoomType = EntranceToRoomType.ZAxisP; exitsInRoomType.Add (ExitsInRoomType.ZAxisN); // Начинается ниже комнаты, отступая на длину коридора corridorPos = new Vector2( posRoom.x + (Length - corridorWigth) / 2f, posRoom.y - corridorLength ); cLength = corridorWigth; cWidth = corridorLength; break; } // Создаем коридор как отдельную комнату Room corridor = new Room(corridorPos, cLength, cWidth, RoomType.Corridor,false, EntranceToRoomType.Null,exitsInRoomType); LevelManager.Rooms.Add(corridor); // // Визуализация коридора (расставляем маркеры по углам коридора для наглядности) // Instantiate(GameObjectB, new Vector3(corridorPos.x, 0, corridorPos.y), Quaternion.identity); // Instantiate(GameObjectB, new Vector3(corridorPos.x + cLength, 0, corridorPos.y), Quaternion.identity); // Instantiate(GameObjectB, new Vector3(corridorPos.x + cLength, 0, corridorPos.y + cWidth), Quaternion.identity); // Instantiate(GameObjectB, new Vector3(corridorPos.x, 0, corridorPos.y + cWidth), Quaternion.identity); return corridor; } void TryPlaceRoom(Room prevRoom,ExitsInRoomType exitForCor) { if (prevRoom == null || prevRoom.exits.Count == 0) return; // if (IsRoomCanFit(new Vector2(prevRoom.Position.x + prevRoom.Length, prevRoom.Position.y / 2), // exitForCor)) // { // Room newRoom = GenerateRandomRoom(); // newRoom.Position = new Vector2(); // newRoom.rt = RoomType.Undefined; // newRoom.entrance = EntranceToRoomType.XAxisP; // newRoom.exits = new List(); // if (IsRoomCanFit(new Vector2(prevRoom.Position.x + prevRoom.Length, prevRoom.Position.y / 2), // newRoom.Length, newRoom.Width, exitForCor)) // { // newRoom.isWallable = false; // levelManager.AddRoom(newRoom); // CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor); // } // else // { // newRoom.isWallable = true; // EditRoomFoFitting(newRoom); // levelManager.AddRoom(newRoom); // CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor); // } // } Room newRoom = GenerateRandomRoom(); newRoom.rt = RoomType.Undefined; newRoom.exits = new List(); Vector2 newRoomPos = Vector2.zero; // Вычисляем позицию новой комнаты и откуда в нее входит коридор switch (exitForCor) { // Если вышли направо, новая комната слева получает вход (-X) case ExitsInRoomType.XAxisP: newRoom.entrance = EntranceToRoomType.XAxisN; newRoomPos = new Vector2( prevRoom.Position.x + prevRoom.Length + corridorLength, // Сдвигаем на ширину пред. комнаты и коридор prevRoom.Position.y + (prevRoom.Width / 2f) - (newRoom.Width / 2f) // Центрируем по оси Y (Z) ); break; // Если вышли налево case ExitsInRoomType.XAxisN: newRoom.entrance = EntranceToRoomType.XAxisP; newRoomPos = new Vector2( prevRoom.Position.x - corridorLength - newRoom.Length, // Отступаем влево на коридор и ширину новой комнаты prevRoom.Position.y + (prevRoom.Width / 2f) - (newRoom.Width / 2f) ); break; // Если вышли вверх (+Z/Y) case ExitsInRoomType.ZAxisP: newRoom.entrance = EntranceToRoomType.ZAxisN; newRoomPos = new Vector2( prevRoom.Position.x + (prevRoom.Length / 2f) - (newRoom.Length / 2f), // Центрируем по оси X prevRoom.Position.y + prevRoom.Width + corridorLength ); break; // Если вышли вниз (-Z/Y) case ExitsInRoomType.ZAxisN: newRoom.entrance = EntranceToRoomType.ZAxisP; newRoomPos = new Vector2( prevRoom.Position.x + (prevRoom.Length / 2f) - (newRoom.Length / 2f), prevRoom.Position.y - corridorLength - newRoom.Width ); break; } // Устанавливаем просчитанную позицию newRoom.Position = newRoomPos; // Проверяем, помещается ли комната с ее реальными размерами if (IsRoomCanFit(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor)) { newRoom.isWallable = false; levelManager.AddRoom(newRoom); CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor); } else { newRoom.isWallable = true; EditRoomFoFitting(newRoom); // Подгоняем размеры под границы карты // Проверяем, вмещается ли хотя бы комната минимального размера после обрезки if (newRoom.Length >= lengthWallMin && newRoom.Width >= lengthWallMin) { levelManager.AddRoom(newRoom); CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Width, exitForCor); } else { // Места не хватило даже для минимальной комнаты. // Отменяем создание этой комнаты и завершаем ветку. // При необходимости здесь можно удалить сгенерированный к ней коридор. return; } } if (exitForCor != ExitsInRoomType.XAxisN) TryPlaceRoom(newRoom, ExitsInRoomType.XAxisP); // 2. Влево (-X): идем, только если TryPlaceRoomНЕ слеа (XAxisP) if (exitForCor != ExitsInRoomType.XAxisP) TryPlaceRoom(newRoom, ExitsInRoomType.XAxisN); // 3. Вверх/Вперед (+Z): идем, только TryPlaceRoomпришли НЕ верху (ZAxisN) if (exitForCor != ExitsInRoomType.ZAxisN) TryPlaceRoom(newRoom, ExitsInRoomType.ZAxisP); // 4. Вниз/Назад (-Z): идем, только если TryPlaceRoomишли НЕ сниу (ZAxisP) if (exitForCor != ExitsInRoomType.ZAxisP) TryPlaceRoom(newRoom, ExitsInRoomType.ZAxisN); } private void EditRoomFoFitting(Room room) { if (lengthFloor - room.Position.x + room.Length <= 0) { room.Length = lengthFloor - Convert.ToInt32(room.Position.x); } if (lengthFloor - room.Position.y + room.Width <= 0) { room.Width = lengthFloor - Convert.ToInt32(room.Position.y); } if (room.Position.x < 0) { room.Position.x = 0; } if (room.Position.y < 0) { room.Position.y = 0; } } private bool IsRoomCanFit(Vector2 vector2, ExitsInRoomType exitForCor) { switch (exitForCor) { case ExitsInRoomType.XAxisP: { if ((lengthFloor - (vector2.x + lengthWallMin) >= 0) && (lengthFloor - (vector2.y + lengthWallMin / 2f) >= 0) && (vector2.y - lengthWallMin/ 2f) >= 0) { return true; } return false; } case ExitsInRoomType.XAxisN: { if ((vector2.x - lengthWallMin >= 0) && (lengthFloor - (vector2.y + lengthWallMin / 2f) >= 0) && (vector2.y - lengthWallMin/ 2f) >= 0) { return true; } return false; } case ExitsInRoomType.ZAxisP: { if ((lengthFloor - (vector2.y + lengthWallMin) >= 0) && (lengthFloor - (vector2.x + lengthWallMin / 2f) >= 0) && (vector2.x - lengthWallMin/ 2f) >= 0) { return true; } return false; } case ExitsInRoomType.ZAxisN: { if ((vector2.y - lengthWallMin >= 0) && (lengthFloor - (vector2.x + lengthWallMin / 2f) >= 0) && (vector2.x - lengthWallMin/ 2f) >= 0) { return true; } return false; } case ExitsInRoomType.Null: default: return false; } } private bool IsRoomCanFit(Vector2 vector2,int lengthX,int lengthZ, ExitsInRoomType exitForCor) { switch (exitForCor) { case ExitsInRoomType.XAxisP: { if ((lengthFloor - (vector2.x + lengthX) >= 0) && (lengthFloor - (vector2.y + lengthZ / 2f) >= 0) && (vector2.y - lengthZ/2f) >= 0) { return true; } return false; } case ExitsInRoomType.XAxisN: { if ((vector2.x - lengthX >= 0) && (lengthFloor - (vector2.y + lengthZ / 2f) >= 0) && (vector2.y - lengthZ/2f) >= 0) { return true; } return false; } case ExitsInRoomType.ZAxisP: { if ((lengthFloor - (vector2.y + lengthZ) >= 0) && (lengthFloor - (vector2.x + lengthX / 2f) >= 0) && (vector2.x - lengthX/2f) >= 0) { return true; } return false; } case ExitsInRoomType.ZAxisN: { if ((vector2.y - lengthZ >= 0) && (lengthFloor - (vector2.x + lengthX / 2f) >= 0) && (vector2.x - lengthX/2) >= 0) { return true; } return false; } case ExitsInRoomType.Null: default: return false; } } Room GenerateRandomRoom() { int a = Random.Range(lengthWallMin, lengthWallMax); int b = Random.Range(lengthWallMin, lengthWallMax); Room room = new Room(); room.Length = a; room.Width = b; return room; } void CreateStartRoom() { float randValue = Random.value; int xR, zR; Vector2Int posStartRoom = new Vector2Int(); Room room = new Room( lengthStartRoom, lengthStartRoom, RoomType.Start); if (randValue < 0.25f) //1 квадрант { xR = Random.Range(0,lengthFloor/2-lengthStartRoom); if (xR + lengthStartRoom <= lengthFloor / 4) { room.exits.Add(ExitsInRoomType.XAxisP); zR = Random.Range(0, lengthFloor/2-lengthStartRoom); } else { room.exits.Add(ExitsInRoomType.ZAxisP); zR = Random.Range(0, lengthFloor/4-lengthStartRoom); } } else if (randValue < 0.5f) // 2 квадрант { xR = Random.Range(lengthFloor/2, lengthFloor-lengthStartRoom);//от половины до конца if (xR + lengthStartRoom <= lengthFloor * 3/4) { room.exits.Add(ExitsInRoomType.ZAxisP); zR = Random.Range(0, lengthFloor/4-lengthStartRoom); } else { room.exits.Add(ExitsInRoomType.XAxisN); zR = Random.Range(0, lengthFloor/2-lengthStartRoom); } } else if (randValue < 0.75f) { xR = Random.Range(lengthFloor / 2, lengthFloor - lengthStartRoom); if (xR + lengthStartRoom <= lengthFloor * 3 / 4) { room.exits.Add(ExitsInRoomType.ZAxisN); zR = Random.Range(lengthFloor * 3 / 4, lengthFloor - lengthStartRoom); } else { room.exits.Add(ExitsInRoomType.XAxisN); zR = Random.Range(lengthFloor / 2, lengthFloor - lengthStartRoom); } } else { xR = Random.Range(0, lengthFloor / 2 - lengthStartRoom); if (xR + lengthStartRoom <= lengthFloor / 4) { room.exits.Add(ExitsInRoomType.XAxisP); zR = Random.Range(lengthFloor / 2, lengthFloor - lengthStartRoom); } else { room.exits.Add(ExitsInRoomType.ZAxisN); zR = Random.Range(lengthFloor * 3 / 4, lengthFloor - lengthStartRoom); } } room.entrance = EntranceToRoomType.Null; LevelManager.Rooms.Add(room); // Instantiate(GameObjectA, new Vector3(0,-1,0), Quaternion.identity); // // Instantiate(GameObjectB, new Vector3(xR,0,zR), Quaternion.identity); // Instantiate(GameObjectB, new Vector3(xR+lengthStartRoom,0,zR), Quaternion.identity); // Instantiate(GameObjectB, new Vector3(xR+lengthStartRoom,0,zR+lengthStartRoom), Quaternion.identity); // Instantiate(GameObjectB, new Vector3(xR,0,zR+lengthStartRoom), Quaternion.identity); CreateCorridor(new Vector2Int(xR, zR),lengthStartRoom,lengthStartRoom,room.exits.First()); Room firstCorridor = CreateCorridor(new Vector2(xR, zR), lengthStartRoom, lengthStartRoom, room.exits.First()); if (firstCorridor != null) { TryPlaceRoom(room,room.exits.First()); } } } }