Open the Door

A single room is a demo. A connected world — rooms that lead to other rooms — is a game. This tutorial adds a multi-room system: each room is a map stored in an object, and door tiles trigger transitions between them.

Loading editor…

Walk into the yellow door tiles to move between rooms.

Multiple rooms

Each room is an entry in a rooms object keyed by room ID. The map array lives inside each room, alongside any other per-room data you need:

// Our room database - easy to expand!
const rooms = {
    1: {
        name: "Village Square",
        map: [
            [1, 1, 1, 1, 1, 1, 1, 1],
            [1, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 0, 0, 0, 0, 2, 1],  // Door (tile type 2)
            [1, 1, 1, 1, 1, 1, 1, 1]
        ],
        music: "village_theme.ogg",
        background: "#2c3e50"
    },
    
    2: {
        name: "Mysterious Cave", 
        map: [
            [1, 1, 1, 1, 1, 1, 1, 1],
            [1, 0, 0, 0, 0, 0, 0, 1],
            [1, 0, 1, 0, 0, 1, 0, 1],
            [1, 0, 0, 0, 0, 0, 0, 1],
            [3, 0, 0, 0, 0, 0, 0, 1],  // Different door (tile type 3)
            [1, 1, 1, 1, 1, 1, 1, 1]
        ],
        music: "cave_ambient.ogg",
        background: "#1a1a2e"
    }
};

// Door destinations - where each door type leads
const doors = {
    2: { 
        toRoom: 2, 
        playerX: 1, 
        playerY: 4,
        message: "Entering the mysterious cave..."
    },
    3: { 
        toRoom: 1, 
        playerX: 6, 
        playerY: 4,
        message: "Returning to the village..."
    }
};

// Game state manager
const gameState = {
    currentRoom: 1,
    previousRoom: null,
    transitionInProgress: false
};

All room data is in one place and each room can carry its own settings — background colour, music track, particle effects — without any other room needing to know about them.

Room transitions

Step 1: Door detection

// Check if player is standing on a door
function checkForDoors(hero, currentRoom) {
    const map = rooms[currentRoom].map;
    const tileType = map[hero.tileY][hero.tileX];
    
    // Is this tile a door?
    if (doors[tileType]) {
        return doors[tileType];
    }
    
    return null; // No door here
}

Step 2: Transition system

function transitionToRoom(doorData, hero, gameState, app) {
    // Prevent multiple rapid transitions
    if (gameState.transitionInProgress) return;
    
    gameState.transitionInProgress = true;
    
    // Optional: Show transition effect
    showTransitionEffect(doorData.message);
    
    // Update game state
    gameState.previousRoom = gameState.currentRoom;
    gameState.currentRoom = doorData.toRoom;
    
    // Move hero to new position
    hero.tileX = doorData.playerX;
    hero.tileY = doorData.playerY;
    
    // Rebuild the room
    buildRoom(gameState.currentRoom, app);
    
    // Re-enable transitions after a brief delay
    setTimeout(() => {
        gameState.transitionInProgress = false;
    }, 500);
}

function showTransitionEffect(message) {
    // Simple fade effect or message display
    console.log(message);
    
    // You could add visual effects here:
    // - Screen fade
    // - Flash effect  
    // - Loading animation
    // - Sound effects
}

Step 3: Integration with movement

function updateMovement(hero, keys, gameState, app) {
    // ... normal movement code ...
    
    // After successful movement, check for doors
    const doorData = checkForDoors(hero, gameState.currentRoom);
    if (doorData) {
        transitionToRoom(doorData, hero, gameState, app);
    }
}

Extended door types

The buildRoom function can read per-room properties to set background colour, start music, or trigger effects:

function buildRoom(roomId, app) {
    const room = rooms[roomId];
    
    app.stage.removeChildren();
    app.renderer.background.color = room.background || 0x2c3e50;
    
    renderMap(room.map, app);
    
    if (room.particles) addParticleEffects(room.particles, app);
    if (room.music)     playBackgroundMusic(room.music);
    
    displayRoomTitle(room.name, app);
}

// Doors with conditions
const specialDoors = {
    LOCKED: {
        canUse: (hero) => hero.hasKey,
        message: "This door is locked.",
        sound: "door_locked.ogg"
    },
    
    MAGIC: {
        canUse: (hero) => hero.mana >= 10,
        cost: { mana: 10 },
        effect: "sparkle"
    },
    
    TELEPORTER: {
        canUse: () => true,
        effect: "flash"
    }
};

// Smart door system
function tryUseDoor(tileType, hero) {
    const doorData = doors[tileType];
    if (!doorData) return false;
    
    // Check if door can be used
    if (doorData.special) {
        const specialType = specialDoors[doorData.special];
        if (!specialType.canUse(hero)) {
            showMessage(specialType.message);
            return false;
        }
        
        // Apply costs
        if (specialType.cost) {
            Object.assign(hero, specialType.cost);
        }
        
        // Show special effects
        if (specialType.effect) {
            playEffect(specialType.effect);
        }
    }
    
    return true; // Door can be used!
}

What you built:

  • A rooms object that stores each map alongside per-room settings
  • A doors lookup that maps tile values to destination rooms and spawn positions
  • A buildRoom function that clears the stage and renders the new room
  • A transition guard (transitionInProgress) to prevent double-triggers

Next: Locked Doors