Optimize Maps en Kirin: un tileset para cada mapa, no un tileset gigante para todo
Un mapa de RPG Maker XP puede utilizar apenas una fracción de un tileset gigantesco. Optimize Maps analiza lo que cada mapa necesita, genera una variante compacta y evita que Android pague por miles de tiles que nunca van a aparecer en pantalla.
RPG Maker XP permite que muchos mapas compartan un mismo tileset. En proyectos pequeños es una solución simple y eficaz. El problema aparece cuando ese tileset crece durante años hasta convertirse en una imagen enorme que contiene miles de tiles, aunque un mapa concreto sólo utilice una pequeña parte.
Ese patrón es especialmente frecuente en proyectos grandes construidos sobre Pokémon Essentials. El desarrollador añade ciudades, árboles, caminos, edificios, objetos y decoraciones al mismo recurso y el tileset continúa creciendo. Para RPG Maker XP sigue siendo un único archivo. Para un teléfono Android puede convertirse en una textura innecesariamente grande, lenta de cargar o incluso imposible de representar de la manera tradicional.
El problema de los tilesets gigantes
Imaginemos un archivo:
Graphics/Tilesets/Exterior.png
256 × 20000 px
Con ocho tiles de 32×32 píxeles por fila, un tileset de 20.000 píxeles de altura puede contener alrededor de cinco mil tiles del bloque principal. Sin embargo, un pequeño pueblo puede utilizar únicamente cien o doscientos de ellos.
El modelo tradicional continúa relacionando el mapa con el recurso completo:
Kirin cambia el punto de vista. En vez de preguntarse cómo hacer que Android cargue más eficientemente una imagen gigantesca, intenta descubrir qué partes de esa imagen son realmente necesarias para ese mapa.
Optimize Maps analiza los datos reales del proyecto
La optimización comienza leyendo la estructura de RPG Maker XP. Kirin examina Data/Tilesets.rxdata para relacionar cada tileset_id con su nombre y después recorre los archivos MapXXX.rxdata.
Para cada mapa obtiene:
- qué tileset utiliza;
- qué identificadores de tile aparecen en sus capas;
- qué tiles se utilizan como gráficos de eventos;
- qué conjunto completo debe conservarse para que el mapa siga siendo visualmente idéntico.
Esto es importante porque un tile que no aparezca en el terreno normal todavía puede estar siendo usado por un evento. El optimizador no se limita a mirar la imagen visible del mapa: también incorpora esos tiles de eventos antes de decidir qué puede eliminar.
La filosofía: un tileset para cada mapa
Conceptualmente el sistema original se parece a esto:
TILESET GIGANTE
↑
┌────────────┼────────────┐
│ │ │
Map001 Map002 Map003
Optimize Maps busca algo más parecido a:
Map001 → tileset compacto A
Map002 → tileset compacto B
Map003 → tileset compacto C
No significa necesariamente que Kirin escriba un archivo distinto para cada mapa. La filosofía es que cada mapa tenga una variante adaptada a su necesidad real. Si varios mapas necesitan exactamente el mismo conjunto de tiles, pueden compartir la misma variante.
De cinco mil tiles a los que realmente importan
Supongamos que el tileset original contiene aproximadamente:
5000 tiles disponibles
pero un mapa utiliza únicamente:
120 tiles
Kirin puede reconstruir un atlas compacto con esos 120 tiles. Como el formato de RMXP trabaja con ocho tiles por fila, 120 tiles necesitan quince filas:
120 / 8 = 15 filas
15 × 32 = 480 px
El recurso lógico necesario por ese mapa puede pasar entonces de:
Original
- 256 × 20000 px
- ~5000 tiles
- gran superficie a decodificar y administrar
Variante compacta
- 256 × 480 px
- 120 tiles usados
- mucho menos trabajo para cargar el mapa
En RGBA de 32 bits, una superficie 256×20000 representa aproximadamente 19,5 MiB sin comprimir. Una de 256×480 representa menos de medio MiB. La diferencia puede ser enorme incluso antes de aplicar la compresión de los formatos de runtime.
El atlas se construye tile por tile
Una vez conocido el conjunto utilizado, Kirin crea una nueva superficie de 256 píxeles de ancho y coloca allí cada tile de 32×32. Los tiles se compactan sin cambiar lo que el mapa cree que está utilizando.
TILESET ORIGINAL
#384 #385 #386 ... #1401 ... #2988 ...
MAPA USA
#420 #853 #1401 #2988
ATLAS COMPACTO
#0 #1 #2 #3
Esto obliga a mantener una correspondencia entre los índices históricos del mapa y sus nuevas posiciones físicas.
El mapa original no se reescribe
Ésta es una de las partes más importantes del diseño. Optimize Maps no necesita convertir todos los MapXXX.rxdata a una numeración nueva.
El mapa puede continuar solicitando:
tile #1401
mientras Kirin sabe que, para ese mapa concreto, ese tile se encuentra en una posición distinta dentro del atlas compacto.
De esta manera se conserva la semántica de RPG Maker XP mientras cambia completamente la representación gráfica situada debajo.
Si dos mapas usan lo mismo, no hay por qué duplicar
La implementación actual genera una firma SHA-256 a partir del conjunto de tiles utilizado por cada mapa. Si dos mapas usan el mismo tileset y el mismo conjunto de tiles, producen la misma variante lógica.
Map012 ─┐
├──→ variante 7f31...
Map013 ─┘
Map014 ───→ variante b824...
Esto evita que la especialización por mapa se transforme en cientos de copias idénticas.
La filosofía sigue siendo “un tileset apropiado para cada mapa”, pero el almacenamiento puede reutilizar variantes cuando hacerlo es seguro.
index.kgi: la tabla que une mapa, variante y tile
Kirin guarda los metadatos de esta optimización dentro de:
Graphics/Tilesets/KirinOptimized/index.kgi
Ese índice contiene la información necesaria para resolver el recurso correcto durante la ejecución:
- tileset original;
- dimensiones lógicas;
- tamaño de tile;
- tabla mapa → variante;
- archivo correspondiente a cada variante;
- tabla tile original → índice compacto.
Así el runtime no tiene que deducir todo esto cada vez que entra en un mapa. El trabajo complejo se realiza durante la optimización y el juego consume después una estructura preparada.
Optimize Maps se concentra en los casos realmente problemáticos
La implementación actual no intenta compactar cualquier tileset. Está dirigida específicamente a tilesets RMXP de 256 píxeles de ancho cuya altura supera los 4096 píxeles.
ancho = 256 px
altura > 4096 px
→ candidato a Optimize Maps
Un tileset pequeño no necesita esta infraestructura adicional. El objetivo es atacar los recursos que empiezan a convertirse en un problema real de memoria, carga o compatibilidad gráfica.
Por qué puede eliminar mapas negros
El artículo anterior sobre GL_MAX_TEXTURE_SIZE mostró que una GPU posee un límite máximo para las dimensiones de una textura individual. Un teléfono puede aceptar 8192 o 16384 píxeles mientras una GPU de escritorio puede permitir bastante más.
Supongamos:
tileset = 256 × 20000
GPU móvil: GL_MAX_TEXTURE_SIZE = 16384
La imagen original no puede existir como una única textura convencional en esa GPU. Dependiendo del camino gráfico utilizado por el juego, esto puede terminar en un mapa que no aparece correctamente o incluso en el conocido síntoma de un mapa negro.
Optimize Maps no intenta aumentar el límite de la GPU. Elimina la necesidad de alcanzarlo.
256 × 20000 original
↓
Map023 sólo necesita 120 tiles
↓
256 × 480 compacto
↓
ya no existe la textura gigante para ese mapa
La mejor forma de manejar una textura gigante puede ser no cargarla.
Carga más rápida porque hay menos que cargar
La reducción de tamaño también tiene una consecuencia inmediata sobre el tiempo de carga.
Sin la optimización:
abrir tileset gigante
→ leer
→ decodificar
→ preparar
→ transferir / administrar
→ renderizar mapa
Con la variante ya generada:
identificar Map023
→ consultar index.kgi
→ abrir atlas compacto
→ cargar menos datos
→ renderizar mapa
La aceleración concreta depende del proyecto y del dispositivo, pero el principio es directo: menos superficie significa menos datos que leer, decodificar, mantener y transferir.
El coste se paga durante la optimización, no en cada entrada al mapa
Optimize Maps no elimina trabajo mágicamente. Lo desplaza.
Durante la preparación Kirin tiene que:
- leer todos los mapas;
- leer
Tilesets.rxdata; - detectar los tiles utilizados;
- incluir tiles de eventos;
- decodificar el tileset fuente;
- construir los nuevos atlases;
- generar las tablas de remapeo;
- escribir
index.kgi.
Es trabajo deliberadamente realizado una vez para evitar repetir un coste mayor durante el juego.
Es la misma filosofía que aparece en el caché de rutas de Kirin:
Los atlases compactos se escriben como KAL4
La implementación actual genera los atlases compactos mediante KAL4 v2. KAL4 almacena bloques GPU ASTC 4×4 y utiliza LZ4 para su representación física.
Por tanto el recorrido real de Optimize Maps se aproxima a:
tileset gigante
↓
analizar MapXXX.rxdata
↓
seleccionar tiles usados
↓
construir atlas compacto
↓
KAL4 v2
↓
runtime / GPU
La opción de mapas y la optimización gráfica completa comparten así una misma tecnología física de recursos, aunque sus objetivos sean distintos.
Optimize Maps no es lo mismo que Optimize Graphics
Esto conviene dejarlo claro.
Optimize Maps
- analiza MapXXX.rxdata;
- compacta tilesets gigantes por uso real;
- genera variantes;
- crea index.kgi;
- no necesita convertir todos los PNG del juego.
Optimize Graphics
- abarca el conjunto gráfico completo;
- convierte recursos elegibles al pipeline KAL4;
- tiene un alcance más amplio que los mapas.
Optimize Maps es una optimización especializada del sistema de mapas, no simplemente otro nombre para convertir todos los gráficos.
La optimización modifica el juego seleccionado
El sistema actual funciona in-place. No crea una copia completa del juego dentro de otra carpeta de Kirin.
Los atlases y su índice aparecen bajo:
Graphics/
└── Tilesets/
└── KirinOptimized/
├── index.kgi
├── Exterior_a1b2....png
├── Exterior_c3d4....png
└── ...
El manifiesto de optimización permite además saber cuántos mapas y tilesets fueron procesados y si el último proceso terminó correctamente.
Compatibilidad antes que una optimización incompleta
Kirin tampoco intenta optimizar a cualquier precio.
Si un mapa no puede leerse correctamente, se omite. Si un tileset está ausente o no puede decodificarse, el grupo correspondiente se deja fuera del índice optimizado y el runtime puede continuar por su ruta normal.
Esto evita uno de los peores escenarios posibles:
La prioridad es que el juego continúe funcionando. La optimización sólo se utiliza cuando Kirin puede construir una representación consistente.
Incluso un mapa sin tiles obtiene una variante válida
Existe un detalle pequeño pero importante. Si el mapa no utiliza ningún tile del bloque principal, Kirin puede crear un atlas transparente mínimo de 256×32.
Esto significa que el runtime sigue teniendo una asignación directa:
map_id → variante
sin añadir excepciones especiales para el caso vacío.
De un recurso global a recursos especializados
Optimize Maps representa muy bien una idea recurrente en Kirin.
RPG Maker XP expone una estructura lógica:
Mapa → tileset → tile
Kirin conserva esa semántica, pero cambia su representación física:
Mapa
↓
index.kgi
↓
variante compacta
↓
tile remapeado
↓
GPU
El juego no necesita enterarse de que el enorme tileset original ya no es el recurso que la GPU está utilizando para ese mapa.
No adaptar el problema: eliminarlo
Un port tradicional puede intentar responder:
¿Cómo hacemos para cargar este tileset de 20.000 píxeles en Android?
Optimize Maps introduce una pregunta más útil:
¿Por qué este mapa necesita cargar 20.000 píxeles si sólo utiliza 480?
Ésa es la diferencia entre reproducir una limitación histórica y evolucionar la arquitectura.
Un tileset para cada mapa
La filosofía completa puede resumirse así:
RPG MAKER XP
5000 tiles disponibles
↓
tileset gigante
↓
Map001 usa 120
pero el recurso contiene 5000
KIRIN
5000 tiles originales
↓
analizar Map001
↓
120 tiles usados
↓
atlas compacto
↓
120 tiles
Si otro mapa necesita 85 tiles, obtiene otra variante. Si varios mapas necesitan exactamente el mismo conjunto, pueden compartirla.
De una sola decisión aparecen tres beneficios al mismo tiempo:
Optimize Maps no intenta hacer que Android soporte mejor todo lo que RPG Maker XP acumuló. Intenta asegurarse de que cada mapa pague solamente por lo que realmente utiliza.
Optimización orientada al contenido real
Kirin conserva la lógica del mapa original, pero puede ofrecer a la GPU una representación mucho más pequeña y adaptada al dispositivo.
Ver más artículos técnicos