169 lines
6.2 KiB
C#
169 lines
6.2 KiB
C#
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<Gap> CollectGaps(FloorData floor)
|
||
{
|
||
var gaps = new List<Gap>();
|
||
|
||
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<Gap> gaps)
|
||
{
|
||
int cursor = from;
|
||
|
||
if (gaps != null)
|
||
{
|
||
var own = new List<Gap>();
|
||
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));
|
||
}
|
||
}
|
||
} |