Rendering a Map
Time to witness some MAGIC! 🎮 You’re about to transform those boring arrays of numbers into a living, breathing game world. By the end of this chapter, you’ll watch your map data come alive on screen - just like the pros do it! This is the moment where your game starts feeling real.
Look at our map array again, but this time imagine it as your game world:
Array: Visual Result:
[1, 1, 1, 1] → 🧱🧱🧱🧱
[1, 0, 0, 1] → 🧱 🌟 🌟🧱
[1, 1, 1, 1] → 🧱🧱🧱🧱
Each 1 becomes a solid wall, each 0 becomes walkable space!
The result should look like this:
First, let’s set up our map data and tile definitions using modern JavaScript:
// Our map as a 2D array - same concept, cleaner syntax!
const myMap = [
[1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1]
];
// Game configuration object
const game = {
tileW: 30,
tileH: 30
};
// Tile type definitions - modern approach
const TileTypes = {
FLOOR: {
id: 0,
walkable: true,
color: 0x003311, // Dark green for floors
name: 'floor'
},
WALL: {
id: 1,
walkable: false,
color: 0x00ff41, // Bright green for walls
name: 'wall'
}
};
Boom! Look what we’ve built - a complete tile system! 🔥 The game object holds all our configuration - keeping everything organized in one place makes our code much cleaner and easier to manage. You’re already thinking like a game developer!
Notice how we set tileW: 30 and tileH: 30 in our game object. This defines how big each tile will be in pixels. Here’s something cool - tiles don’t have to be squares! Want massive 64x64 tiles for that chunky retro feel? Thin 32x8 platform strips for precise platforming? Just change these numbers and watch the magic happen!
Whenever you need to know a tile’s size:
game.tileW; // Gets tile width
game.tileH; // Gets tile height
In modern JavaScript, we use objects to define our tile types instead of prototypes. Our TileTypes object contains all the information about each tile:
- id: The number we use in our map array (0 for floor, 1 for wall)
- walkable: Can the player move through this tile?
- color: What color should this tile be in PixiJS?
- name: A readable name for debugging
This approach is much cleaner than the old Flash prototype system and makes it easy to add new tile types later!
LET’S RENDER OUR MAP! 🚀
Time to make those tiles appear on screen! This is where the real magic happens. We’ll create a buildMap function that transforms your data into a playable world. You can use this same function to build different levels by passing in different map arrays.
Our rendering strategy:
- Step 1: Create a PixiJS canvas (your game’s window to the world)
- Step 2: Loop through every tile position (we’re building this systematically!)
- Step 3: Create graphics for each tile (watch the magic happen!)
- Step 4: Position everything perfectly
- Step 5: Add it all to the stage (and celebrate! 🎉)
Here’s our modern PixiJS powerhouse:
async function buildMap(map, containerId) {
// Step 1: Create your canvas (your game's window to the world)
const app = new PIXI.Application();
await app.init({
width: map[0].length * game.tileW,
height: map.length * game.tileH,
backgroundColor: 0x2c3e50,
antialias: true
});
// Add canvas to our HTML container
document.getElementById(containerId).appendChild(app.canvas);
// Get map dimensions
const mapWidth = map[0].length;
const mapHeight = map.length;
// Create a container for all tiles
const tileContainer = new PIXI.Container();
app.stage.addChild(tileContainer);
// Step 2 & 3: Loop through every position and create tiles
for (let row = 0; row < mapHeight; row++) {
for (let col = 0; col < mapWidth; col++) {
const tileId = map[row][col];
const tileType = Object.values(TileTypes).find(type => type.id === tileId);
// Create tile graphics (the magic happens here!)
const tileGraphics = new PIXI.Graphics();
tileGraphics.beginFill(tileType.color);
tileGraphics.drawRect(0, 0, game.tileW, game.tileH);
tileGraphics.lineStyle(1, 0x00ff41, 0.3);
tileGraphics.drawRect(0, 0, game.tileW, game.tileH);
tileGraphics.endFill();
// Step 4: Position the tile perfectly
tileGraphics.x = col * game.tileW;
tileGraphics.y = row * game.tileH;
// Add to container
tileContainer.addChild(tileGraphics);
}
}
return app; // Return the app so we can control it later
}
Try This Right Now! 🔥
Want to see some instant magic? Try changing the colors in TileTypes and refresh the page:
- Want red walls? Change
0x00ff41to0xff0000 - Want blue floors? Change
0x003311to0x0066cc - Want purple walls? Try
0x9932cc
Go ahead, experiment! This is how you learn to make games that are uniquely yours.
Let’s break down what’s happening in our modern PixiJS powerhouse:
Setting up the stage: Instead of Flash’s old attachMovie system, we create a PIXI.Application which gives us a canvas and handles all the rendering magic for us. No more worrying about movie clips in the library - this is the modern way!
Container system: We create a PIXI.Container called tileContainer to hold all our tiles. This is like a magic folder that organizes everything. When you want to remove all tiles (like when transitioning to a new level), just remove the container and POOF - all tiles disappear instantly!
Map dimensions: We calculate mapWidth and mapHeight the same way. map[0].length gives us the number of columns (how many tiles across), and map.length gives us the number of rows (how many tiles down). Simple but powerful!
The nested loops: This is the heart of tile rendering! We’re using the classic double-loop pattern that powers countless games:
for (let row = 0; row < mapHeight; row++) { // Loop through rows (top to bottom)
for (let col = 0; col < mapWidth; col++) { // Loop through columns (left to right)
// Create tile at position [row][col] - building your world piece by piece!
}
}
Creating tiles: Instead of attaching movie clips, we use PIXI.Graphics to draw colored rectangles. We look up the tile type from our TileTypes object and use its color. Each tile gets its own unique graphics object!
Positioning magic: Same math as the pros use! col * game.tileW for x position, row * game.tileH for y position. This creates a perfect grid where every tile knows exactly where it belongs.
Using it: Call the function like this:
const mapApp = await buildMap(myMap, 'my-canvas-container');
🏆 VICTORY! You just built a complete tile rendering system that would make professional game developers proud! This is the same technique used in countless indie hits and AAA games. Your arrays of numbers have transformed into a visual game world!
What you’ve accomplished:
- ✅ Mastered the fundamentals of game rendering
- ✅ Built a reusable map system
- ✅ Created your first interactive game world
- ✅ Learned the same techniques used by the pros
Ready to add some life to this world? Next up: creating a hero character who can explore your newly created level! Time to make your world truly interactive! 🚀