вроде порешал косяк лифта с поворотами. Мб не работает
This commit is contained in:
parent
490c534cfa
commit
9519be076f
@ -13842,15 +13842,15 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::_Project.Scripts.LevelGenerating.WallsGenerator
|
||||
floorsCount: 10
|
||||
lengthWallMin: 10
|
||||
lengthWallMax: 25
|
||||
lengthWallMin: 20
|
||||
lengthWallMax: 40
|
||||
lengthStartRoom: 10
|
||||
lengthLiftRoom: 10
|
||||
widthLiftRoom: 5
|
||||
lengthFloor: 100
|
||||
corridorLength: 5
|
||||
corridorWigth: 4
|
||||
_minDepthLiftRoom: 0
|
||||
_minDepthLiftRoom: 7
|
||||
GameObjectA: {fileID: 8066171868259172852, guid: e46748b8eb8a6074d9bb87701cebe84b, type: 3}
|
||||
GameObjectB: {fileID: 4641718306729093824, guid: 3905eab8a5f6b3049a83378b1acf1ebc, type: 3}
|
||||
maxRooms: 15
|
||||
|
||||
@ -26,6 +26,10 @@ namespace _Project.Scripts.LevelGenerating
|
||||
|
||||
private int _curRooms;
|
||||
private readonly Dictionary<Room, int> _depth = new Dictionary<Room, int>();
|
||||
private readonly Dictionary<Room, (Room parent, ExitsInRoomType dir)> _parent
|
||||
= new Dictionary<Room, (Room, ExitsInRoomType)>();
|
||||
[SerializeField] private bool liftDoorAnyPosition = false; // true, если дверь в префабе может быть не по центру
|
||||
private readonly Dictionary<Room, Room> _corridorOf = new Dictionary<Room, Room>();
|
||||
private LevelManager levelManager;
|
||||
|
||||
private static readonly ExitsInRoomType[] AllDirs =
|
||||
@ -40,40 +44,153 @@ namespace _Project.Scripts.LevelGenerating
|
||||
GenerateFloor();
|
||||
}
|
||||
|
||||
bool PlaceElevator()
|
||||
bool PlaceElevator()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (TryAttachLift(true, roomMargin)) return true; // норма: глубина >= минимума
|
||||
if (TryAttachLift(false, roomMargin)) return true; // без требования глубины
|
||||
if (TryAttachLift(false, 0f)) return true; // без зазора
|
||||
if (!PruneRandomLeaf()) return false; // освобождаем место и повторяем
|
||||
}
|
||||
}
|
||||
|
||||
private ExitsInRoomType[] LiftEntryDirs()
|
||||
{
|
||||
if (lengthLiftRoom > widthLiftRoom) return new[] { ExitsInRoomType.ZAxisP, ExitsInRoomType.ZAxisN };
|
||||
if (widthLiftRoom > lengthLiftRoom) return new[] { ExitsInRoomType.XAxisP, ExitsInRoomType.XAxisN };
|
||||
return AllDirs;
|
||||
}
|
||||
|
||||
// Сдвиги лифта вдоль стены, чтобы коридор всё равно попал в стену
|
||||
private IEnumerable<int> LiftShifts(ExitsInRoomType dir)
|
||||
{
|
||||
yield return 0;
|
||||
if (!liftDoorAnyPosition) yield break;
|
||||
|
||||
bool xDir = dir == ExitsInRoomType.XAxisP || dir == ExitsInRoomType.XAxisN;
|
||||
int cross = xDir ? widthLiftRoom : lengthLiftRoom;
|
||||
int max = (cross - corridorWigth) / 2;
|
||||
for (int s = 1; s <= max; s++) { yield return s; yield return -s; }
|
||||
}
|
||||
|
||||
bool TryAttachLift(bool requireMinDepth, float margin)
|
||||
{
|
||||
var start = levelManager.GetRooms().First(r => r.rt == RoomType.Start);
|
||||
|
||||
var parents = _depth.Keys
|
||||
.OrderByDescending(r => _depth[r])
|
||||
.ThenByDescending(r => (r.Position - start.Position).sqrMagnitude)
|
||||
.ToList();
|
||||
|
||||
foreach (var parent in parents)
|
||||
{
|
||||
if (requireMinDepth && _depth[parent] + 1 < _minDepthLiftRoom) continue;
|
||||
|
||||
foreach (var dir in LiftEntryDirs().OrderBy(_ => Random.value))
|
||||
{
|
||||
var start = levelManager.GetRooms().First(r => r.rt == RoomType.Start);
|
||||
if (parent.exits.Contains(dir)) continue;
|
||||
|
||||
// максимум шагов, при равенстве выбираем самую дальнюю от старта по прямой
|
||||
var best = _depth
|
||||
.OrderByDescending(p => p.Value)
|
||||
.ThenByDescending(p => (p.Key.Position - start.Position).sqrMagnitude)
|
||||
.First();
|
||||
|
||||
if (best.Key == start || best.Value <= _minDepthLiftRoom)
|
||||
foreach (int shift in LiftShifts(dir))
|
||||
{
|
||||
return false;
|
||||
|
||||
Room lift = new Room { Length = lengthLiftRoom, Width = widthLiftRoom };
|
||||
PlaceByEntry(EntryPoint(parent, dir), dir, lift);
|
||||
|
||||
bool xDir = dir == ExitsInRoomType.XAxisP || dir == ExitsInRoomType.XAxisN;
|
||||
lift.Position += xDir ? new Vector2(0, shift) : new Vector2(shift, 0);
|
||||
|
||||
if (!CanPlaceLift(parent, lift, dir, margin)) continue;
|
||||
|
||||
lift.rt = RoomType.Lift;
|
||||
lift.exits = new List<ExitsInRoomType>();
|
||||
lift.entrance = ToEntrance(dir);
|
||||
lift.isWallable = false;
|
||||
|
||||
levelManager.AddRoom(lift);
|
||||
_depth[lift] = _depth[parent] + 1;
|
||||
_parent[lift] = (parent, dir);
|
||||
_corridorOf[lift] = CreateCorridor(parent, dir);
|
||||
parent.exits.Add(dir);
|
||||
_curRooms++;
|
||||
return true;
|
||||
}
|
||||
best.Key.rt = RoomType.Lift; // добавь значение в enum RoomType
|
||||
best.Key.Length = lengthLiftRoom;
|
||||
best.Key.Width = widthLiftRoom;
|
||||
best.Key.exits.Clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CanPlaceLift(Room parent, Room lift, ExitsInRoomType dir, float margin)
|
||||
{
|
||||
if (!InBounds(lift)) return false;
|
||||
if (!IsAreaFree(CorridorRect(parent, dir))) return false;
|
||||
|
||||
Rect area = RoomRect(lift);
|
||||
float m = Mathf.Min(margin, corridorLength);
|
||||
area.xMin -= m; area.yMin -= m; area.xMax += m; area.yMax += m;
|
||||
return IsAreaFree(area, parent);
|
||||
}
|
||||
|
||||
// Удаляет случайную тупиковую комнату вместе с её коридором
|
||||
bool PruneRandomLeaf()
|
||||
{
|
||||
var parentsSet = new HashSet<Room>(_parent.Values.Select(v => v.parent));
|
||||
var leaves = _parent.Keys.Where(r => !parentsSet.Contains(r)).ToList();
|
||||
if (leaves.Count == 0) return false;
|
||||
|
||||
Room leaf = leaves[Random.Range(0, leaves.Count)];
|
||||
var (p, dir) = _parent[leaf];
|
||||
|
||||
LevelManager.Rooms.Remove(leaf);
|
||||
if (_corridorOf.TryGetValue(leaf, out var cor))
|
||||
{
|
||||
LevelManager.Rooms.Remove(cor);
|
||||
_corridorOf.Remove(leaf);
|
||||
}
|
||||
p.exits.Remove(dir);
|
||||
_depth.Remove(leaf);
|
||||
_parent.Remove(leaf);
|
||||
_curRooms--;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Позиция комнаты заданного размера относительно точки входа
|
||||
private static void PlaceByEntry(Vector2 e, ExitsInRoomType dir, Room n)
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case ExitsInRoomType.XAxisP: n.Position = new Vector2(e.x, e.y - n.Width / 2f); break;
|
||||
case ExitsInRoomType.XAxisN: n.Position = new Vector2(e.x - n.Length, e.y - n.Width / 2f); break;
|
||||
case ExitsInRoomType.ZAxisP: n.Position = new Vector2(e.x - n.Length / 2f, e.y); break;
|
||||
default: n.Position = new Vector2(e.x - n.Length / 2f, e.y - n.Width); break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool InBounds(Room r) =>
|
||||
r.Position.x >= 0 && r.Position.y >= 0 &&
|
||||
r.Position.x + r.Length <= lengthFloor &&
|
||||
r.Position.y + r.Width <= lengthFloor;
|
||||
|
||||
// Комнаты проверяются с зазором, коридоры без него (иначе зазор заденет собственный коридор лифта)
|
||||
|
||||
void GenerateFloor()
|
||||
{
|
||||
LevelManager.Rooms.Clear();
|
||||
_depth.Clear();// статический список мог остаться с прошлого запуска
|
||||
_curRooms = 0;
|
||||
const int maxAttempts = 50;
|
||||
bool ok = false;
|
||||
|
||||
CreateStartRoom();
|
||||
|
||||
if (!PlaceElevator())
|
||||
for (int i = 0; i < maxAttempts && !ok; i++)
|
||||
{
|
||||
GenerateFloor();
|
||||
LevelManager.Rooms.Clear();
|
||||
_depth.Clear();
|
||||
_parent.Clear();
|
||||
_corridorOf.Clear();
|
||||
_curRooms = 0;
|
||||
|
||||
CreateStartRoom();
|
||||
ok = PlaceElevator();
|
||||
}
|
||||
|
||||
if (!ok) Debug.LogWarning("Лифт не удалось разместить, этаж собран без него");
|
||||
|
||||
Instantiate(GameObjectA, new Vector3(0, -1, 0), Quaternion.identity);
|
||||
|
||||
foreach (var room in levelManager.GetRooms())
|
||||
@ -243,7 +360,8 @@ namespace _Project.Scripts.LevelGenerating
|
||||
// Всё хорошо - фиксируем
|
||||
levelManager.AddRoom(newRoom);
|
||||
_depth[newRoom] = _depth[prevRoom] + 1;
|
||||
CreateCorridor(prevRoom, dir);
|
||||
_parent[newRoom] = (prevRoom, dir);
|
||||
_corridorOf[newRoom] = CreateCorridor(prevRoom, dir); // вместо отдельного CreateCorridor(...)
|
||||
_curRooms++;
|
||||
if (!prevRoom.exits.Contains(dir)) prevRoom.exits.Add(dir);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user