Semi-random thoughts and tales of tinkering
The core of Minecraft! You click to break blocks and right-click to place them. This lesson brings mouse input, coordinate conversion, and world modification together. ⛏️🧱
Just like keyboard events, the browser tells us when the mouse does things:
const mouse = { x: 0, y: 0, left: false, right: false };
canvas.addEventListener('mousemove', function(event) {
mouse.x = event.clientX; // Mouse X on screen
mouse.y = event.clientY; // Mouse Y on screen
});
canvas.addEventListener('mousedown', function(event) {
if (event.button === 0) mouse.left = true; // Left click
if (event.button === 2) mouse.right = true; // Right click
});
canvas.addEventListener('mouseup', function(event) {
if (event.button === 0) mouse.left = false;
if (event.button === 2) mouse.right = false;
});
// Prevent the right-click menu from appearing
canvas.addEventListener('contextmenu', function(event) {
event.preventDefault();
});
The mouse gives us screen coordinates, but we need to know which block in the world the mouse is pointing at. We add the camera position and divide by block size:
// Convert mouse screen position to world block coordinates
const worldMouseX = Math.floor((mouse.x + cameraX) / BLOCK_SIZE);
const worldMouseY = Math.floor((mouse.y + cameraY) / BLOCK_SIZE);
In Minecraft, you can only break/place blocks within arm's reach. We check the distance between the player and the mouse cursor:
const REACH = 5; // 5 blocks
// Distance from player center to mouse block
const playerCenterCol = (playerX + playerW / 2) / BLOCK_SIZE;
const playerCenterRow = (playerY + playerH / 2) / BLOCK_SIZE;
const distance = Math.hypot(worldMouseX - playerCenterCol,
worldMouseY - playerCenterRow);
if (distance <= REACH) {
// Close enough to interact!
}
if (mouse.left && distance <= REACH) {
const block = getBlock(worldMouseX, worldMouseY);
if (block !== 0) { // Not air
setBlock(worldMouseX, worldMouseY, 0); // Replace with air!
}
}
if (mouse.right && distance <= REACH) {
const block = getBlock(worldMouseX, worldMouseY);
if (block === 0) { // Only place in empty space
setBlock(worldMouseX, worldMouseY, 3); // Place stone
}
}
We draw a white outline around the block the mouse is pointing at — so the player knows which block they'll interact with:
// Draw highlight around hovered block
if (distance <= REACH) {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)';
ctx.lineWidth = 2;
ctx.strokeRect(
worldMouseX * BLOCK_SIZE - cameraX,
worldMouseY * BLOCK_SIZE - cameraY,
BLOCK_SIZE, BLOCK_SIZE
);
}
⬆️ Click here first! A D move, Space jump, Left-click = break, Right-click = place stone
mousemove, mousedown, mouseup