Saltar al contenido principal

Módulo GridMap

El módulo GridMap proporciona una estructura de datos de cuadrícula 2D optimizada para juegos y aplicaciones que requieren mapas de tiles, pathfinding y detección de colisiones basada en celdas. Cada celda almacena un valor entero de 0 a 255, permitiendo representar diferentes tipos de terreno, obstáculos o estados.

JARU GridMap Module

Este módulo es especialmente útil para desarrollar juegos tipo arcade, puzzles basados en cuadrículas, simulaciones de mapas y cualquier aplicación que necesite navegación inteligente entre puntos.

Uso

use GridMap

Constructor

new

La función GridMap.new(ancho, alto) crea una nueva cuadrícula con las dimensiones especificadas. Todas las celdas se inicializan a 0.

use GridMap

// Crear una cuadrícula de 20x15 celdas
var mapa = GridMap.new(20, 15)
ParámetroTipoDescripción
anchointegerNúmero de columnas de la cuadrícula
altointegerNúmero de filas de la cuadrícula

Retorno

Devuelve un objeto GridMap con las siguientes propiedades:

PropiedadTipoDescripción
widthintegerAncho de la cuadrícula (columnas)
heightintegerAlto de la cuadrícula (filas)

Métodos de instancia

setCell

El método setCell(x, y, valor) establece el valor de una celda específica.

// Establecer una pared (valor 1) en la posición (5, 3)
mapa.setCell(5, 3, 1)

// Establecer diferentes tipos de terreno
mapa.setCell(0, 0, 0) // Suelo vacío
mapa.setCell(1, 0, 1) // Pared
mapa.setCell(2, 0, 2) // Agua
mapa.setCell(3, 0, 5) // Punto de interés
ParámetroTipoDescripción
xintegerCoordenada X (columna)
yintegerCoordenada Y (fila)
valorintegerValor a asignar (0-255)

getCell

El método getCell(x, y) obtiene el valor de una celda específica.

var valor = mapa.getCell(5, 3)
println("Valor en (5,3): ", valor)
ParámetroTipoDescripción
xintegerCoordenada X (columna)
yintegerCoordenada Y (fila)

Retorno

Devuelve el valor entero (0-255) almacenado en la celda, o -1 si las coordenadas están fuera de rango.

isBlocked

El método isBlocked(x, y) comprueba si una celda está bloqueada (tiene un valor distinto de 0).

if (mapa.isBlocked(5, 3)) then
println("La celda está bloqueada")
else
println("La celda está libre")
end
ParámetroTipoDescripción
xintegerCoordenada X (columna)
yintegerCoordenada Y (fila)

Retorno

Devuelve true si el valor de la celda es distinto de 0, false en caso contrario.

clear

El método clear(valor) establece todas las celdas de la cuadrícula al valor especificado.

// Limpiar todo el mapa (poner a 0)
mapa.clear(0)

// Llenar todo de paredes
mapa.clear(1)
ParámetroTipoDescripción
valorintegerValor a asignar a todas las celdas (0-255)

clone

El método clone() crea una copia profunda de la cuadrícula.

var copiaDelMapa = mapa.clone()

// Modificar la copia no afecta al original
copiaDelMapa.setCell(0, 0, 99)
println(mapa.getCell(0, 0)) // Valor original
println(copiaDelMapa.getCell(0, 0)) // 99

Retorno

Devuelve un nuevo objeto GridMap con los mismos valores que el original.

findPath

El método findPath(sx, sy, gx, gy [, pasables [, permitirWrap]]) encuentra el camino más corto entre dos puntos usando el algoritmo BFS (Breadth-First Search).

// Encontrar camino desde (0,0) hasta (10,10)
var camino = mapa.findPath(0, 0, 10, 10)

if (camino != nil) then
println("Camino encontrado con ", len(camino), " pasos")
foreach (var punto in camino)
println(" -> (", punto[0], ", ", punto[1], ")")
end
else
println("No hay camino posible")
end
ParámetroTipoDescripción
sxintegerCoordenada X de inicio
syintegerCoordenada Y de inicio
gxintegerCoordenada X de destino
gyintegerCoordenada Y de destino
pasableslist(Opcional) Lista de valores considerados transitables. Por defecto: [1, 2, 3, 5]
permitirWrapboolean(Opcional) Si true, permite movimiento toroidal (los bordes se conectan). Por defecto: false

Retorno

Devuelve una lista de coordenadas [[x1,y1], [x2,y2], ...] representando el camino, o nil si no existe camino posible.

Valores pasables

Por defecto, las celdas con valores 1, 2, 3 y 5 son transitables. La celda con valor 0 también es transitable (suelo vacío). Puedes personalizar qué valores son obstáculos pasando tu propia lista.

buildDistanceMap

El método buildDistanceMap(objetivos [, pasables [, permitirWrap]]) construye un mapa de distancias desde múltiples puntos objetivo usando BFS multi-fuente.

// Puntos de interés (ej: power-ups en un juego)
var objetivos = [[5, 5], [15, 10], [8, 12]]

// Construir mapa de distancias
var distancias = mapa.buildDistanceMap(objetivos)

// Obtener distancia desde cualquier punto al objetivo más cercano
var dist = distancias.getCell(0, 0)
println("Distancia al objetivo más cercano: ", dist)
ParámetroTipoDescripción
objetivoslistLista de coordenadas [[x1,y1], [x2,y2], ...]
pasableslist(Opcional) Lista de valores transitables
permitirWrapboolean(Opcional) Permite movimiento toroidal

Retorno

Devuelve un nuevo GridMap donde cada celda contiene la distancia mínima al objetivo más cercano. Las celdas inalcanzables tienen el valor 255.

findNearestOf

El método findNearestOf(objetivos, sx, sy [, pasables [, permitirWrap]]) encuentra el objetivo más cercano desde una posición dada.

// Posiciones de los fantasmas
var fantasmas = [[2, 3], [8, 1], [12, 7]]

// Encontrar el fantasma más cercano al jugador
var resultado = mapa.findNearestOf(fantasmas, jugadorX, jugadorY)

if (resultado != nil) then
println("Fantasma más cercano en: (", resultado[0], ", ", resultado[1], ")")
println("Distancia: ", resultado[2], " pasos")
else
println("No se puede alcanzar ningún fantasma")
end
ParámetroTipoDescripción
objetivoslistLista de coordenadas objetivo
sxintegerCoordenada X de inicio
syintegerCoordenada Y de inicio
pasableslist(Opcional) Lista de valores transitables
permitirWrapboolean(Opcional) Permite movimiento toroidal

Retorno

Devuelve una lista [x, y, distancia] con las coordenadas del objetivo más cercano y la distancia, o nil si ningún objetivo es alcanzable.

Conceptos importantes

Valores de celda

Cada celda almacena un valor de 0 a 255 que puede representar:

ValorUso típico
0Suelo vacío / transitable
1Pared / obstáculo
2-254Diferentes tipos de terreno o estados
255Reservado para "inalcanzable" en mapas de distancia

Movimiento toroidal (Wrap)

Cuando permitirWrap es true, los bordes de la cuadrícula se conectan:

  • Moverse a la derecha desde la última columna lleva a la primera columna
  • Moverse hacia abajo desde la última fila lleva a la primera fila

Esto es útil para juegos estilo Pac-Man donde el personaje puede atravesar los bordes del mapa.

// Mapa con bordes conectados
var camino = mapa.findPath(0, 5, 19, 5, [0, 1, 2, 3, 5], true)

Complejidad algorítmica

Todas las operaciones de pathfinding usan BFS con complejidad O(W×H), donde W es el ancho y H es el alto de la cuadrícula.

Ejemplo completo: Juego estilo Pac-Man

use GridMap
use Display
use Bitmap
use Sprite

Display.open(320, 240)
var draw = Display.draw

// Crear mapa del laberinto (20x15 celdas de 16x16 píxeles)
var mapa = GridMap.new(20, 15)

// 0 = pasillo, 1 = pared, 5 = punto/píldora
// Configurar paredes del laberinto
for (var x = 0; x < 20; x++)
mapa.setCell(x, 0, 1) // Pared superior
mapa.setCell(x, 14, 1) // Pared inferior
end
for (var y = 0; y < 15; y++)
mapa.setCell(0, y, 1) // Pared izquierda
mapa.setCell(19, y, 1) // Pared derecha
end

// Añadir paredes internas
mapa.setCell(5, 5, 1)
mapa.setCell(5, 6, 1)
mapa.setCell(5, 7, 1)
mapa.setCell(14, 5, 1)
mapa.setCell(14, 6, 1)
mapa.setCell(14, 7, 1)

// Colocar puntos en los pasillos
for (var y = 1; y < 14; y++)
for (var x = 1; x < 19; x++)
if (mapa.getCell(x, y) == 0) then
mapa.setCell(x, y, 5) // Punto
end
end
end

// Cargar sprites
var tilePared = Bitmap.load("pared.bmp")
var tilePunto = Bitmap.load("punto.bmp")
var spriteJugador = Sprite.load("pacman.spr")
var spriteFantasma = Sprite.load("fantasma.spr")

// Posiciones iniciales
var jugadorX = 1
var jugadorY = 1
var fantasmaX = 10
var fantasmaY = 7

var puntuacion = 0

while (true)
// Entrada del jugador (simplificada)
var dx = 0
var dy = 0
// ... leer entrada GPIO o teclado ...

// Mover jugador si la celda destino no es pared
var nuevoX = jugadorX + dx
var nuevoY = jugadorY + dy

if (mapa.getCell(nuevoX, nuevoY) != 1) then
jugadorX = nuevoX
jugadorY = nuevoY

// Recoger punto
if (mapa.getCell(jugadorX, jugadorY) == 5) then
mapa.setCell(jugadorX, jugadorY, 0)
puntuacion = puntuacion + 10
end
end

// IA del fantasma: perseguir al jugador
var camino = mapa.findPath(fantasmaX, fantasmaY, jugadorX, jugadorY)
if (camino != nil and len(camino) > 1) then
fantasmaX = camino[1][0]
fantasmaY = camino[1][1]
end

// Dibujar
draw.cls(0x000000)

// Dibujar mapa
for (var y = 0; y < 15; y++)
for (var x = 0; x < 20; x++)
var valor = mapa.getCell(x, y)
if (valor == 1) then
draw.bitmap(tilePared, x * 16, y * 16)
elsif (valor == 5) then
draw.bitmap(tilePunto, x * 16, y * 16)
end
end
end

// Dibujar personajes
spriteJugador.pos(jugadorX * 16, jugadorY * 16)
spriteFantasma.pos(fantasmaX * 16, fantasmaY * 16)
draw.sprite(spriteJugador)
draw.sprite(spriteFantasma)

// UI
draw.text(5, 225, "Puntos: " + puntuacion, 0xFFFFFF)

// Detectar colisión jugador-fantasma
if (jugadorX == fantasmaX and jugadorY == fantasmaY) then
draw.text(100, 120, "GAME OVER", 0xFF0000)
end

Display.update()
pause(100)
end

Uso con el módulo Draw

El módulo Draw incluye la función gridBitmap para renderizar eficientemente cuadrículas:

use GridMap
use Bitmap
use Display

Display.open(320, 240)
var draw = Display.draw

var mapa = GridMap.new(20, 15)
// ... configurar mapa ...

var tilePared = Bitmap.load("pared.bmp")
var tileSuelo = Bitmap.load("suelo.bmp")

// Dibujar todas las paredes de una vez
draw.gridBitmap(mapa, 1, tilePared, 0, 0, 16, 16)

// Dibujar todo el suelo
draw.gridBitmap(mapa, 0, tileSuelo, 0, 0, 16, 16)

Display.update()

Consideraciones de rendimiento

Memoria y rendimiento
  • Una cuadrícula de 100×100 ocupa aproximadamente 10 KB
  • Las operaciones de pathfinding son O(W×H), considera el tamaño del mapa para aplicaciones en tiempo real
  • Usa buildDistanceMap cuando necesites calcular distancias desde múltiples puntos de forma eficiente

Plataformas soportadas

PlataformaSoporteNotas
Windows (SDL2)Soporte completo
ESP32Soporte completo
Emscripten (Web)Soporte completo
SiFive🚧En desarrollo