Процедурная генерация — основа рогаликов и RPG в Roblox. Без грамотных алгоритмов бесконечные карты перегружают память сервера и приводят к лагам.
Используя BSP для разбиения комнат, триангуляцию Делоне для постройки коридоров и встроенный `StreamingEnabled`, можно создавать масштабные и плавные подземелья.
1. Разбиение пространства с помощью Binary Space Partitioning (BSP)
Рекурсивное деление области для предотвращения пересечений комнат:
- Рекурсивное ветвление: Карта последовательно делится на секторы по горизонтали и вертикали до достижения нужного размера комнат.
- Контроль пропорций: Ограничение соотношения сторон (1:1–1:2.5) исключает появление неестественно узких вытянутых залов.
- Гарантированное отсутствие коллизий: Комнаты вписываются строго внутрь своих секторов, исключая наложение друг на друга без тяжелых физических проверок.
2. Построение коридоров: Триангуляция Делоне и Остовное Дерево (MST)
Органичное соединение всех залов без тупиковых зон:
- Центроиды залов: Центры комнат формируют планарный 2D-граф триангуляции Делоне со всеми соседними путями.
- Минимальное остовное дерево (MST): Алгоритм Прима удаляет лишние ребра, соединяя все комнаты кратчайшим маршрутом.
- Добавление циклических петель (15%): Возврат части ребер предотвращает унылое линейное блуждание вперед-назад.
3. Трассировка коридоров и Сборка модульной геометрии
Превращение абстрактных графов в физические блоки Roblox:
- Ортогональные L-образные переходы: Коридоры прокладываются под прямым углом к дверным проемам комнат.
- 4-битный автотайлинг: Автоматический подбор углов, перекрестков и прямых стен в зависимости от соседних блоков.
- Оптимизация мешей: Объединение стен и полов сокращает общее число физических деталей на 90%.
-- Модуль разбиения пространства BSP
local BSPNode = {}
BSPNode.__index = BSPNode
function BSPNode.new(x, z, width, depth)
local self = setmetatable({}, BSPNode)
self.X, self.Z = x, z
self.Width, self.Depth = width, depth
self.LeftChild = nil
self.RightChild = nil
self.Room = nil
return self
end
function BSPNode:Split(minSize)
if self.LeftChild or self.RightChild then return false end
local splitHorizontal = math.random() > 0.5
if self.Width > self.Depth and (self.Width / self.Depth) >= 1.25 then
splitHorizontal = false
elseif self.Depth > self.Width and (self.Depth / self.Width) >= 1.25 then
splitHorizontal = true
end
local maxDimension = (splitHorizontal and self.Depth or self.Width) - minSize
if maxDimension <= minSize then return false end
local splitPos = math.random(minSize, maxDimension)
if splitHorizontal then
self.LeftChild = BSPNode.new(self.X, self.Z, self.Width, splitPos)
self.RightChild = BSPNode.new(self.X, self.Z + splitPos, self.Width, self.Depth - splitPos)
else
self.LeftChild = BSPNode.new(self.X, self.Z, splitPos, self.Depth)
self.RightChild = BSPNode.new(self.X + splitPos, self.Z, self.Width - splitPos, self.Depth)
end
return true
end
return BSPNode
4. Управление памятью через StreamingEnabled
Стабильная работа подземелий на 100+ комнат даже на устройствах с 2 ГБ ОЗУ:
- ModelStreamingMode.Atomic: Загрузка комнат целиком предотвращает проваливание персонажей сквозь отсутствующие полы.
- Чанки 64x64 studs: Отключение физических расчетов для далеких секторов подземелья.
- Окклюзивный куллинг: Двери и порталы отсекают рендеринг скрытых помещений, снижая нагрузку на видеокарту.
5. Синхронизация через Seed и Контроль сущностей на сервере
Честный геймплей без задержек сетевой передачи карты:
- Единый генератор случайных чисел: Передача одного 32-битного числа (Seed) позволяет клиенту построить точную копию карты локально.
- Спавн врагов на сервере: Монстры, сундуки и ловушки создаются и обсчитываются строго сервером.
- Динамический NavMesh: Настройка PathfindingModifier на тайлах пола для безупречного преследования игроков ИИ-монстрами.
Frequently Asked Questions
Почему BSP лучше простого случайного размещения?
Случайное размещение требует тяжелых проверок столкновений и оставляет пустоты. BSP равномерно делит пространство без наложений.
Зачем совмещать триангуляцию Делоне и MST?
Делоне строит естественные связи между соседями, а MST гарантирует связность всех залов без лишней путаницы.
Как StreamingEnabled помогает подземельям?
Он подгружает только ближайшие комнаты, позволяя запускать гигантские карты даже на слабых смартфонах.
Как избежать рассинхрона карты между игроками?
Достаточно передать один и тот же сид (числовой ключ), чтобы клиент и сервер построили абсолютно одинаковый лабиринт.