using System.Collections.Generic; using UnityEngine; namespace _Project.Scripts.LevelGenerating { public enum WallFacing { XP, XN, ZP, ZN } [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; } } // Дверной проём в стене (для перемычки над дверью и спавна самой двойной двери) [System.Serializable] public struct Doorway { public Vector2Int Start; public int Length; public WallFacing Facing; public int RoomIndex; public bool SpawnDoor; public Doorway(Vector2Int start, int length, WallFacing facing, int roomIndex, bool spawnDoor) { Start = start; Length = length; Facing = facing; RoomIndex = roomIndex; SpawnDoor = spawnDoor; } } public static class ShellBuilder { private struct Gap { public bool Vertical; public int Line, From, To; } public static void Build(FloorData floor) { floor.Walls.Clear(); floor.Doorways.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); AddDoorway(floor, i, true, x0, z0, z1, WallFacing.XP, false); AddDoorway(floor, i, true, x1, z0, z1, WallFacing.XN, false); } else { AddSide(floor, i, true, x0, z0, z1, WallFacing.XP, null); AddSide(floor, i, true, x1, z0, z1, WallFacing.XN, null); AddDoorway(floor, i, false, z0, x0, x1, WallFacing.ZP, false); AddDoorway(floor, i, false, z1, x0, x1, WallFacing.ZN, false); } } 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); // восточная } } } 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; } 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); // Записываем проём для перемычки и двери int gapStart = Mathf.Max(cursor, g.From); int gapEnd = Mathf.Min(to, g.To); if (gapEnd > gapStart) AddDoorway(floor, owner, vertical, line, gapStart, gapEnd, facing, true); 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)); } private static void AddDoorway(FloorData floor, int owner, bool vertical, int line, int a, int b, WallFacing facing, bool spawnDoor) { Vector2Int start = vertical ? new Vector2Int(line, a) : new Vector2Int(a, line); floor.Doorways.Add(new Doorway(start, b - a, facing, owner, spawnDoor)); } } }