HTML5 Canvas: Handling Player Input (Keyboard & Mouse)
HTML5 Canvas: Handling Player Input
A game without player input is just an animation. To make it a true game, we need to allow the player to control elements on the screen. Let's learn to capture keyboard and mouse input effectively!
1. The Right Way to Handle Keyboard Input
If you simply attach an event listener to a button press and move the player directly inside that listener, the movement will feel choppy and clunky.
The industry-standard way to do this is to keep track of which keys are currently being held down. We do this by storing the state in an object, and then applying movement inside our requestAnimationFrame Game Loop.
Step 1: Create a State Object
const keys = {
ArrowUp: false,
ArrowDown: false,
ArrowLeft: false,
ArrowRight: false
};
Step 2: Listeners to Update State
window.addEventListener('keydown', (e) => {
if (keys.hasOwnProperty(e.code)) {
keys[e.code] = true; // Key is being pressed
}
});
window.addEventListener('keyup', (e) => {
if (keys.hasOwnProperty(e.code)) {
keys[e.code] = false; // Key was released
}
});
Step 3: Apply to Game Loop
Now, inside the same Game Loop we learned about previously!
let player = { x: 100, y: 100, size: 30, speed: 5 };
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Smooth movement checked every single frame!
if (keys.ArrowUp) player.y -= player.speed;
if (keys.ArrowDown) player.y += player.speed;
if (keys.ArrowLeft) player.x -= player.speed;
if (keys.ArrowRight) player.x += player.speed;
// Draw Player
ctx.fillStyle = 'blue';
ctx.fillRect(player.x, player.y, player.size, player.size);
requestAnimationFrame(update);
}
2. Tracking the Mouse
Mouse tracking is incredibly useful for shooting games, drag-and-drop puzzles, or custom cursors.
Because the standard e.clientX gives the position based on the whole browser window, we must subtract the canvas's padding/margin bounds to get the exact X and Y on our game grid.
let mouse = { x: 0, y: 0 };
canvas.addEventListener('mousemove', (e) => {
// Get the size and position of the canvas on the webpage
const rect = canvas.getBoundingClientRect();
// Calculate exact coordinates relative to canvas
mouse.x = e.clientX - rect.left;
mouse.y = e.clientY - rect.top;
});
// Want a click event?
canvas.addEventListener('click', (e) => {
console.log(`Pew pew! Gun fired at X: ${mouse.x}, Y: ${mouse.y}`);
});
Now you can build a game loop that constantly draws an crosshair image exactly at mouse.x and mouse.y!