La generación procedimental es el motor de los juegos roguelike y RPG en Roblox. Sin un algoritmo sólido, los mapas saturan la memoria del servidor y provocan caídas de fotogramas.
Mediante partición binaria (BSP), triangulación de Delaunay para pasillos y el sistema `StreamingEnabled`, es posible crear mazmorras infinitas y fluidas para miles de jugadores.
1. Creación de Habitaciones con Partición Espacial Binaria (BSP)
Subdivisión matemática para una distribución homogénea:
- División Recursiva: El mapa se corta horizontal o verticalmente en proporciones aleatorias hasta alcanzar el tamaño deseado en los nodos hoja.
- Control de Proporciones: Evita habitaciones desproporcionadamente estrechas manteniendo una relación de aspecto de 1:1 a 1:2.5.
- Inscripción Segura: Las salas se circunscriben en sus particiones, eliminando solapamientos sin costosas pruebas de colisión física.
2. Pasillos Orgánicos: Triangulación de Delaunay y Árbol de Expansión Mínima
Conexión natural sin callejones sin salida:
- Nube de Puntos Centroides: Conecta los centros de cada habitación mediante una red de Delaunay plana.
- Árbol de Expansión Mínima (MST): Elimina conexiones redundantes garantizando que todas las salas estén comunicadas.
- Bucles Cíclicos (15% Extra): Reincorpora algunas aristas eliminadas para ofrecer rutas alternativas y evitar trayectos lineales.
3. Enrutamiento en Cuadrícula e Instanciación de Bloques
Transformación de líneas matemáticas en partes reales de Roblox:
- Pasillos en L y S: Rutas ortogonales en ángulo recto que unen las puertas de cada sala.
- Bitmasking para Autotiling: Selección automática de muros rectos, esquinas y cruces según vecinos adyacentes.
- Fusión Geométrica: Agrupación en modelos soldados o mallas combinadas para reducir el conteo de partes en un 90%.
-- Módulo de Partición Espacial Binaria (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. Optimización de Memoria con StreamingEnabled
Rendimiento estable en dispositivos móviles con 2GB de RAM:
- ModelStreamingMode.Atomic: Carga salas completas de golpe para evitar caídas al vacío por paredes ausentes.
- Partición en Chunks de 64x64 studs: Desactiva la física de sectores lejanos hasta que el jugador se aproxime.
- Culling de Oclusión: Las puertas cerradas impiden renderizar cámaras ocultas fuera de la vista.
5. Semillas Deterministas y Autoridad del Servidor
Sincronización perfecta y prevención de trampas:
- Replicación de Semilla (Seed): Un único número entero permite al cliente y servidor generar el mismo mapa con 0 lag.
- Entidades en Servidor: Monstruos, cofres y trampas se generan exclusivamente en el servidor.
- NavMesh Dinámico: Configuración de PathfindingModifier para que la IA enemiga navegue esquivando abismos.
Frequently Asked Questions
¿Por qué usar BSP en lugar de ubicar salas al azar?
El azar puro genera solapamientos difíciles de corregir y huecos vacíos. BSP distribuye el espacio de manera matemática y homogénea.
¿Qué ventaja aporta la triangulación de Delaunay junto al MST?
Delaunay encuentra vecinos cercanos lógicos y el MST asegura que todo el mapa sea transitable sin bifurcaciones excesivas.
¿Cómo beneficia StreamingEnabled a las mazmorras?
Permite descargar de memoria los sectores lejanos, logrando que mazmorras gigantescas funcionen con total fluidez en móviles.
¿Cómo sincronizar la generación sin saturar la red?
Compartiendo únicamente una semilla numérica idéntica en cliente y servidor para que ambos construyan el mismo mapa localmente.