Ladders

Ready to add vertical exploration to your game world? 🪜 Ladders are one of the most iconic platformer mechanics - think Donkey Kong’s construction sites, Mega Man’s industrial levels, or any classic 2D adventure! You’re about to give your players the freedom to climb up and down through your levels, opening up incredible possibilities for level design!

Controls: Arrow Keys to move, Up/Down to climb ladders
Try this: Use the brown ladders to climb between platforms!

Understanding Ladder Types: Design Choices Matter!

Ladders might seem simple, but there are important design decisions to make! Let’s break down the different types:

🧱 Type A - Wall Ladders: Ladder inside a solid wall tile

🚶 Type B - Walkable Ladders: Ladder tile that’s also walkable

⬆️ Type C - Top-only Ladders: No ladder below, only above

❓ Type D - Floating Ladders: Ladder that ends in mid-air

Different ladder types and their behaviors

Why these distinctions matter: Each type creates different gameplay feelings and level design possibilities. Choose based on how you want players to move through your world!

The Ladder Rules: Clear Gameplay Guidelines

Before we code, let’s establish crystal-clear rules for how ladders work in our game:

Rule 1: Hero climbs using Up/Down arrow keys (intuitive controls!)

Rule 2: Can climb UP if ladder exists at hero’s current position OR above

Rule 3: Can climb DOWN if ladder exists below hero’s destination

Rule 4: Can move LEFT/RIGHT off ladder if no walls block the path

Rule 5: Cannot jump while climbing (climbing mode vs jumping mode)

Why these rules work:

These rules create the solid foundation for responsive, bug-free ladder mechanics!

Creating Ladder Tiles: Modern Implementation

Time to set up our ladder system using clean, modern JavaScript patterns:

// Tile type constants
const TILE_TYPES = {
    EMPTY: 0,
    SOLID: 1,
    LADDER: 2,
    LADDER_SOLID: 3  // Ladder you can also walk on
};

// Tile properties
const tileProperties = {
    [TILE_TYPES.EMPTY]: {
        solid: false,
        climbable: false,
        walkable: true
    },
    [TILE_TYPES.SOLID]: {
        solid: true,
        climbable: false, 
        walkable: false
    },
    [TILE_TYPES.LADDER]: {
        solid: false,
        climbable: true,
        walkable: false  // Can't walk through, only climb
    },
    [TILE_TYPES.LADDER_SOLID]: {
        solid: false,
        climbable: true,
        walkable: true   // Can walk AND climb
    }
};

// Helper functions
function getTileProperties(tileType) {
    return tileProperties[tileType] || tileProperties[TILE_TYPES.EMPTY];
}

function isClimbable(x, y) {
    const tileType = getTileAt(x, y);
    return getTileProperties(tileType).climbable;
}

function isSolid(x, y) {
    const tileType = getTileAt(x, y);
    return getTileProperties(tileType).solid;
}

Why this approach rocks:

Input Handling: Climbing Controls

Let’s implement responsive climbing controls that feel natural:

function handleClimbingInput(player, keys) {
    if (player.isClimbing) {
        // Climbing mode - up/down movement
        if (keys['ArrowUp'] && canClimbUp(player)) {
            player.y -= player.climbSpeed;
            centerPlayerOnLadder(player);
        } else if (keys['ArrowDown'] && canClimbDown(player)) {
            player.y += player.climbSpeed;
            centerPlayerOnLadder(player);
        } else if (keys['ArrowLeft'] || keys['ArrowRight']) {
            // Try to exit ladder horizontally
            tryExitLadder(player, keys['ArrowLeft'] ? -1 : 1);
        }
    } else {
        // Normal mode - check for ladder entry
        if ((keys['ArrowUp'] || keys['ArrowDown']) && canStartClimbing(player)) {
            player.isClimbing = true;
            player.velocityY = 0; // Stop falling
            centerPlayerOnLadder(player);
        }
    }
}

function centerPlayerOnLadder(player) {
    // Snap player to center of ladder for clean movement
    const ladderCol = Math.floor((player.x + player.width/2) / TILE_SIZE);
    const ladderCenterX = ladderCol * TILE_SIZE + TILE_SIZE/2;
    player.x = ladderCenterX - player.width/2;
}

function tryExitLadder(player, direction) {
    const newX = player.x + direction * player.speed;
    
    // Check all four corners for wall collision
    const corners = [
        {x: newX, y: player.y},                           // Top-left
        {x: newX + player.width, y: player.y},            // Top-right  
        {x: newX, y: player.y + player.height},           // Bottom-left
        {x: newX + player.width, y: player.y + player.height} // Bottom-right
    ];
    
    // Only exit if no corners hit walls
    const canExit = corners.every(corner => !isSolid(corner.x, corner.y));
    
    if (canExit) {
        player.x = newX;
        player.isClimbing = false;
    }
}

Key features:

Ladder Detection: Smart Climbing Logic

Now for the core climbing detection system that makes everything work smoothly:

// Check if player can start climbing at current position
function canStartClimbing(player) {
    const centerX = player.x + player.width / 2;
    const centerY = player.y + player.height / 2;
    
    return isClimbable(centerX, centerY);
}

// Check if player can climb upward
function canClimbUp(player) {
    const centerX = player.x + player.width / 2;
    
    // Check current position and above
    const currentClimbable = isClimbable(centerX, player.y + player.height/2);
    const aboveClimbable = isClimbable(centerX, player.y - player.climbSpeed);
    
    return currentClimbable && (aboveClimbable || isClimbable(centerX, player.y));
}

// Check if player can climb downward  
function canClimbDown(player) {
    const centerX = player.x + player.width / 2;
    const futureY = player.y + player.height + player.climbSpeed;
    
    // Must have ladder where we're going
    return isClimbable(centerX, futureY);
}

// Main climbing physics update
function updateClimbing(player) {
    if (player.isClimbing) {
        // Disable gravity while climbing
        player.velocityY = 0;
        player.velocityX = 0;
        
        // Check if still on a ladder
        if (!canStartClimbing(player)) {
            player.isClimbing = false;
            // Resume normal physics
        }
    }
}

Visual Feedback System

Make climbing feel responsive with immediate visual feedback:

function updatePlayerVisuals(player) {
    // Change appearance based on state
    if (player.isClimbing) {
        player.sprite.tint = 0xFFFF99;  // Slight yellow tint
        // Could add climbing animation here
    } else {
        player.sprite.tint = 0xFFFFFF;  // Normal color
    }
    
    // Update sprite position
    player.sprite.x = player.x;
    player.sprite.y = player.y;
}

The magic happens when:

  1. 🎯 Player approaches laddercanStartClimbing() detects it
  2. ⬆️ Up/Down pressed → Enter climbing mode
  3. 🧲 Auto-center → Player snaps to ladder center
  4. 🚫 Gravity disabled → No falling while climbing
  5. 🚶 Left/Right pressed → Smart exit with collision checking
  6. Visual feedback → Player knows they’re in climb mode

🏆 Congratulations! You’ve just implemented professional-grade ladder mechanics! Your players can now explore vertically through your levels with smooth, responsive climbing. This opens up amazing possibilities for level design - multi-story buildings, underground caverns, sky-high towers!

Next up: Time to add some challenge with enemies! Next: Stupid Enemy