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

151 lines
6.7 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 SegmentKind { Wall, Corner }
// Куда смотрит видимая сторона сегмента (внутрь комнаты или коридора).
// Для Corner - какой это угол комнаты (SW = минимальные X и Z).
public enum SegmentFacing { XP, XN, ZP, ZN, CornerSW, CornerSE, CornerNW, CornerNE }
// Один сегмент стены = одна клетка (1 модуль = 0.5 м) по периметру.
// Поля публичные, чтобы потом можно было сохранять в файл.
[System.Serializable]
public struct WallSegment
{
public Vector2Int Cell;
public SegmentKind Kind;
public SegmentFacing Facing;
public WallSegment(Vector2Int cell, SegmentKind kind, SegmentFacing facing)
{
Cell = cell;
Kind = kind;
Facing = facing;
}
}
// =====================================================================
// Строит сегменты стен из FloorData. Спавна здесь нет, только данные.
//
// Правила:
// - Стены стоят ВНУТРИ прямоугольника комнаты: это внешнее кольцо клеток шириной 1 модуль.
// - У коридора стены только по двум длинным сторонам, торцы открыты.
// - Проём в стене комнаты равен ВНУТРЕННЕЙ ширине коридора (ширина коридора минус 2 клетки,
// то есть минус по 0.5 м стены с каждой стороны). Иначе проём был бы шире прохода.
// - Стык стены коридора со стеной комнаты - Т-образный, угловой элемент там не ставится.
//
// НЕ ЗАБЫТЬ: ширина коридора должна быть минимум 3 клетки, иначе проёма не будет.
// =====================================================================
public static class ShellBuilder
{
public static void Build(FloorData floor)
{
floor.Walls.Clear();
var doors = CollectDoorCells(floor);
foreach (var r in floor.Rooms)
{
if (r.rt == RoomType.Corridor) AddCorridorWalls(floor, r);
else AddRoomWalls(floor, r, doors);
}
}
// Коридор идёт вдоль 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 HashSet<Vector2Int> CollectDoorCells(FloorData floor)
{
var set = new HashSet<Vector2Int>();
foreach (var c in floor.Corridors)
{
int x0 = c.Position.x, z0 = c.Position.y;
if (IsAlongX(c))
{
// слева стена комнаты в колонке x0 - 1, справа в колонке x0 + Length
for (int z = z0 + 1; z < z0 + c.Width - 1; z++)
{
set.Add(new Vector2Int(x0 - 1, z));
set.Add(new Vector2Int(x0 + c.Length, z));
}
}
else
{
// снизу стена комнаты в ряду z0 - 1, сверху в ряду z0 + Width
for (int x = x0 + 1; x < x0 + c.Length - 1; x++)
{
set.Add(new Vector2Int(x, z0 - 1));
set.Add(new Vector2Int(x, z0 + c.Width));
}
}
}
return set;
}
private static void AddRoomWalls(FloorData floor, Room r, HashSet<Vector2Int> doors)
{
int x0 = r.Position.x, z0 = r.Position.y;
int x1 = x0 + r.Length - 1, z1 = z0 + r.Width - 1;
// углы
Add(floor, new Vector2Int(x0, z0), SegmentKind.Corner, SegmentFacing.CornerSW);
Add(floor, new Vector2Int(x1, z0), SegmentKind.Corner, SegmentFacing.CornerSE);
Add(floor, new Vector2Int(x0, z1), SegmentKind.Corner, SegmentFacing.CornerNW);
Add(floor, new Vector2Int(x1, z1), SegmentKind.Corner, SegmentFacing.CornerNE);
// нижняя и верхняя стены (идут вдоль X)
for (int x = x0 + 1; x < x1; x++)
{
AddWall(floor, new Vector2Int(x, z0), SegmentFacing.ZP, doors);
AddWall(floor, new Vector2Int(x, z1), SegmentFacing.ZN, doors);
}
// левая и правая стены (идут вдоль Z)
for (int z = z0 + 1; z < z1; z++)
{
AddWall(floor, new Vector2Int(x0, z), SegmentFacing.XP, doors);
AddWall(floor, new Vector2Int(x1, z), SegmentFacing.XN, doors);
}
}
private static void AddCorridorWalls(FloorData floor, Room c)
{
int x0 = c.Position.x, z0 = c.Position.y;
if (IsAlongX(c))
{
for (int x = x0; x < x0 + c.Length; x++)
{
Add(floor, new Vector2Int(x, z0), SegmentKind.Wall, SegmentFacing.ZP);
Add(floor, new Vector2Int(x, z0 + c.Width - 1), SegmentKind.Wall, SegmentFacing.ZN);
}
}
else
{
for (int z = z0; z < z0 + c.Width; z++)
{
Add(floor, new Vector2Int(x0, z), SegmentKind.Wall, SegmentFacing.XP);
Add(floor, new Vector2Int(x0 + c.Length - 1, z), SegmentKind.Wall, SegmentFacing.XN);
}
}
}
private static void AddWall(FloorData floor, Vector2Int cell, SegmentFacing facing, HashSet<Vector2Int> doors)
{
if (doors.Contains(cell)) return; // здесь проём
Add(floor, cell, SegmentKind.Wall, facing);
}
private static void Add(FloorData floor, Vector2Int cell, SegmentKind kind, SegmentFacing facing) =>
floor.Walls.Add(new WallSegment(cell, kind, facing));
}
}