Skip to content

Instantly share code, notes, and snippets.

@nilsFK
Created July 14, 2025 12:49
Show Gist options
  • Save nilsFK/deda2295dc2a57be3bcbc8367fa51209 to your computer and use it in GitHub Desktop.
Save nilsFK/deda2295dc2a57be3bcbc8367fa51209 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Tilemap Game</title>
<style>
canvas {
border: 1px solid black;
image-rendering: pixelated;
}
</style>
</head>
<body>
<canvas id="game" width="320" height="320"></canvas>
<script>
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const tileSize = 32;
const mapWidth = 10;
const mapHeight = 10;
const initialMap = [
[0,0,0,0,0,0,0,0,0,0],
[0,1,1,1,0,0,1,1,1,0],
[0,0,0,1,0,0,1,0,0,0],
[0,1,0,0,0,1,1,0,1,0],
[0,1,1,1,0,0,0,0,1,0],
[0,0,0,1,1,1,1,0,1,0],
[0,1,0,0,0,0,1,0,1,0],
[0,1,1,1,1,0,1,0,1,0],
[0,0,0,0,0,0,0,0,1,0],
[0,0,0,0,0,0,0,0,0,0]
];
let map = JSON.parse(JSON.stringify(initialMap));
const player = { x: 1, y: 1, color: 'red' };
const enemy = { x: 8, y: 8, color: 'green' };
function drawMap() {
for (let y = 0; y < mapHeight; y++) {
for (let x = 0; x < mapWidth; x++) {
ctx.fillStyle = map[y][x] === 1 ? '#444' : '#ccc';
ctx.fillRect(x * tileSize, y * tileSize, tileSize, tileSize);
}
}
}
function drawCircle(x, y, color) {
const centerX = x * tileSize + tileSize / 2;
const centerY = y * tileSize + tileSize / 2;
const radius = tileSize / 3;
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
ctx.fill();
}
function drawPlayer() {
drawCircle(player.x, player.y, player.color);
}
function drawEnemy() {
drawCircle(enemy.x, enemy.y, enemy.color);
}
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawMap();
drawPlayer();
drawEnemy();
}
function movePlayer(dx, dy) {
const newX = player.x + dx;
const newY = player.y + dy;
if (
newX >= 0 && newX < mapWidth &&
newY >= 0 && newY < mapHeight &&
map[newY][newX] === 0
) {
player.x = newX;
player.y = newY;
}
render();
}
function resetGame() {
alert("You got caught! Restarting...");
map = JSON.parse(JSON.stringify(initialMap));
player.x = 1;
player.y = 1;
enemy.x = 8;
enemy.y = 8;
render();
}
function enemyMove() {
const dx = player.x - enemy.x;
const dy = player.y - enemy.y;
let stepX = dx === 0 ? 0 : dx > 0 ? 1 : -1;
let stepY = dy === 0 ? 0 : dy > 0 ? 1 : -1;
if (canMove(enemy.x + stepX, enemy.y)) {
enemy.x += stepX;
} else if (canMove(enemy.x, enemy.y + stepY)) {
enemy.y += stepY;
}
if (enemy.x === player.x && enemy.y === player.y) {
resetGame();
}
render();
}
function canMove(x, y) {
return x >= 0 && x < mapWidth && y >= 0 && y < mapHeight && map[y][x] === 0;
}
// 🕹️ Player movement
document.addEventListener('keydown', (e) => {
switch (e.key) {
case 'ArrowUp': movePlayer(0, -1); break;
case 'ArrowDown': movePlayer(0, 1); break;
case 'ArrowLeft': movePlayer(-1, 0); break;
case 'ArrowRight': movePlayer(1, 0); break;
}
if (player.x === enemy.x && player.y === enemy.y) {
resetGame();
}
});
// 🖱️ Toggle wall/walkable with mouse
canvas.addEventListener('click', (e) => {
const rect = canvas.getBoundingClientRect();
const x = Math.floor((e.clientX - rect.left) / tileSize);
const y = Math.floor((e.clientY - rect.top) / tileSize);
if ((x === player.x && y === player.y) || (x === enemy.x && y === enemy.y)) {
return;
}
map[y][x] = map[y][x] === 1 ? 0 : 1;
render();
});
setInterval(enemyMove, 1000);
render();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment