TCJSGame TileMap Class: Complete Reference Guide (Updated for v3)
⚠️ 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
];
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]
];
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;
🎯 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;
}
}
🔧 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
}
}
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])
🚀 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;
}
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...
}
🎮 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;
}
}
🔧 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
}
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]
];
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();
// ...
}
📚 v3 TileMap Conclusion
Key v3 Differences:
- No null in tiles array - Engine automatically adds index 0
- show() in update function - Must be called every frame
- 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...
}
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)