создание стен как информации, ещё не обьекты

This commit is contained in:
vladislove 2026-10-11 19:07:55 +03:00
parent 650af515e9
commit bb8db47ecc
5 changed files with 174 additions and 7 deletions

View File

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

View File

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

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

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a50a2fbc9cd247ff94eba16018870886
timeCreated: 1791732492

View File

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