создание стен как информации, ещё не обьекты
This commit is contained in:
parent
650af515e9
commit
bb8db47ecc
@ -30,6 +30,9 @@ namespace _Project.Scripts.LevelGenerating
|
||||
public readonly List<Room> Rooms = new List<Room>();
|
||||
public readonly Dictionary<Room, int> Depth = new Dictionary<Room, int>();
|
||||
|
||||
// Сегменты стен (заполняет ShellBuilder.Build)
|
||||
public readonly List<WallSegment> Walls = new List<WallSegment>();
|
||||
|
||||
public Room Start; // стартовая комната (вход с предыдущего этажа)
|
||||
public Room Lift; // комната с лифтом (выход на следующий этаж)
|
||||
|
||||
@ -74,6 +77,7 @@ namespace _Project.Scripts.LevelGenerating
|
||||
{
|
||||
Rooms.Clear();
|
||||
Depth.Clear();
|
||||
Walls.Clear();
|
||||
Start = null;
|
||||
Lift = null;
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ namespace _Project.Scripts.LevelGenerating
|
||||
this.rt = rt;
|
||||
}
|
||||
|
||||
public Room(Vector2Int position, int width, int length, RoomType rt, bool isWallable,
|
||||
public Room(Vector2Int position, int width, int length, RoomType rt, bool isClipped,
|
||||
EntranceToRoomType entrance, List<ExitsInRoomType> exits)
|
||||
{
|
||||
Position = position;
|
||||
@ -64,7 +64,7 @@ namespace _Project.Scripts.LevelGenerating
|
||||
Length = length;
|
||||
this.rt = rt;
|
||||
this.entrance = entrance;
|
||||
this.isWallable = isWallable;
|
||||
this.isClipped = isClipped;
|
||||
this.exits = exits;
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ namespace _Project.Scripts.LevelGenerating
|
||||
public Vector2Int Position; // левый нижний угол, в модулях
|
||||
public RoomType rt { get; set; }
|
||||
public EntranceToRoomType entrance { get; set; }
|
||||
public bool isWallable { get; set; } // по факту: комнату ужали об границу карты (стоит переименовать)
|
||||
public bool isClipped { get; set; }
|
||||
public List<ExitsInRoomType> exits { get; set; }
|
||||
|
||||
public Vector2 Center => new Vector2(Position.x + Length / 2f, Position.y + Width / 2f);
|
||||
|
||||
151
Assets/_Project/Scripts/LevelGenerating/ShellBuilder.cs
Normal file
151
Assets/_Project/Scripts/LevelGenerating/ShellBuilder.cs
Normal file
@ -0,0 +1,151 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a50a2fbc9cd247ff94eba16018870886
|
||||
timeCreated: 1791732492
|
||||
@ -123,6 +123,7 @@ namespace _Project.Scripts.LevelGenerating
|
||||
if (!ok) Debug.LogError("Лифт не помещается: проверь размеры карты, лифта и коридора");
|
||||
|
||||
AssignRoles();
|
||||
ShellBuilder.Build(_data); // сегменты стен (только данные, без спавна)
|
||||
|
||||
SpawnMarkers(); // временно
|
||||
return _data;
|
||||
@ -133,7 +134,7 @@ namespace _Project.Scripts.LevelGenerating
|
||||
{
|
||||
foreach (var r in _data.UnassignedRooms.ToList())
|
||||
{
|
||||
var pool = r.isWallable ? ClippedRoles : FullRoles;
|
||||
var pool = r.isClipped ? ClippedRoles : FullRoles;
|
||||
r.rt = pool[Random.Range(0, pool.Length)];
|
||||
}
|
||||
}
|
||||
@ -222,7 +223,7 @@ namespace _Project.Scripts.LevelGenerating
|
||||
lift.rt = RoomType.Lift; // тип нужно выставить ДО AddRoom, чтобы FloorData запомнил Lift
|
||||
lift.exits = new List<ExitsInRoomType>();
|
||||
lift.entrance = ToEntrance(dir);
|
||||
lift.isWallable = false;
|
||||
lift.isClipped = false;
|
||||
|
||||
_data.AddRoom(lift, liftDepth);
|
||||
_parent[lift] = (parent, dir);
|
||||
@ -432,7 +433,7 @@ namespace _Project.Scripts.LevelGenerating
|
||||
newRoom.entrance = ToEntrance(dir);
|
||||
|
||||
if (!FitRoom(prevRoom, newRoom, dir, out bool shrunk)) return false;
|
||||
newRoom.isWallable = shrunk;
|
||||
newRoom.isClipped = shrunk;
|
||||
|
||||
// Пересечения: комната (с зазором, без prevRoom) и коридор к ней
|
||||
RectInt roomArea = Inflate(RoomRect(newRoom), Mathf.Min(_margin, _corrLen));
|
||||
@ -568,6 +569,14 @@ namespace _Project.Scripts.LevelGenerating
|
||||
Vector3 c = LevelGrid.ToWorld(r.Center);
|
||||
Gizmos.DrawWireCube(c, new Vector3(r.Length * LevelGrid.Module, 0.1f, r.Width * LevelGrid.Module));
|
||||
}
|
||||
|
||||
// Сегменты стен: чёрные - стена, красные - угол
|
||||
foreach (var s in _data.Walls)
|
||||
{
|
||||
Gizmos.color = s.Kind == SegmentKind.Corner ? Color.red : Color.black;
|
||||
Vector3 pos = LevelGrid.ToWorld(new Vector2(s.Cell.x + 0.5f, s.Cell.y + 0.5f), 0.5f);
|
||||
Gizmos.DrawCube(pos, new Vector3(LevelGrid.Module, 1f, LevelGrid.Module) * 0.9f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user