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

146 lines
6.2 KiB
C#
Raw 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 }
// Прямой отрезок стены по линии сетки (координаты в модулях).
// 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<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;
}
// Добавляет сторону [from, to] на линии line, вырезая проёмы
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);
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));
}
}
}