DEV Community

Cover image for TCJSGame TileMap Class: Complete Reference Guide (Updated for v3)
Kehinde Owolabi
Kehinde Owolabi

Posted on

TCJSGame TileMap Class: Complete Reference Guide (Updated for v3)

TCJSGame TileMap Class: Complete Reference Guide (Updated for v3)

TileMap Systems

⚠️ Important v3 Updates

Critical Change: In TCJSGame v3, display.tileFace.show() must be called inside the update function for the TileMap to render properly each frame. Also, the engine automatically adds the null index with this.tile.unshift(0), so you don't need to include null in your tiles array.

🏗️ Basic TileMap Setup (v3 Corrected)

Creating Tile Definitions (No Null Needed)

// v3: No need to include null at index 0 - engine handles it automatically!
const tiles = [
    new Component(0, 0, "green", 0, 0, "rect"),  // Index 1 - Grass
    new Component(0, 0, "gray", 0, 0, "rect"),   // Index 2 - Stone wall
    new Component(0, 0, "blue", 0, 0, "rect"),   // Index 3 - Water
    new Component(0, 0, "brown", 0, 0, "rect"),  // Index 4 - Dirt
    new Component(0, 0, "yellow", 0, 0, "rect")  // Index 5 - Sand
];

// Image-based tiles (also no null needed)
const imageTiles = [
    new Component(0, 0, "tiles/grass.png", 0, 0, "image"),  // Index 1
    new Component(0, 0, "tiles/stone.png", 0, 0, "image"),  // Index 2
    new Component(0, 0, "tiles/water.png", 0, 0, "image")   // Index 3
];
Enter fullscreen mode Exit fullscreen mode

Creating Map Layouts

// Map uses indexes starting from 1 (0 = empty, handled automatically)
const mapLayout = [
    [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
    [2, 1, 1, 1, 1, 1, 1, 1, 1, 2],
    [2, 1, 1, 3, 3, 3, 1, 1, 1, 2],
    [2, 1, 1, 3, 3, 3, 1, 1, 1, 2],
    [2, 1, 1, 1, 1, 1, 1, 1, 1, 2],
    [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
];
Enter fullscreen mode Exit fullscreen mode

Initializing the TileMap (v3 Method)

// Setup display
const display = new Display();
display.start(800, 600);

// Assign tiles and map to display
display.tile = tiles;      // No null needed!
display.map = mapLayout;

// Create the tilemap (but don't call show() here!)
display.tileMap();         // Creates tileFace instance

// v3 CRITICAL: show() must be called in update function!
function update() {
    display.tileFace.show();  // This renders the tilemap each frame

    // Your other game logic...
}

// Access the tilemap directly
const tilemap = display.tileFace;
Enter fullscreen mode Exit fullscreen mode

🎯 Complete Working Example (v3)

Proper v3 Implementation

const display = new Display();
display.start(800, 600);

// Define tiles (NO NULL needed - engine handles it)
const tiles = [
    new Component(0, 0, "green", 0, 0, "rect"),   // Index 1 - Grass
    new Component(0, 0, "gray", 0, 0, "rect"),    // Index 2 - Wall
    new Component(0, 0, "blue", 0, 0, "rect")     // Index 3 - Water
];

// Create map layout (0 = empty, handled automatically)
const levelMap = [
    [2, 2, 2, 2, 2, 2, 2, 2],
    [2, 1, 1, 1, 1, 1, 1, 2],
    [2, 1, 3, 3, 1, 1, 1, 2],
    [2, 1, 1, 1, 1, 1, 1, 2],
    [2, 2, 2, 2, 2, 2, 2, 2]
];

// Assign to display and create TileMap
display.tile = tiles;
display.map = levelMap;
display.tileMap();  // Creates tileFace

// Player setup
const player = new Component(30, 30, "red", 100, 100, "rect");
player.physics = true;
player.gravity = 0.5;
display.add(player);

// v3: TileMap rendering MUST be in update function
function update() {
    // CRITICAL: Render the tilemap every frame
    display.tileFace.show();

    // Player controls
    if (display.keys[37]) player.speedX = -5; // Left
    if (display.keys[39]) player.speedX = 5;  // Right
    if (display.keys[38] && player.gravitySpeed === 0) {
        player.speedY = -12; // Jump
    }

    // Collision detection with tiles
    if (display.tileFace.crashWith(player, 2)) { // Wall collision
        player.speedX = 0;
        player.hitBottom();
    }

    if (display.tileFace.crashWith(player, 3)) { // Water physics
        player.speedX *= 0.6;
        player.speedY *= 0.6;
    }
}
Enter fullscreen mode Exit fullscreen mode

🔧 TileMap Properties and Methods (v3)

Automatic Index Handling

// v3 automatically handles the empty tile index
class TileMap {
    constructor(render, map, tile, width, height, scene = 0) {
        this.map = map;
        this.tile = tile;
        this.tile.unshift(0);  // ← ENGINE ADDS THIS AUTOMATICALLY!
        this.tileHeight = height / map.length;
        this.tileWidth = width / map[0].length;
        this.tileList = [];
        this.scene = scene;
    }

    show() {
        // Rendering logic - must be called each frame in v3
        let yy = 0;
        let tyy = 0;
        // ... rendering code
    }
}
Enter fullscreen mode Exit fullscreen mode

Proper Tile Access

// Your tiles array starts from index 0 for your first tile
const tiles = [
    new Component(0, 0, "green", 0, 0, "rect"),   // You access as tiles[0]
    new Component(0, 0, "gray", 0, 0, "rect"),    // tiles[1]
    new Component(0, 0, "blue", 0, 0, "rect")     // tiles[2]
];

// But in the map, you use indexes starting from 1
const map = [
    [2, 2, 2],  // This uses gray tiles (index 2 = tiles[1])
    [2, 1, 2],  // 1 = green (tiles[0]), 2 = gray (tiles[1])
    [2, 2, 2]
];

// Access tiles correctly
const grassTiles = tilemap.tiles(1);  // Get all tiles with ID 1 (your tiles[0])
const wallTiles = tilemap.tiles(2);   // Get all tiles with ID 2 (your tiles[1])
Enter fullscreen mode Exit fullscreen mode

🚀 Advanced v3 TileMap Patterns

Dynamic TileMap with Real-time Updates

const display = new Display();
display.start(800, 600);

// Tile definitions
const tiles = [
    new Component(0, 0, "#7CFC00", 0, 0, "rect"), // Grass
    new Component(0, 0, "#8B4513", 0, 0, "rect"), // Dirt
    new Component(0, 0, "#FFD700", 0, 0, "rect")  // Gold
];

// Initial map
const gameMap = [
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1],
    [1, 1, 1, 1, 1]
];

display.tile = tiles;
display.map = gameMap;
display.tileMap();

const player = new Component(30, 30, "blue", 100, 100, "rect");
display.add(player);

let coinsCollected = 0;

function update() {
    // v3: Must render tilemap in update
    display.tileFace.show();

    // Convert player position to grid coordinates
    const gridX = Math.floor(player.x / display.tileFace.tileWidth);
    const gridY = Math.floor(player.y / display.tileFace.tileHeight);

    // Check if player is on a gold tile
    if (gridX >= 0 && gridY >= 0 && gridY < gameMap.length && gridX < gameMap[0].length) {
        if (gameMap[gridY][gridX] === 3) { // Gold tile
            // Collect coin and change tile to dirt
            display.tileFace.remove(gridX, gridY);
            gameMap[gridY][gridX] = 2; // Change to dirt
            coinsCollected++;
            console.log(`Coins collected: ${coinsCollected}`);
        }
    }

    // Player movement
    if (display.keys[37]) player.x -= 5;
    if (display.keys[39]) player.x += 5;
    if (display.keys[38]) player.y -= 5;
    if (display.keys[40]) player.y += 5;
}
Enter fullscreen mode Exit fullscreen mode

Animated Tiles in v3

const display = new Display();
display.start(800, 600);

// Animated water tiles
const tiles = [
    new Component(0, 0, "green", 0, 0, "rect"),  // Grass
    new Component(0, 0, "blue", 0, 0, "rect")    // Water
];

const map = [
    [1, 1, 1, 1],
    [1, 2, 2, 1],
    [1, 2, 2, 1],
    [1, 1, 1, 1]
];

display.tile = tiles;
display.map = map;
display.tileMap();

function update() {
    // v3: Render tilemap
    display.tileFace.show();

    // Animate water tiles (ID 2)
    const waterTiles = display.tileFace.tiles(2);
    waterTiles.forEach((tile, index) => {
        // Create wave effect
        tile.y += Math.sin(display.frameNo * 0.1 + index) * 0.5;
    });

    // Your game logic...
}
Enter fullscreen mode Exit fullscreen mode

🎮 Complete Platformer Example (v3 Corrected)

const display = new Display();
display.start(800, 600);

// v3: No null in tiles array!
const tiles = [
    new Component(0, 0, "#228B22", 0, 0, "rect"), // Grass (ID 1)
    new Component(0, 0, "#8B4513", 0, 0, "rect"), // Dirt (ID 2)
    new Component(0, 0, "#C0C0C0", 0, 0, "rect"), // Stone (ID 3)
    new Component(0, 0, "#87CEEB", 0, 0, "rect")  // Water (ID 4)
];

const platformerMap = [
    [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, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 3, 3, 3, 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, 3, 3, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
];

display.tile = tiles;
display.map = platformerMap;
display.tileMap();

// Player setup
const player = new Component(30, 30, "red", 100, 100, "rect");
player.physics = true;
player.gravity = 0.5;
player.bounce = 0.2;
display.add(player);

// Camera setup
display.camera.worldWidth = platformerMap[0].length * display.tileFace.tileWidth;
display.camera.worldHeight = platformerMap.length * display.tileFace.tileHeight;
display.camera.follow(player, true);

function update() {
    // v3 CRITICAL: Render tilemap every frame
    display.tileFace.show();

    // Player controls
    if (display.keys[37]) player.speedX = -5; // Left
    if (display.keys[39]) player.speedX = 5;  // Right
    if (display.keys[38] && player.gravitySpeed === 0) {
        player.speedY = -12; // Jump
    }

    // Collision with solid tiles (1=grass, 2=dirt, 3=stone)
    if (display.tileFace.crashWith(player, 1) || 
        display.tileFace.crashWith(player, 2) ||
        display.tileFace.crashWith(player, 3)) {
        player.hitBottom();
    }

    // Water physics
    if (display.tileFace.crashWith(player, 4)) {
        player.speedX *= 0.7;
        player.speedY *= 0.7;
    }
}
Enter fullscreen mode Exit fullscreen mode

🔧 Common v3 Issues and Solutions

TileMap Not Rendering

// ❌ WRONG - show() called only once
display.tileMap();
display.tileFace.show(); // Only renders once

// ✅ CORRECT - show() in update function
display.tileMap();
function update() {
    display.tileFace.show(); // Renders every frame
}
Enter fullscreen mode Exit fullscreen mode

Incorrect Tile Indexing

// ❌ WRONG - including null manually
const tiles = [
    null, // Don't do this - engine handles it!
    new Component(0, 0, "green", 0, 0, "rect")
];

// ✅ CORRECT - no null needed
const tiles = [
    new Component(0, 0, "green", 0, 0, "rect") // This becomes index 1 in map
];

// In map, use 1 for the first tile, 2 for the second, etc.
const map = [
    [1, 1, 1],
    [1, 2, 1], // 2 would be your second tile in the array
    [1, 1, 1]
];
Enter fullscreen mode Exit fullscreen mode

Performance Optimization for v3

// Optimized v3 TileMap rendering
let lastTileRender = 0;
const tileRenderInterval = 2; // Render tiles every 2 frames

function update() {
    // Only render tiles every few frames for better performance
    if (display.frameNo - lastTileRender >= tileRenderInterval) {
        display.tileFace.show();
        lastTileRender = display.frameNo;
    }

    // Other game logic runs every frame
    player.move();
    // ...
}
Enter fullscreen mode Exit fullscreen mode

📚 v3 TileMap Conclusion

Key v3 Differences:

  1. No null in tiles array - Engine automatically adds index 0
  2. show() in update function - Must be called every frame
  3. Simplified indexing - Your first tile = map index 1

Proper v3 Workflow:

// 1. Define tiles (no null)
const tiles = [tile1, tile2, tile3];

// 2. Create map (indexes start from 1)
const map = [[1,2,3], [1,1,1]];

// 3. Assign to display
display.tile = tiles;
display.map = map;
display.tileMap();

// 4. Render in update
function update() {
    display.tileFace.show(); // ← CRITICAL!
    // Game logic...
}
Enter fullscreen mode Exit fullscreen mode

The v3 TileMap system is more efficient but requires the show() method to be called in the update loop. This change allows for dynamic tile updates and better performance in complex games!

Top comments (0)