создание стен как информации, ещё не обьекты
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 List<Room> Rooms = new List<Room>();
|
||||||
public readonly Dictionary<Room, int> Depth = new Dictionary<Room, int>();
|
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 Start; // стартовая комната (вход с предыдущего этажа)
|
||||||
public Room Lift; // комната с лифтом (выход на следующий этаж)
|
public Room Lift; // комната с лифтом (выход на следующий этаж)
|
||||||
|
|
||||||
@ -74,6 +77,7 @@ namespace _Project.Scripts.LevelGenerating
|
|||||||
{
|
{
|
||||||
Rooms.Clear();
|
Rooms.Clear();
|
||||||
Depth.Clear();
|
Depth.Clear();
|
||||||
|
Walls.Clear();
|
||||||
Start = null;
|
Start = null;
|
||||||
Lift = null;
|
Lift = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,7 @@ namespace _Project.Scripts.LevelGenerating
|
|||||||
this.rt = rt;
|
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)
|
EntranceToRoomType entrance, List<ExitsInRoomType> exits)
|
||||||
{
|
{
|
||||||
Position = position;
|
Position = position;
|
||||||
@ -64,7 +64,7 @@ namespace _Project.Scripts.LevelGenerating
|
|||||||
Length = length;
|
Length = length;
|
||||||
this.rt = rt;
|
this.rt = rt;
|
||||||
this.entrance = entrance;
|
this.entrance = entrance;
|
||||||
this.isWallable = isWallable;
|
this.isClipped = isClipped;
|
||||||
this.exits = exits;
|
this.exits = exits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ namespace _Project.Scripts.LevelGenerating
|
|||||||
public Vector2Int Position; // левый нижний угол, в модулях
|
public Vector2Int Position; // левый нижний угол, в модулях
|
||||||
public RoomType rt { get; set; }
|
public RoomType rt { get; set; }
|
||||||
public EntranceToRoomType entrance { get; set; }
|
public EntranceToRoomType entrance { get; set; }
|
||||||
public bool isWallable { get; set; } // по факту: комнату ужали об границу карты (стоит переименовать)
|
public bool isClipped { get; set; }
|
||||||
public List<ExitsInRoomType> exits { get; set; }
|
public List<ExitsInRoomType> exits { get; set; }
|
||||||
|
|
||||||
public Vector2 Center => new Vector2(Position.x + Length / 2f, Position.y + Width / 2f);
|
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("Лифт не помещается: проверь размеры карты, лифта и коридора");
|
if (!ok) Debug.LogError("Лифт не помещается: проверь размеры карты, лифта и коридора");
|
||||||
|
|
||||||
AssignRoles();
|
AssignRoles();
|
||||||
|
ShellBuilder.Build(_data); // сегменты стен (только данные, без спавна)
|
||||||
|
|
||||||
SpawnMarkers(); // временно
|
SpawnMarkers(); // временно
|
||||||
return _data;
|
return _data;
|
||||||
@ -133,7 +134,7 @@ namespace _Project.Scripts.LevelGenerating
|
|||||||
{
|
{
|
||||||
foreach (var r in _data.UnassignedRooms.ToList())
|
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)];
|
r.rt = pool[Random.Range(0, pool.Length)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,7 +223,7 @@ namespace _Project.Scripts.LevelGenerating
|
|||||||
lift.rt = RoomType.Lift; // тип нужно выставить ДО AddRoom, чтобы FloorData запомнил Lift
|
lift.rt = RoomType.Lift; // тип нужно выставить ДО AddRoom, чтобы FloorData запомнил Lift
|
||||||
lift.exits = new List<ExitsInRoomType>();
|
lift.exits = new List<ExitsInRoomType>();
|
||||||
lift.entrance = ToEntrance(dir);
|
lift.entrance = ToEntrance(dir);
|
||||||
lift.isWallable = false;
|
lift.isClipped = false;
|
||||||
|
|
||||||
_data.AddRoom(lift, liftDepth);
|
_data.AddRoom(lift, liftDepth);
|
||||||
_parent[lift] = (parent, dir);
|
_parent[lift] = (parent, dir);
|
||||||
@ -432,7 +433,7 @@ namespace _Project.Scripts.LevelGenerating
|
|||||||
newRoom.entrance = ToEntrance(dir);
|
newRoom.entrance = ToEntrance(dir);
|
||||||
|
|
||||||
if (!FitRoom(prevRoom, newRoom, dir, out bool shrunk)) return false;
|
if (!FitRoom(prevRoom, newRoom, dir, out bool shrunk)) return false;
|
||||||
newRoom.isWallable = shrunk;
|
newRoom.isClipped = shrunk;
|
||||||
|
|
||||||
// Пересечения: комната (с зазором, без prevRoom) и коридор к ней
|
// Пересечения: комната (с зазором, без prevRoom) и коридор к ней
|
||||||
RectInt roomArea = Inflate(RoomRect(newRoom), Mathf.Min(_margin, _corrLen));
|
RectInt roomArea = Inflate(RoomRect(newRoom), Mathf.Min(_margin, _corrLen));
|
||||||
@ -568,6 +569,14 @@ namespace _Project.Scripts.LevelGenerating
|
|||||||
Vector3 c = LevelGrid.ToWorld(r.Center);
|
Vector3 c = LevelGrid.ToWorld(r.Center);
|
||||||
Gizmos.DrawWireCube(c, new Vector3(r.Length * LevelGrid.Module, 0.1f, r.Width * LevelGrid.Module));
|
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