Step 3: Keyboard Controls
Let's add arrow key controls so players can steer the worm! We'll also prevent the worm from reversing into itself.
Understanding Keyboard Input
p5.js has a built-in function called keyPressed() that runs automatically when any key is pressed. We'll use it to detect arrow keys.
The keyPressed() Function
Add this function to handle keyboard input:
function keyPressed() {
// Right arrow
if (keyCode === RIGHT_ARROW && xSpeed !== -1) {
xSpeed = 1;
ySpeed = 0;
}
// Left arrow
else if (keyCode === LEFT_ARROW && xSpeed !== 1) {
xSpeed = -1;
ySpeed = 0;
}
// Down arrow
else if (keyCode === DOWN_ARROW && ySpeed !== -1) {
xSpeed = 0;
ySpeed = 1;
}
// Up arrow
else if (keyCode === UP_ARROW && ySpeed !== 1) {
xSpeed = 0;
ySpeed = -1;
}
}
Breaking it down:
Checking Which Key Was Pressed
if (keyCode === RIGHT_ARROW)
keyCodeis a p5.js variable that holds the code of the pressed keyRIGHT_ARROW,LEFT_ARROW, etc. are p5.js constants- This checks if the right arrow key was pressed
Setting Direction
xSpeed = 1;
ySpeed = 0;
- For right: move horizontally (x), not vertically (y)
- Sets the direction for the
updateWorm()function to use
Preventing Reverse Movement
if (keyCode === RIGHT_ARROW && xSpeed !== -1)
xSpeed !== -1means "not currently moving left"- This prevents the worm from reversing into itself
- Without this check, the worm could instantly hit its own body!
Why prevent reverse?
If the worm is moving right (xSpeed = 1) and has length > 1:
Head → [2][1][0] ← Tail
If we allowed reversing left (xSpeed = -1), the head would immediately collide with segment [1]:
[2] ← Head turns around
[1] ← COLLISION!
[0]
The game would be instantly over!
Direction Mapping
Here's how each arrow key maps to speeds:
| Key | xSpeed | ySpeed | Direction |
|---|---|---|---|
| RIGHT_ARROW | 1 | 0 | Moving right |
| LEFT_ARROW | -1 | 0 | Moving left |
| DOWN_ARROW | 0 | 1 | Moving down |
| UP_ARROW | 0 | -1 | Moving up |
Important: Only ONE speed should be non-zero at a time!
Alternative: WASD Controls
Want to use W/A/S/D keys instead? Here's how:
function keyPressed() {
// D key - Right
if (key === 'd' && xSpeed !== -1) {
xSpeed = 1;
ySpeed = 0;
}
// A key - Left
else if (key === 'a' && xSpeed !== 1) {
xSpeed = -1;
ySpeed = 0;
}
// S key - Down
else if (key === 's' && ySpeed !== -1) {
xSpeed = 0;
ySpeed = 1;
}
// W key - Up
else if (key === 'w' && ySpeed !== 1) {
xSpeed = 0;
ySpeed = -1;
}
}
Difference: Use key instead of keyCode for letter keys!
Complete Code
// Grid settings
let cellSize = 20;
let cols, rows;
// Worm
let worm = [];
let xSpeed = 1;
let ySpeed = 0;
function setup() {
createCanvas(400, 400);
frameRate(10);
// Calculate grid dimensions
cols = width / cellSize;
rows = height / cellSize;
// Initialize worm in the center
let startX = floor(cols / 2);
let startY = floor(rows / 2);
worm.push({x: startX, y: startY});
}
function draw() {
background(50);
// Update worm position
updateWorm();
// Draw grid lines (optional)
stroke(80);
strokeWeight(1);
for (let i = 0; i < cols; i++) {
line(i * cellSize, 0, i * cellSize, height);
}
for (let i = 0; i < rows; i++) {
line(0, i * cellSize, width, i * cellSize);
}
// Draw the worm
noStroke();
fill(0, 255, 0);
for (let i = 0; i < worm.length; i++) {
let segment = worm[i];
rect(segment.x * cellSize, segment.y * cellSize, cellSize, cellSize);
}
}
function updateWorm() {
// Get the current head position
let head = worm[worm.length - 1];
// Calculate new head position
let newHead = {
x: head.x + xSpeed,
y: head.y + ySpeed
};
// Add new head to the front
worm.push(newHead);
// Remove the tail
worm.shift();
}
function keyPressed() {
// Right arrow
if (keyCode === RIGHT_ARROW && xSpeed !== -1) {
xSpeed = 1;
ySpeed = 0;
}
// Left arrow
else if (keyCode === LEFT_ARROW && xSpeed !== 1) {
xSpeed = -1;
ySpeed = 0;
}
// Down arrow
else if (keyCode === DOWN_ARROW && ySpeed !== -1) {
xSpeed = 0;
ySpeed = 1;
}
// Up arrow
else if (keyCode === UP_ARROW && ySpeed !== 1) {
xSpeed = 0;
ySpeed = -1;
}
}
Test It Out!
Run the code and try the controls:
- ✅ Press arrow keys to change direction
- ✅ Worm responds immediately to input
- ✅ Can't reverse direction (try it - it won't work!)
- ✅ Worm still goes off screen (we'll fix this soon)
Understanding the Logic Flow
When you press RIGHT_ARROW while moving up:
keyPressed()is called- Check:
keyCode === RIGHT_ARROW✓ (true) - Check:
xSpeed !== -1✓ (true, because xSpeed is 0) - Set:
xSpeed = 1, ySpeed = 0 - Next frame:
updateWorm()uses new speeds - Worm turns right!
When you press LEFT_ARROW while moving right:
keyPressed()is called- Check:
keyCode === LEFT_ARROW✓ (true) - Check:
xSpeed !== 1✗ (false, because xSpeed IS 1) - Nothing happens - worm keeps moving right
- This prevents instant death!
Common p5.js Key Variables
keyCode- For special keys (arrows, Enter, Shift, etc.)key- For regular character keys (letters, numbers)
Special key constants:
RIGHT_ARROW,LEFT_ARROW,UP_ARROW,DOWN_ARROWENTER,BACKSPACE,DELETESHIFT,CONTROL,ALT
What You Learned
- How to use
keyPressed()to detect keyboard input - The difference between
keyCodeandkey - How to use p5.js arrow key constants
- Why preventing reverse movement is crucial
- How to use
!==to check inequality - Immediate vs delayed response to input