Souljack/Assets/_Project/Scripts/LevelGenerating/ShellBuilder.cs

169 lines
6.2 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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));
}
}
}