Tileset-Map Editor Game
Play GameThis guide provides a detailed explanation of a Tileset-Map Editor Game. This game allows users to create and edit maps using a tileset. We will break down the entire JavaScript logic, explaining each part thoroughly and providing references to relevant documentation sections.
Introduction
The Tileset-Map Editor Game is a tool that allows users to create, edit, and save maps using a predefined set of tiles. This type of tool is commonly used in game development to design levels and environments.
Setting Up the Project
Before we start coding, ensure you have the following setup:
- A text editor (like VS Code)
- Basic knowledge of HTML, CSS, and JavaScript
- A tileset image to use for creating the map
JavaScript Logic
The JavaScript logic for our Tileset-Map Editor Game is extensive, so we will break it down into sections:
Initialization
First, we need to initialize our canvas and context:
const canvas = document.querySelector("canvas");
const tilesetContainer = document.querySelector(".tileset-container");
const tilesetSelection = document.querySelector(".tileset-container_selection");
const tilesetImage = document.querySelector("#tileset-source");
const selection = [0, 0]; // Which tile we will paint from the menu
let isMouseDown = false;
let currentLayer = 0;
const layers = [
{}, // Bottom
{}, // Middle
{}, // Top
];
// Load the tileset image
tilesetImage.onload = function () {
layers = defaultState;
draw();
setLayer(0);
};
tilesetImage.src = "https://assets.codepen.io/21542/TileEditorSpritesheet.2x_2.png"; // Default tileset image
const defaultState = [
// Example of default state map
// Each entry is structured as "x-y": ["tileset_x", "tileset_y"]
// Example: "1-1": [3, 4],
];
Canvas Setup
Next, we set up the canvas and draw the initial grid:
function drawGrid() {
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
layers.forEach((layer) => {
Object.keys(layer).forEach((key) => {
const positionX = Number(key.split("-")[0]);
const positionY = Number(key.split("-")[1]);
const [tilesheetX, tilesheetY] = layer[key];
ctx.drawImage(
tilesetImage,
tilesheetX * 32,
tilesheetY * 32,
32,
32,
positionX * 32,
positionY * 32,
32,
32
);
});
});
}
Event Listeners
In this section, we add event listeners to handle user interactions. Event listeners are crucial for making the canvas interactive, allowing users to draw tiles by clicking and dragging.
To learn more about event listeners, you can read the detailed guide.
canvas.addEventListener("mousedown", () => {
isMouseDown = true;
});
canvas.addEventListener("mouseup", () => {
isMouseDown = false;
});
canvas.addEventListener("mouseleave", () => {
isMouseDown = false;
});
canvas.addEventListener("mousedown", addTile);
canvas.addEventListener("mousemove", (event) => {
if (isMouseDown) {
addTile(event);
}
});
Utility Functions
Utility function to get the coordinates of mouse clicks:
function getCoords(event) {
const { x, y } = event.target.getBoundingClientRect();
const mouseX = event.clientX - x;
const mouseY = event.clientY - y;
return [Math.floor(mouseX / 32), Math.floor(mouseY / 32)];
}
Drawing the Grid
Function to draw the grid and map tiles:
function drawGrid() {
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
layers.forEach((layer) => {
Object.keys(layer).forEach((key) => {
const positionX = Number(key.split("-")[0]);
const positionY = Number(key.split("-")[1]);
const [tilesheetX, tilesheetY] = layer[key];
ctx.drawImage(
tilesetImage,
tilesheetX * 32,
tilesheetY * 32,
32,
32,
positionX * 32,
positionY * 32,
32,
32
);
});
});
}
Placing Tiles
Function to place tiles on the grid when the user clicks on the canvas:
function addTile(event) {
const clicked = getCoords(event);
const key = `${clicked[0]}-${clicked[1]}`;
if (event.shiftKey) {
delete layers[currentLayer][key];
} else {
layers[currentLayer][key] = selection;
}
drawGrid();
}
Saving and Loading Maps
Functions to save and load the map data:
function exportImage() {
const data = canvas.toDataURL();
const image = new Image();
image.src = data;
const w = window.open("");
w.document.write(image.outerHTML);
}
function clearCanvas() {
layers.fill({});
drawGrid();
}
function setLayer(newLayer) {
currentLayer = newLayer;
const oldActiveLayer = document.querySelector(".layer.active");
if (oldActiveLayer) {
oldActiveLayer.classList.remove("active");
}
document.querySelector(`[tile-layer="${currentLayer}"]`).classList.add("active");
}
Complete Code
Here is the complete code for the game
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tile Map Editor</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="card">
<header>
<h1>Tile Map Editor</h1>
<div>
<button class="button-as-link" onclick="clearCanvas()">Clear Canvas</button>
<button class="primary-button" onclick="exportImage()">Export Image</button>
</div>
</header>
<div class="card_body">
<aside>
<label>Tiles</label>
<div class="tileset-container">
<img id="tileset-source" src="https://opengameart.org/sites/default/files/grass_tileset_16x16_preview_0.png" alt="Tileset" />
<!-- <img id="tileset-source" crossorigin /> -->
<div class="tileset-container_selection"></div>
</div>
</aside>
<div class="card_right-column">
<!-- The main canvas -->
<canvas width="480" height="480"></canvas>
<p class="instructions">
<strong>Click</strong> to paint.
<strong>Shift+Click</strong> to remove.
</p>
<!-- UI for layers -->
<div>
<label>Editing Layer:</label>
<ul class="layers">
<li><button onclick="setLayer(2)" class="layer" tile-layer="2">Top Layer</button></li>
<li><button onclick="setLayer(1)" class="layer" tile-layer="1">Middle Layer</button></li>
<li><button onclick="setLayer(0)" class="layer" tile-layer="0">Bottom Layer</button></li>
</ul>
</div>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>