-добавил проверку на размер для сгенерированной комнаты

This commit is contained in:
vladislove 2026-10-02 16:19:34 +03:00
parent b4e619a93e
commit e84940b8fe
3 changed files with 134 additions and 115 deletions

View File

@ -10,7 +10,7 @@ namespace _Project.Scripts.LevelGenerating
public static List<Room> Rooms = new List<Room>();
[SerializeField] private readonly int curFloor;
public void AddRoom(ref Room room)
public void AddRoom(Room room)
{
Rooms.Add(room);
}

View File

@ -35,11 +35,23 @@ namespace _Project.Scripts.LevelGenerating
this.rt = rt;
}
public Room(Vector2 position, int wigth, int length, RoomType rt, bool isWallable, EntranceToRoomType entrance, List<ExitsInRoomType> exits)
{
Position = position;
Wigth = wigth;
Length = length;
this.rt = rt;
this.entrance = entrance;
this.isWallable = isWallable;
this.exits = exits;
}
public int Wigth { get; set; }
public int Length { get; set; }
public Vector2 Position;
public RoomType rt { get; set; }
public EntranceToRoomType entrance { get; set; }
public bool isWallable { get; set; }
public List<ExitsInRoomType> exits { get; set; }
}

View File

@ -120,135 +120,142 @@ namespace _Project.Scripts.LevelGenerating
return corridor;
}
void TryPlaceRoom(Room corridor)
void TryPlaceRoom(Room prevRoom,ExitsInRoomType exitForCor)
{
// Базовая защита: если коридора нет или у него нет направления выхода
if (corridor == null || corridor.exits.Count == 0) return;
if (prevRoom == null || prevRoom.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)
switch (exitForCor)
{
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<ExitsInRoomType> availableSides = GetThreeAvailableSides(entrance);
// Перемешиваем стороны, чтобы ветвление шло в случайном порядке
availableSides = availableSides.OrderBy(x => Random.value).ToList();
foreach (var exitSide in availableSides)
{
// Шанс ветвления 65%: чтобы этаж не забивался сплошным ковром комнат,
// а оставались тупики и коридорные развилки
if (Random.value < 0.65f)
case ExitsInRoomType.XAxisP:
{
// Пытаемся построить коридор в эту сторону
Room nextCorridor = CreateCorridor(newRoom.Position, newRoom.Length, newRoom.Wigth, exitSide);
if (nextCorridor != null)
if (IsRoomCanFit(new Vector2(prevRoom.Position.x + prevRoom.Length, prevRoom.Position.y / 2),
exitForCor))
{
// Рекурсивный шаг: пытаемся пристроить комнату к концу нового коридора
TryPlaceRoom(nextCorridor);
Room newRoom = GenerateRandomRoom();
newRoom.Position = new Vector2();
newRoom.rt = RoomType.Undefined;
newRoom.entrance = EntranceToRoomType.XAxisP;
newRoom.exits = new List<ExitsInRoomType>();
if (IsRoomCanFit(new Vector2(prevRoom.Position.x + prevRoom.Length, prevRoom.Position.y / 2),
newRoom.Length, newRoom.Wigth, exitForCor))
{
newRoom.isWallable = false;
levelManager.AddRoom(newRoom);
}
}
break;
}
}
}
// Вспомогательный метод 1: возвращает 3 стены, исключая стену входа
List<ExitsInRoomType> GetThreeAvailableSides(EntranceToRoomType entrance)
private bool IsRoomCanFit(Vector2 vector2, ExitsInRoomType exitForCor)
{
List<ExitsInRoomType> sides = new List<ExitsInRoomType>();
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)
switch (exitForCor)
{
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))
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 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()
{
@ -337,7 +344,7 @@ namespace _Project.Scripts.LevelGenerating
Room firstCorridor = CreateCorridor(new Vector2(xR, zR), lengthStartRoom, lengthStartRoom, room.exits.First());
if (firstCorridor != null)
{
TryPlaceRoom(firstCorridor);
TryPlaceRoom(room,room.exits.First());
}
}