using System.Collections.Generic; using UnityEngine; namespace _Project.Scripts.LevelGenerating { // Куда смотрит видимая сторона стены (внутрь комнаты или коридора) public enum WallFacing { XP, XN, ZP, ZN } // Прямой отрезок стены по линии сетки (координаты в модулях). // Start - точка на линии сетки, с которой отрезок начинается. // Для ZP/ZN отрезок идёт вдоль +X, для XP/XN - вдоль +Z. // RoomIndex - индекс комнаты в FloorData.Rooms, которой принадлежит стена. // Поля публичные, чтобы потом сохранять в файл. [System.Serializable] public struct WallRun { public Vector2Int Start; public int Length; public WallFacing Facing; public int RoomIndex; public WallRun(Vector2Int start, int length, WallFacing facing, int roomIndex) { Start = start; Length = length; Facing = facing; RoomIndex = roomIndex; } } // ===================================================================== // Строит отрезки стен из FloorData. Спавна здесь нет, только данные. // // Правила: // - Стена стоит на границе прямоугольника комнаты (плоскость без толщины). // - У коридора стены только по двум длинным сторонам, торцы открыты. // - В стенах комнат вырезаются проёмы шириной ровно с коридор. // - Каждый отрезок помнит комнату-владельца (RoomIndex). // ===================================================================== public static class ShellBuilder { private struct Gap { public bool Vertical; // линия x = Line (вертикальная), иначе z = Line public int Line, From, To; } public static void Build(FloorData floor) { floor.Walls.Clear(); var gaps = CollectGaps(floor); for (int i = 0; i < floor.Rooms.Count; i++) { var r = floor.Rooms[i]; int x0 = r.Position.x, x1 = x0 + r.Length; int z0 = r.Position.y, z1 = z0 + r.Width; if (r.rt == RoomType.Corridor) { // у коридора проёмов нет, его торцы просто открыты if (IsAlongX(r)) { AddSide(floor, i, false, z0, x0, x1, WallFacing.ZP, null); AddSide(floor, i, false, z1, x0, x1, WallFacing.ZN, null); } else { AddSide(floor, i, true, x0, z0, z1, WallFacing.XP, null); AddSide(floor, i, true, x1, z0, z1, WallFacing.XN, null); } } else { AddSide(floor, i, false, z0, x0, x1, WallFacing.ZP, gaps); // южная AddSide(floor, i, false, z1, x0, x1, WallFacing.ZN, gaps); // северная AddSide(floor, i, true, x0, z0, z1, WallFacing.XP, gaps); // западная AddSide(floor, i, true, x1, z0, z1, WallFacing.XN, gaps); // восточная } } } // Коридор идёт вдоль 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 List CollectGaps(FloorData floor) { var gaps = new List(); foreach (var c in floor.Corridors) { int x0 = c.Position.x, x1 = x0 + c.Length; int z0 = c.Position.y, z1 = z0 + c.Width; if (IsAlongX(c)) { gaps.Add(new Gap { Vertical = true, Line = x0, From = z0, To = z1 }); gaps.Add(new Gap { Vertical = true, Line = x1, From = z0, To = z1 }); } else { gaps.Add(new Gap { Vertical = false, Line = z0, From = x0, To = x1 }); gaps.Add(new Gap { Vertical = false, Line = z1, From = x0, To = x1 }); } } return gaps; } // Добавляет сторону [from, to] на линии line, вырезая проёмы private static void AddSide(FloorData floor, int owner, bool vertical, int line, int from, int to, WallFacing facing, List gaps) { int cursor = from; if (gaps != null) { var own = new List(); foreach (var g in gaps) if (g.Vertical == vertical && g.Line == line && g.To > from && g.From < to) own.Add(g); own.Sort((a, b) => a.From.CompareTo(b.From)); foreach (var g in own) { if (g.From > cursor) AddRun(floor, owner, vertical, line, cursor, g.From, facing); cursor = Mathf.Max(cursor, g.To); } } if (cursor < to) AddRun(floor, owner, vertical, line, cursor, to, facing); } private static void AddRun(FloorData floor, int owner, bool vertical, int line, int a, int b, WallFacing facing) { Vector2Int start = vertical ? new Vector2Int(line, a) : new Vector2Int(a, line); floor.Walls.Add(new WallRun(start, b - a, facing, owner)); } } }