Skip to main content

Cómo usar el sistema de mapas

Este tutorial fue escrito en febrero de 2026, para la v2 del motor.

El motor tiene un sistema de tilemaps integrado. Colocas tiles en una cuadrícula con mset(), renderizas una capa entera con map(), y el motor se encarga del resto — sin bucles manuales por arrays 2D, sin llamar a spr() para cada celda.

Vamos a construir un campo de hierba, añadir capas para árboles, gestionar mapas separados para diferentes áreas, y desplazar la cámara por mundos más grandes que la pantalla de 128x128. Este tutorial se centra solo en construir niveles — nada de movimiento de jugador ni colisiones. Si quieres eso, el tutorial de plataformas lo cubre.

Todo el arte de tiles es del Kenney 1-Bit Pack (CC0 — libre para cualquier uso). Los tiles del pack son de 16x16, pero el motor trabaja con celdas de 8x8, así que cada tile se divide en cuatro sprites de cuadrante (_tl, _tr, _bl, _br) y se coloca como un bloque de 2x2. Un helper tile() se encarga de esto en todo el tutorial — le pasas una posición y un nombre de tile, y llama a mset() cuatro veces.

Tu primer tilemap

mset(x, y, tile) coloca un sprite en una posición de celda por nombre. La pantalla es de 128x128 píxeles y cada celda es de 8x8. Nuestros tiles compuestos son de 16x16 — dos celdas de ancho, dos de alto — así que tenemos una cuadrícula de 8x8 tiles. El helper tile() coloca los cuatro cuadrantes en una sola llamada. Vamos a llenar la cuadrícula con hierba y trazar un camino de tierra:

engine.scope(({ start, cls, mset, map }) => {
    const sprites = {
        grass_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0,  0,  0,  0,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0,  0,  0, 11, 11,  0,
              0,  0, 11,  0,  0,  0, 11,  0,
        ], null],
        grass_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
            11, 11,  0,  0,  0,  0, 11,  0,
            11,  0,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
        ], null],
        grass_bl: [[
              0, 11, 11,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0, 11,  0,  0,  0,  0, 11, 11,
              0, 11, 11,  0,  0,  0,  0, 11,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        grass_br: [[
              0,  0, 11,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0, 11,  0,  0,
              0, 11,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  5,  0,  5,
              0,  0,  5,  0,  0,  0,  0,  0,
              0,  0,  5,  5,  0,  0,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              5,  0,  0,  0,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  0,  0,  0,
        ], null],
        dirt_bl: [[
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  5,  0,  0,  5,  5,  0,
              0,  0,  5,  5,  0,  5,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_br: [[
              0,  5,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  5,  0,  0,  0,
              0,  0,  0,  0,  5,  5,  0,  0,
              5,  0,  0,  0,  0,  5,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
    };

    function tile(tx, ty, name, layer = 0, mapId) {
        const cx = tx * 2, cy = ty * 2;
        mset(cx, cy, name + '_tl', layer, mapId);
        mset(cx + 1, cy, name + '_tr', layer, mapId);
        mset(cx, cy + 1, name + '_bl', layer, mapId);
        mset(cx + 1, cy + 1, name + '_br', layer, mapId);
    }

    function init() {
        for (let y = 0; y < 8; y++) {
            for (let x = 0; x < 8; x++) {
                tile(x, y, 'grass');
            }
        }
        for (let x = 0; x < 8; x++) { tile(x, 3, 'dirt'); }
        for (let y = 0; y < 8; y++) { tile(3, y, 'dirt'); }
    }

    function draw() {
        cls(0);
        map(0);
    }

    start({ sprites, sounds: {}, init, draw, target });
});
Map System: First Tilemap
Un campo de hierba con un cruce de tierra renderizado completamente desde datos de tilemap

Dos bucles anidados llenan cada posición con hierba. Otros dos sobreescriben la fila y columna del medio con tierra, formando una cruz. Cada llamada a tile() coloca cuatro sprites de 8x8 en un bloque de 2x2 — las matemáticas de cuadrante son internas. cls(0) limpia a negro y map(0) renderiza cada celda en la capa 0. Estableces los datos una vez en init() y persisten entre fotogramas.

Añadir capas

Las capas son cuadrículas separadas que comparten el mismo espacio de coordenadas. La capa 0 es el suelo. La capa 1 va encima — árboles, edificios, cualquier cosa que deba dibujarse sobre el terreno. El cuarto argumento de tile() (que lo pasa a mset()) establece la capa:

engine.scope(({ start, cls, mset, map }) => {
    const sprites = {
        grass_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0,  0,  0,  0,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0,  0,  0, 11, 11,  0,
              0,  0, 11,  0,  0,  0, 11,  0,
        ], null],
        grass_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
            11, 11,  0,  0,  0,  0, 11,  0,
            11,  0,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
        ], null],
        grass_bl: [[
              0, 11, 11,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0, 11,  0,  0,  0,  0, 11, 11,
              0, 11, 11,  0,  0,  0,  0, 11,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        grass_br: [[
              0,  0, 11,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0, 11,  0,  0,
              0, 11,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  5,  0,  5,
              0,  0,  5,  0,  0,  0,  0,  0,
              0,  0,  5,  5,  0,  0,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              5,  0,  0,  0,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  0,  0,  0,
        ], null],
        dirt_bl: [[
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  5,  0,  0,  5,  5,  0,
              0,  0,  5,  5,  0,  5,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_br: [[
              0,  5,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  5,  0,  0,  0,
              0,  0,  0,  0,  5,  5,  0,  0,
              5,  0,  0,  0,  0,  5,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        tree1_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
        ], null],
        tree1_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, 11, 11, 11, 11, -1, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
        ], null],
        tree1_bl: [[
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, -1, 11, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, 11, -1, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree1_br: [[
            11, 11, 11, 11, 11, 11, -1, -1,
            -1, -1, -1, -1, 11, -1, -1, -1,
            11, -1, 11, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree2_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
        ], null],
        tree2_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
        ], null],
        tree2_bl: [[
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree2_br: [[
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
    };

    function tile(tx, ty, name, layer = 0, mapId) {
        const cx = tx * 2, cy = ty * 2;
        mset(cx, cy, name + '_tl', layer, mapId);
        mset(cx + 1, cy, name + '_tr', layer, mapId);
        mset(cx, cy + 1, name + '_bl', layer, mapId);
        mset(cx + 1, cy + 1, name + '_br', layer, mapId);
    }

    function init() {
        for (let y = 0; y < 8; y++) {
            for (let x = 0; x < 8; x++) {
                tile(x, y, 'grass');
            }
        }
        for (let x = 0; x < 8; x++) { tile(x, 3, 'dirt'); }
        for (let y = 0; y < 8; y++) { tile(3, y, 'dirt'); }

        tile(1, 1, 'tree1', 1);
        tile(6, 1, 'tree2', 1);
        tile(2, 5, 'tree1', 1);
        tile(5, 2, 'tree2', 1);
        tile(0, 6, 'tree1', 1);
        tile(6, 6, 'tree2', 1);
        tile(2, 2, 'tree2', 1);
    }

    function draw() {
        cls(0);
        map(0);
        map(1);
    }

    start({ sprites, sounds: {}, init, draw, target });
});
Map System: Adding Layers
Árboles en la capa 1 dibujados sobre la hierba y tierra de la capa 0

La capa 0 se renderiza primero, la capa 1 se dibuja encima. Los sprites de árboles usan -1 (transparente) para los píxeles vacíos, así que el suelo se ve a través donde no hay follaje.

El orden de dibujo importa:

// inside draw()
cls(0);
map(0); // ground layer renders first
map(1); // object layer renders on top

Consejo: Puedes usar tantas capas como necesites. Una configuración común es capa 0 para el suelo, capa 1 para objetos y capa 2 para elementos superiores como copas de árboles que se renderizan delante del sprite del jugador.

Configurar múltiples mapas

Hasta ahora todo ha ido al mapa por defecto. Pero mset() acepta un quinto argumento — una cadena mapId que nombra el mapa. Nuestro helper tile() lo pasa directamente, así que tile(x, y, 'grass', 0, 'forest') coloca hierba en el mapa del bosque. Cada mapId tiene su propia cuadrícula de tiles con sus propias capas. Si lo omites, el motor usa 'default'.

Vamos a llenar dos mapas — un bosque y una aldea — cada uno con sus propias capas de suelo y objetos:

// inside init()

// --- forest map ---
for (let y = 0; y < 8; y++) {
    for (let x = 0; x < 8; x++) {
        tile(x, y, 'grass', 0, 'forest');
    }
}
for (let x = 0; x < 8; x++) { tile(x, 3, 'dirt', 0, 'forest'); }
tile(1, 1, 'tree1', 1, 'forest');
tile(6, 1, 'tree2', 1, 'forest');
tile(2, 5, 'tree1', 1, 'forest');
tile(5, 2, 'tree2', 1, 'forest');

// --- village map ---
for (let y = 0; y < 8; y++) {
    for (let x = 0; x < 8; x++) {
        tile(x, y, 'stone', 0, 'village');
    }
}
for (let x = 0; x < 8; x++) { tile(x, 4, 'dirt', 0, 'village'); }
tile(1, 1, 'house', 1, 'village');
tile(5, 2, 'house', 1, 'village');

Los datos permanecen en memoria hasta que los limpies con mclear(). Ambos mapas usan las mismas definiciones de sprites — solo almacenan diferentes diseños de tiles.

Cambiar entre mapas

Ahora que tenemos dos mapas en memoria, vamos a cambiar entre ellos en tiempo de ejecución — pulsa 1 para el bosque, 2 para la aldea. Lo único que cambia es qué mapId pasamos a map():

engine.scope(({ start, cls, mset, map, rectfill, text, btnp }) => {
    const sprites = {
        grass_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0,  0,  0,  0,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0,  0,  0, 11, 11,  0,
              0,  0, 11,  0,  0,  0, 11,  0,
        ], null],
        grass_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
            11, 11,  0,  0,  0,  0, 11,  0,
            11,  0,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
        ], null],
        grass_bl: [[
              0, 11, 11,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0, 11,  0,  0,  0,  0, 11, 11,
              0, 11, 11,  0,  0,  0,  0, 11,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        grass_br: [[
              0,  0, 11,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0, 11,  0,  0,
              0, 11,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  5,  0,  5,
              0,  0,  5,  0,  0,  0,  0,  0,
              0,  0,  5,  5,  0,  0,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              5,  0,  0,  0,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  0,  0,  0,
        ], null],
        dirt_bl: [[
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  5,  0,  0,  5,  5,  0,
              0,  0,  5,  5,  0,  5,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_br: [[
              0,  5,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  5,  0,  0,  0,
              0,  0,  0,  0,  5,  5,  0,  0,
              5,  0,  0,  0,  0,  5,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        water_tl: [[
              0,  0, 12, 12, 12, 12, 12, 12,
              0,  0,  0, 12, 12, 12, 12, 12,
            12,  0,  0, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_tr: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_bl: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_br: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        stone_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  6,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  6,  6,  6,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  6,  6,
              0,  6,  0,  6,  6,  0,  6,  6,
        ], null],
        stone_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              6,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              6,  6,  0,  6,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  6,  0,  6,  0,  6,  6,  0,
              0,  0,  6,  0,  0,  0,  0,  0,
        ], null],
        stone_bl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  6,  6,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  6,
              0,  0,  0,  0,  0,  6,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        stone_br: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              6,  0,  0,  6,  6,  0,  0,  0,
              0,  6,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  6,  0,  0,  0,  0,
              6,  6,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        tree1_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
        ], null],
        tree1_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, 11, 11, 11, 11, -1, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
        ], null],
        tree1_bl: [[
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, -1, 11, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, 11, -1, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree1_br: [[
            11, 11, 11, 11, 11, 11, -1, -1,
            -1, -1, -1, -1, 11, -1, -1, -1,
            11, -1, 11, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree2_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
        ], null],
        tree2_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
        ], null],
        tree2_bl: [[
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree2_br: [[
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        house_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1,  8,
            -1, -1, -1, -1, -1,  8,  8, -1,
            -1, -1, -1,  8,  8, -1, -1, -1,
            -1, -1,  8, -1, -1, -1, -1, -1,
            -1,  8, -1, -1, -1, -1, -1, -1,
            -1,  8, -1, -1, -1, -1, -1, -1,
            -1,  8, -1, -1, -1, -1, -1,  8,
        ], null],
        house_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
              8, -1, -1, -1, -1, -1, -1, -1,
            -1,  8, -1, -1, -1, -1, -1, -1,
            -1,  8,  8, -1, -1, -1, -1, -1,
            -1, -1,  8,  8, -1, -1, -1, -1,
            -1, -1,  8,  8,  8, -1, -1, -1,
            -1, -1, -1,  8,  8,  8, -1, -1,
            -1, -1, -1,  8,  8,  8,  8, -1,
        ], null],
        house_bl: [[
            -1,  8, -1, -1, -1,  8,  8, -1,
            -1,  8, -1,  8,  8, -1, -1,  8,
            -1,  8,  8, -1, -1,  8,  8,  8,
            -1,  8, -1,  8,  8,  8,  8,  8,
            -1, -1,  8,  8, -1,  8,  8, -1,
            -1, -1,  8,  8, -1,  8,  8, -1,
            -1, -1,  8,  8,  8,  8,  8, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        house_br: [[
            -1,  8,  8,  8,  8,  8,  8, -1,
              8, -1, -1,  8,  8,  8,  8, -1,
              8,  8,  8, -1, -1,  8,  8, -1,
              8,  8,  8,  8,  8, -1,  8, -1,
            -1,  8,  8, -1,  8,  8, -1, -1,
            -1,  8,  8, -1,  8,  8, -1, -1,
            -1,  8,  8,  8,  8,  8, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
    };

    let currentMap = 'forest';

    function tile(tx, ty, name, layer = 0, mapId) {
        const cx = tx * 2, cy = ty * 2;
        mset(cx, cy, name + '_tl', layer, mapId);
        mset(cx + 1, cy, name + '_tr', layer, mapId);
        mset(cx, cy + 1, name + '_bl', layer, mapId);
        mset(cx + 1, cy + 1, name + '_br', layer, mapId);
    }

    function init() {
        for (let y = 0; y < 8; y++) {
            for (let x = 0; x < 8; x++) {
                tile(x, y, 'grass', 0, 'forest');
            }
        }
        for (let x = 0; x < 8; x++) { tile(x, 3, 'dirt', 0, 'forest'); }
        for (let y = 0; y < 8; y++) { tile(3, y, 'dirt', 0, 'forest'); }
        tile(6, 6, 'water', 0, 'forest');
        tile(1, 1, 'tree1', 1, 'forest'); tile(6, 1, 'tree2', 1, 'forest');
        tile(2, 5, 'tree1', 1, 'forest'); tile(5, 2, 'tree2', 1, 'forest');
        tile(0, 6, 'tree1', 1, 'forest'); tile(2, 2, 'tree2', 1, 'forest');

        for (let y = 0; y < 8; y++) {
            for (let x = 0; x < 8; x++) {
                tile(x, y, 'stone', 0, 'village');
            }
        }
        for (let x = 0; x < 8; x++) { tile(x, 4, 'dirt', 0, 'village'); }
        for (let y = 0; y < 8; y++) { tile(2, y, 'dirt', 0, 'village'); }
        tile(1, 1, 'house', 1, 'village'); tile(5, 1, 'house', 1, 'village');
        tile(5, 6, 'house', 1, 'village');
        tile(1, 6, 'tree1', 1, 'village'); tile(6, 3, 'tree1', 1, 'village');
    }

    function update() {
        if (btnp('1')) currentMap = 'forest';
        if (btnp('2')) currentMap = 'village';
    }

    function draw() {
        cls(0);
        map(0, 0, 0, undefined, undefined, 0, 0, currentMap);
        map(1, 0, 0, undefined, undefined, 0, 0, currentMap);
        rectfill(0, 0, 78, 15, 0);
        text(currentMap, 1, 1, 7);
        text('1=forest 2=village', 1, 8, 6);
    }

    start({ sprites, sounds: {}, init, update, draw, target });
});
Map System: Switching Maps
Pulsa 1 para bosque o 2 para aldea — ambos mapas comparten los mismos sprites de tiles

Al pasar un mapId a map(), necesitas rellenar todos los argumentos anteriores. La firma completa es map(layer, cellX, cellY, cellW, cellH, screenX, screenY, mapId). Para mapas del tamaño de pantalla, pasa undefined para cellW y cellH — el motor los calcula automáticamente.

Desplazamiento con la cámara

Una cuadrícula de 8x8 tiles llena la pantalla exactamente — no hay espacio para desplazarse. Vamos a hacer el mapa más grande y usar camera() para recorrerlo. Este es de 16x12 tiles (32x24 celdas — 256x192 píxeles), dando 128 píxeles de desplazamiento horizontal y 64 de vertical:

engine.scope(({ start, cls, mset, map, rectfill, text, btn, camera, creset }) => {
    const sprites = {
        grass_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0,  0,  0,  0,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0,  0,  0, 11, 11,  0,
              0,  0, 11,  0,  0,  0, 11,  0,
        ], null],
        grass_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
            11, 11,  0,  0,  0,  0, 11,  0,
            11,  0,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
        ], null],
        grass_bl: [[
              0, 11, 11,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0, 11,  0,  0,  0,  0, 11, 11,
              0, 11, 11,  0,  0,  0,  0, 11,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        grass_br: [[
              0,  0, 11,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0, 11,  0,  0,
              0, 11,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  5,  0,  5,
              0,  0,  5,  0,  0,  0,  0,  0,
              0,  0,  5,  5,  0,  0,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              5,  0,  0,  0,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  0,  0,  0,
        ], null],
        dirt_bl: [[
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  5,  0,  0,  5,  5,  0,
              0,  0,  5,  5,  0,  5,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_br: [[
              0,  5,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  5,  0,  0,  0,
              0,  0,  0,  0,  5,  5,  0,  0,
              5,  0,  0,  0,  0,  5,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        water_tl: [[
              0,  0, 12, 12, 12, 12, 12, 12,
              0,  0,  0, 12, 12, 12, 12, 12,
            12,  0,  0, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_tr: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_bl: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_br: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        tree1_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
        ], null],
        tree1_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, 11, 11, 11, 11, -1, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
        ], null],
        tree1_bl: [[
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, -1, 11, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, 11, -1, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree1_br: [[
            11, 11, 11, 11, 11, 11, -1, -1,
            -1, -1, -1, -1, 11, -1, -1, -1,
            11, -1, 11, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree2_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
        ], null],
        tree2_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
        ], null],
        tree2_bl: [[
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree2_br: [[
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
    };

    const mapW = 32, mapH = 24;
    let camX = 0, camY = 0;
    const camSpeed = 2;

    function tile(tx, ty, name, layer = 0, mapId) {
        const cx = tx * 2, cy = ty * 2;
        mset(cx, cy, name + '_tl', layer, mapId);
        mset(cx + 1, cy, name + '_tr', layer, mapId);
        mset(cx, cy + 1, name + '_bl', layer, mapId);
        mset(cx + 1, cy + 1, name + '_br', layer, mapId);
    }

    function init() {
        for (let y = 0; y < 12; y++) {
            for (let x = 0; x < 16; x++) {
                tile(x, y, 'grass');
            }
        }
        for (let x = 0; x < 16; x++) { tile(x, 5, 'dirt'); }
        for (let y = 0; y < 12; y++) { tile(7, y, 'dirt'); }
        for (let x = 10; x < 13; x++) {
            for (let y = 9; y < 11; y++) {
                tile(x, y, 'water');
            }
        }
        tile(1, 1, 'tree1', 1); tile(2, 2, 'tree2', 1);
        tile(5, 2, 'tree1', 1); tile(14, 1, 'tree2', 1);
        tile(1, 8, 'tree1', 1); tile(4, 10, 'tree2', 1);
        tile(12, 3, 'tree1', 1); tile(15, 7, 'tree2', 1);
        tile(0, 4, 'tree2', 1); tile(6, 11, 'tree1', 1);
        tile(13, 4, 'tree1', 1); tile(9, 2, 'tree2', 1);
    }

    function update() {
        if (btn('a') || btn('ArrowLeft')) camX -= camSpeed;
        if (btn('d') || btn('ArrowRight')) camX += camSpeed;
        if (btn('w') || btn('ArrowUp')) camY -= camSpeed;
        if (btn('s') || btn('ArrowDown')) camY += camSpeed;
        camX = Math.max(0, Math.min(mapW * 8 - 128, camX));
        camY = Math.max(0, Math.min(mapH * 8 - 128, camY));
    }

    function draw() {
        cls(0);
        camera(camX, camY);
        map(0, 0, 0, mapW, mapH);
        map(1, 0, 0, mapW, mapH);
        creset();
        rectfill(0, 0, 68, 15, 0);
        text('WASD to scroll', 1, 1, 7);
        text(camX + ',' + camY, 1, 8, 6);
    }

    start({ sprites, sounds: {}, init, update, draw, target });
});
Map System: Camera Scrolling
WASD para desplazar la cámara por un mapa de 16x12 tiles más grande que la pantalla

camera(x, y) desplaza todo el dibujo por esa cantidad. Los tiles fuera de la pantalla de 128x128 se recortan automáticamente. Las matemáticas de clamp evitan que la cámara se desplace más allá de los bordes del mapa.

Pasamos mapW y mapH a map() explícitamente — están en unidades de celda (32x24), no de tile. Las dimensiones de celda auto-calculadas (17x17) solo cubren la región del tamaño de pantalla. Con desplazamiento de cámara, las celdas visibles pueden extenderse mucho más allá, así que necesitas el tamaño completo del mapa.

Llama a creset() antes de dibujar texto del HUD para que permanezca fijo en pantalla en vez de desplazarse con el mundo:

// inside draw()
camera(camX, camY);
map(0, 0, 0, mapW, mapH);
map(1, 0, 0, mapW, mapH);

creset();
text('Forest', 1, 1, 7);

Consejo: El motor renderiza cada tile que le pidas, incluyendo los que están fuera de pantalla — simplemente se recortan en los bordes. Para mapas pequeños (menos de ~64x64 tiles) está bien. Para mapas muy grandes, pasa cellX, cellY, cellW, cellH a map() para renderizar solo la región visible: map(0, Math.floor(camX / 8), Math.floor(camY / 8), 17, 17).

Juntándolo todo

Vamos a combinar todo: dos mapas desplazables multicapa (16x12 tiles cada uno), pulsa 1/2 para cambiar, WASD para desplazar, y un HUD mostrando en qué mapa estás. La cámara se reinicia a (0, 0) al cambiar de mapa para que siempre empieces en la esquina superior izquierda:

engine.scope(({ start, cls, mset, map, rectfill, text, btn, btnp, camera, creset }) => {
    const sprites = {
        grass_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0,  0,  0,  0,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0,  0,  0, 11, 11,  0,
              0,  0, 11,  0,  0,  0, 11,  0,
        ], null],
        grass_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
            11, 11,  0,  0,  0,  0, 11,  0,
            11,  0,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0, 11,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
        ], null],
        grass_bl: [[
              0, 11, 11,  0,  0,  0,  0,  0,
              0, 11,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0, 11,  0,  0,  0,  0, 11, 11,
              0, 11, 11,  0,  0,  0,  0, 11,
              0,  0, 11,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        grass_br: [[
              0,  0, 11,  0,  0,  0,  0,  0,
              0, 11, 11,  0,  0, 11,  0,  0,
              0, 11,  0,  0,  0, 11, 11,  0,
              0,  0,  0,  0,  0,  0, 11,  0,
              0,  0,  0,  0, 11,  0,  0,  0,
              0,  0,  0, 11, 11,  0,  0,  0,
              0,  0,  0, 11,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  5,  0,  5,
              0,  0,  5,  0,  0,  0,  0,  0,
              0,  0,  5,  5,  0,  0,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  5,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              5,  0,  0,  0,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  5,  0,  0,
              5,  5,  0,  5,  5,  0,  0,  0,
        ], null],
        dirt_bl: [[
              0,  5,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  5,  0,
              0,  0,  5,  0,  0,  5,  5,  0,
              0,  0,  5,  5,  0,  5,  0,  0,
              0,  0,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        dirt_br: [[
              0,  5,  0,  5,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  5,  0,  0,  0,
              0,  0,  0,  0,  5,  5,  0,  0,
              5,  0,  0,  0,  0,  5,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        water_tl: [[
              0,  0, 12, 12, 12, 12, 12, 12,
              0,  0,  0, 12, 12, 12, 12, 12,
            12,  0,  0, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_tr: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_bl: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        water_br: [[
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
            12, 12, 12, 12, 12, 12, 12, 12,
        ], null],
        stone_tl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  6,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  6,  6,  6,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  6,  6,
              0,  6,  0,  6,  6,  0,  6,  6,
        ], null],
        stone_tr: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              6,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              6,  6,  0,  6,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  6,  0,  6,  0,  6,  6,  0,
              0,  0,  6,  0,  0,  0,  0,  0,
        ], null],
        stone_bl: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  6,  6,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  6,
              0,  0,  0,  0,  0,  6,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        stone_br: [[
              0,  0,  0,  0,  0,  0,  0,  0,
              6,  0,  0,  6,  6,  0,  0,  0,
              0,  6,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  6,  0,  0,  0,  0,
              6,  6,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
              0,  0,  0,  0,  0,  0,  0,  0,
        ], null],
        tree1_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, 11, 11, 11, 11, 11, 11,
        ], null],
        tree1_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, 11, 11, 11, 11, -1, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
            11, 11, 11, 11, 11, 11, -1, -1,
        ], null],
        tree1_bl: [[
            -1, -1, 11, 11, 11, 11, 11, 11,
            -1, -1, -1, 11, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, 11, -1, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree1_br: [[
            11, 11, 11, 11, 11, 11, -1, -1,
            -1, -1, -1, -1, 11, -1, -1, -1,
            11, -1, 11, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree2_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, -1, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
        ], null],
        tree2_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, 11, -1, -1, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
        ], null],
        tree2_bl: [[
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, 11, 11, 11, 11,
            -1, -1, -1, -1, -1, 11, 11, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, 11,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        tree2_br: [[
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, 11, -1, -1, -1, -1,
            11, 11, 11, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            11, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        house_tl: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
            -1, -1, -1, -1, -1, -1, -1,  8,
            -1, -1, -1, -1, -1,  8,  8, -1,
            -1, -1, -1,  8,  8, -1, -1, -1,
            -1, -1,  8, -1, -1, -1, -1, -1,
            -1,  8, -1, -1, -1, -1, -1, -1,
            -1,  8, -1, -1, -1, -1, -1, -1,
            -1,  8, -1, -1, -1, -1, -1,  8,
        ], null],
        house_tr: [[
            -1, -1, -1, -1, -1, -1, -1, -1,
              8, -1, -1, -1, -1, -1, -1, -1,
            -1,  8, -1, -1, -1, -1, -1, -1,
            -1,  8,  8, -1, -1, -1, -1, -1,
            -1, -1,  8,  8, -1, -1, -1, -1,
            -1, -1,  8,  8,  8, -1, -1, -1,
            -1, -1, -1,  8,  8,  8, -1, -1,
            -1, -1, -1,  8,  8,  8,  8, -1,
        ], null],
        house_bl: [[
            -1,  8, -1, -1, -1,  8,  8, -1,
            -1,  8, -1,  8,  8, -1, -1,  8,
            -1,  8,  8, -1, -1,  8,  8,  8,
            -1,  8, -1,  8,  8,  8,  8,  8,
            -1, -1,  8,  8, -1,  8,  8, -1,
            -1, -1,  8,  8, -1,  8,  8, -1,
            -1, -1,  8,  8,  8,  8,  8, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
        house_br: [[
            -1,  8,  8,  8,  8,  8,  8, -1,
              8, -1, -1,  8,  8,  8,  8, -1,
              8,  8,  8, -1, -1,  8,  8, -1,
              8,  8,  8,  8,  8, -1,  8, -1,
            -1,  8,  8, -1,  8,  8, -1, -1,
            -1,  8,  8, -1,  8,  8, -1, -1,
            -1,  8,  8,  8,  8,  8, -1, -1,
            -1, -1, -1, -1, -1, -1, -1, -1,
        ], null],
    };

    const maps = {
        forest: { w: 32, h: 24 },
        village: { w: 32, h: 24 },
    };
    let currentMap = 'forest';
    let camX = 0, camY = 0;
    const camSpeed = 2;

    function tile(tx, ty, name, layer = 0, mapId) {
        const cx = tx * 2, cy = ty * 2;
        mset(cx, cy, name + '_tl', layer, mapId);
        mset(cx + 1, cy, name + '_tr', layer, mapId);
        mset(cx, cy + 1, name + '_bl', layer, mapId);
        mset(cx + 1, cy + 1, name + '_br', layer, mapId);
    }

    function init() {
        for (let y = 0; y < 12; y++) {
            for (let x = 0; x < 16; x++) {
                tile(x, y, 'grass', 0, 'forest');
            }
        }
        for (let x = 0; x < 16; x++) { tile(x, 5, 'dirt', 0, 'forest'); }
        for (let y = 0; y < 12; y++) { tile(7, y, 'dirt', 0, 'forest'); }
        for (let x = 10; x < 13; x++) {
            for (let y = 9; y < 11; y++) {
                tile(x, y, 'water', 0, 'forest');
            }
        }
        tile(1, 1, 'tree1', 1, 'forest'); tile(2, 2, 'tree2', 1, 'forest');
        tile(5, 2, 'tree1', 1, 'forest'); tile(14, 1, 'tree2', 1, 'forest');
        tile(1, 8, 'tree1', 1, 'forest'); tile(4, 10, 'tree2', 1, 'forest');
        tile(12, 3, 'tree1', 1, 'forest'); tile(15, 7, 'tree2', 1, 'forest');
        tile(0, 4, 'tree2', 1, 'forest'); tile(6, 11, 'tree1', 1, 'forest');
        tile(13, 4, 'tree1', 1, 'forest'); tile(9, 2, 'tree2', 1, 'forest');

        for (let y = 0; y < 12; y++) {
            for (let x = 0; x < 16; x++) {
                tile(x, y, 'stone', 0, 'village');
            }
        }
        for (let x = 0; x < 16; x++) { tile(x, 6, 'dirt', 0, 'village'); }
        for (let y = 0; y < 12; y++) { tile(4, y, 'dirt', 0, 'village'); tile(12, y, 'dirt', 0, 'village'); }
        tile(1, 1, 'house', 1, 'village'); tile(6, 1, 'house', 1, 'village');
        tile(10, 2, 'house', 1, 'village'); tile(14, 4, 'house', 1, 'village');
        tile(2, 8, 'house', 1, 'village'); tile(7, 9, 'house', 1, 'village');
        tile(1, 4, 'tree1', 1, 'village'); tile(15, 10, 'tree1', 1, 'village');
        tile(9, 7, 'tree2', 1, 'village'); tile(13, 1, 'tree2', 1, 'village');
    }

    function update() {
        if (btnp('1')) { currentMap = 'forest'; camX = 0; camY = 0; }
        if (btnp('2')) { currentMap = 'village'; camX = 0; camY = 0; }

        if (btn('a') || btn('ArrowLeft')) camX -= camSpeed;
        if (btn('d') || btn('ArrowRight')) camX += camSpeed;
        if (btn('w') || btn('ArrowUp')) camY -= camSpeed;
        if (btn('s') || btn('ArrowDown')) camY += camSpeed;

        const info = maps[currentMap];
        camX = Math.max(0, Math.min(info.w * 8 - 128, camX));
        camY = Math.max(0, Math.min(info.h * 8 - 128, camY));
    }

    function draw() {
        cls(0);
        camera(camX, camY);
        const info = maps[currentMap];
        map(0, 0, 0, info.w, info.h, 0, 0, currentMap);
        map(1, 0, 0, info.w, info.h, 0, 0, currentMap);
        creset();
        rectfill(0, 0, 78, 22, 0);
        text(currentMap, 1, 1, 7);
        text('1=forest 2=village', 1, 8, 6);
        text('WASD to scroll', 1, 15, 6);
    }

    start({ sprites, sounds: {}, init, update, draw, target });
});
Map System: Complete Example
Pulsa 1/2 para cambiar de mapa y WASD para desplazar — dos mundos multicapa desplazables

Para ir más allá

Algunas direcciones que podrías tomar:

  • Mapas procedurales — usa rnd() para esparcir tiles aleatoriamente para generación de terreno
  • Datos de mapa desde JSON — define cuadrículas de tiles como arrays 2D y recórrelos para llamar a mset()
  • Desplazamiento parallax — renderiza capas de fondo a una fracción de la velocidad de la cámara para dar profundidad
  • Tiles animados — intercambia sprites de tiles con un temporizador (por ejemplo, agua que ondula)
  • Colisión con tiles — combina mget() con código de movimiento para impedir que el jugador atraviese paredes (ver el tutorial de plataformas)