Click the game and press ← and →. It's yours now.
const keys = useKeyboard();
useUpdate((dt) => {
if (keys.isDown('ArrowLeft')) paddle.transform.x -= PADDLE_SPEED * dt;
if (keys.isDown('ArrowRight')) paddle.transform.x += PADDLE_SPEED * dt;
paddle.transform.x = Math.min(Math.max(paddle.transform.x, 0), WIDTH - PADDLE_W);
});The keyboard is asked, not listened to
useKeyboard doesn't notify you when a key goes down. It hands you an object you
question whenever it suits you:
keys.isDown('ArrowLeft') // is it held RIGHT NOW?This is called polling, and it's what you want in a game. With events you'd have to record somewhere that the key is down, clear it on release, and remember to clear it again if the window loses focus. Asking, the answer is always the truth of the frame you're drawing.
The names are the browser's: 'ArrowLeft', 'ArrowRight', 'Enter', ' ' for space.
Single letters ignore case: isDown('a') is the same as isDown('A').
Two more questions you'll want soon: justPressed(key), true for exactly one frame per
press, and justReleased(key). With isDown, a shot would fire sixty times a second while
you lean on the button; with justPressed, once per press.
The line that doesn't look important
paddle.transform.x = Math.min(Math.max(paddle.transform.x, 0), WIDTH - PADDLE_W);Delete it and hold the left arrow: the paddle leaves the screen and never comes back. It's the kind of bug that breaks nothing, raises no error, and ruins the game.
Read it inside out:
Math.max(x, 0): "the larger of the two". Ifxis −40, it becomes 0. Never below 0.Math.min(..., WIDTH - PADDLE_W): "the smaller". Never past the right edge.
And the right edge is WIDTH - PADDLE_W, not WIDTH, for the chapter-2 reason: x is the
paddle's left corner, so you have to leave room for its own width.
This is called clamping a value, and you'll write it a great many times.
What's an `if`?
An if runs something only when a condition holds:
if (keys.isDown('ArrowLeft')) paddle.transform.x -= 5;It reads literally: if the left arrow is down, subtract 5 from x. If it isn't, that line is skipped and nothing happens.
Notice there are two separate ifs here, not an if/else. That's deliberate: if someone
presses both arrows at once, both run and the paddle sits still, which is reasonable. With
else, left would always win.
Your turn
Swap 'ArrowLeft' and 'ArrowRight' for 'a' and 'd'. Add a third if on the spacebar
(' ') that makes the paddle wider while it's held.
And delete the Math.min/Math.max line once, just to watch it run away.