using System.Collections.Generic; using UnityEngine; namespace _Project.Scripts.LevelGenerating { public enum SegmentKind { Wall, Corner } // Куда смотрит видимая сторона сегмента (внутрь комнаты или коридора). // Для Corner - какой это угол комнаты (SW = минимальные X и Z). public enum SegmentFacing { XP, XN, ZP, ZN, CornerSW, CornerSE, CornerNW, CornerNE } // Один сегмент стены = одна клетка (1 модуль = 0.5 м) по периметру. // Поля публичные, чтобы потом можно было сохранять в файл. [System.Serializable] public struct WallSegment { public Vector2Int Cell; public SegmentKind Kind; public SegmentFacing Facing; public WallSegment(Vector2Int cell, SegmentKind kind, SegmentFacing facing) { Cell = cell; Kind = kind; Facing = facing; } } // ===================================================================== // Строит сегменты стен из FloorData. Спавна здесь нет, только данные. // // Правила: // - Стены стоят ВНУТРИ прямоугольника комнаты: это внешнее кольцо клеток шириной 1 модуль. // - У коридора стены только по двум длинным сторонам, торцы открыты. // - Проём в стене комнаты равен ВНУТРЕННЕЙ ширине коридора (ширина коридора минус 2 клетки, // то есть минус по 0.5 м стены с каждой стороны). Иначе проём был бы шире прохода. // - Стык стены коридора со стеной комнаты - Т-образный, угловой элемент там не ставится. // // НЕ ЗАБЫТЬ: ширина коридора должна быть минимум 3 клетки, иначе проёма не будет. // ===================================================================== public static class ShellBuilder { public static void Build(FloorData floor) { floor.Walls.Clear(); var doors = CollectDoorCells(floor); foreach (var r in floor.Rooms) { if (r.rt == RoomType.Corridor) AddCorridorWalls(floor, r); else AddRoomWalls(floor, r, doors); } } // Коридор идёт вдоль X, если его выход по оси X (запасной вариант: длинная сторона) private static bool IsAlongX(Room c) { if (c.exits != null && c.exits.Count > 0) return c.exits[0] == ExitsInRoomType.XAxisP || c.exits[0] == ExitsInRoomType.XAxisN; return c.Length >= c.Width; } // Клетки стен комнат, которые нужно убрать под проёмы коридоров private static HashSet CollectDoorCells(FloorData floor) { var set = new HashSet(); foreach (var c in floor.Corridors) { int x0 = c.Position.x, z0 = c.Position.y; if (IsAlongX(c)) { // слева стена комнаты в колонке x0 - 1, справа в колонке x0 + Length for (int z = z0 + 1; z < z0 + c.Width - 1; z++) { set.Add(new Vector2Int(x0 - 1, z)); set.Add(new Vector2Int(x0 + c.Length, z)); } } else { // снизу стена комнаты в ряду z0 - 1, сверху в ряду z0 + Width for (int x = x0 + 1; x < x0 + c.Length - 1; x++) { set.Add(new Vector2Int(x, z0 - 1)); set.Add(new Vector2Int(x, z0 + c.Width)); } } } return set; } private static void AddRoomWalls(FloorData floor, Room r, HashSet doors) { int x0 = r.Position.x, z0 = r.Position.y; int x1 = x0 + r.Length - 1, z1 = z0 + r.Width - 1; // углы Add(floor, new Vector2Int(x0, z0), SegmentKind.Corner, SegmentFacing.CornerSW); Add(floor, new Vector2Int(x1, z0), SegmentKind.Corner, SegmentFacing.CornerSE); Add(floor, new Vector2Int(x0, z1), SegmentKind.Corner, SegmentFacing.CornerNW); Add(floor, new Vector2Int(x1, z1), SegmentKind.Corner, SegmentFacing.CornerNE); // нижняя и верхняя стены (идут вдоль X) for (int x = x0 + 1; x < x1; x++) { AddWall(floor, new Vector2Int(x, z0), SegmentFacing.ZP, doors); AddWall(floor, new Vector2Int(x, z1), SegmentFacing.ZN, doors); } // левая и правая стены (идут вдоль Z) for (int z = z0 + 1; z < z1; z++) { AddWall(floor, new Vector2Int(x0, z), SegmentFacing.XP, doors); AddWall(floor, new Vector2Int(x1, z), SegmentFacing.XN, doors); } } private static void AddCorridorWalls(FloorData floor, Room c) { int x0 = c.Position.x, z0 = c.Position.y; if (IsAlongX(c)) { for (int x = x0; x < x0 + c.Length; x++) { Add(floor, new Vector2Int(x, z0), SegmentKind.Wall, SegmentFacing.ZP); Add(floor, new Vector2Int(x, z0 + c.Width - 1), SegmentKind.Wall, SegmentFacing.ZN); } } else { for (int z = z0; z < z0 + c.Width; z++) { Add(floor, new Vector2Int(x0, z), SegmentKind.Wall, SegmentFacing.XP); Add(floor, new Vector2Int(x0 + c.Length - 1, z), SegmentKind.Wall, SegmentFacing.XN); } } } private static void AddWall(FloorData floor, Vector2Int cell, SegmentFacing facing, HashSet doors) { if (doors.Contains(cell)) return; // здесь проём Add(floor, cell, SegmentKind.Wall, facing); } private static void Add(FloorData floor, Vector2Int cell, SegmentKind kind, SegmentFacing facing) => floor.Walls.Add(new WallSegment(cell, kind, facing)); } }