Bouncing Ball Catcher with p5play
Bouncing Ball Catcher
In this tutorial, we'll create a simple game where balls fall due to gravity, and the player moves a paddle to bounce them back up.
We'll use p5play, a physics engine for p5.js, which makes it easier to handle movement, collisions, and gravity.
✨ Step 1: Setting Up p5play
What’s new?
In p5.js, we create a
canvas(width, height)
.In p5play, we use
new Canvas("1:1")
, which automatically scales the canvas to a 1:1 ratio.
Code:
function setup() {
new Canvas("1:1"); // Auto-resizing canvas
world.gravity.y = 1; // Enable gravity
}
✅ Why is this useful? With p5play, you don’t have to manually update positions—gravity and physics handle it for you!
🏓 Step 2: Creating a Paddle
What’s new?
Instead of a
rect()
, we create a paddle sprite usingnew Sprite()
.The KINEMATIC collider makes it immovable by physics, but we can still move it with code.
Code:
let paddle;
function setup() {
new Canvas("1:1");
world.gravity.y = 1;
// Create paddle
paddle = new Sprite();
paddle.width = 50;
paddle.height = 50;
paddle.collider = KINEMATIC; // Allows manual movement, not affected by gravity
}
✅ Why is this useful? In plain p5.js, you’d have to manually handle movement, but p5play handles collisions automatically.
⚽ Step 3: Adding Balls
What’s new?
Instead of using an array of objects, we create physics-enabled balls using
new Sprite()
.We set speed and direction instead of manually updating
x
andy
.
Code
let balls = [];
let nBalls = 5;
function addBall() {
let ball = new Sprite(random(50, width - 50), 50, 30, 30);
ball.shapeColor = color(200, 50, 100);
ball.speed = 2;
ball.direction = random(-200, -340); // Random initial velocity
ball.restitution = 0; // Bounciness (0 = no bounce, 1 = full bounce)
balls.push(ball);
}
function setup() {
new Canvas("1:1");
world.gravity.y = 1;
paddle = new Sprite();
paddle.width = 50;
paddle.height = 50;
paddle.collider = KINEMATIC;
for (let i = 0; i < nBalls; i++) {
addBall();
}
}
✅ Why is this useful? Instead of manually updating positions, p5play handles physics like gravity and movement automatically.
🎮 Step 4: Adding Player Controls
What’s new?
Instead of checking
keyIsDown()
, we use p5play’s built-inkb.pressing()
.We update the paddle’s velocity (
paddle.vel.x
), instead of settingpaddle.x
directly.
Code:
function draw() {
clear();
if (kb.pressing("left")) paddle.vel.x = -5;
else if (kb.pressing("right")) paddle.vel.x = 5;
else paddle.vel.x = 0;
// Keep paddle inside the screen
paddle.position.x = constrain(paddle.position.x, paddle.width / 2, width - paddle.width / 2);
}
✅ Why is this useful?
Instead of manually setting position, velocity-based movement feels smoother.
kb.pressing()
is cleaner thankeyIsDown()
.
🔄 Step 5: Handling Collisions
What’s new?
Instead of writing a manual collision check, we use
paddle.collides(ball)
.When the paddle hits the ball, we reverse the ball’s velocity to bounce it.
Code:
for (let i = balls.length - 1; i >= 0; i--) {
let ball = balls[i];
if (paddle.collides(ball)) {
ball.vel.y = -3; // Bounce upwards
}
}
✅ Why is this useful?
In p5.js, we’d have to manually calculate distance for collisions.
p5play automatically detects when objects touch!
🎯 Step 6: Adding Score & Removing Balls
What’s new?
We introduce a score that increases when catching balls.
If a ball falls off the screen, we remove it and decrease the score.
Code:
let score = 0;
function draw() {
clear();
if (kb.pressing("left")) paddle.vel.x = -5;
else if (kb.pressing("right")) paddle.vel.x = 5;
else paddle.vel.x = 0;
paddle.position.x = constrain(paddle.position.x, paddle.width / 2, width - paddle.width / 2);
for (let i = balls.length - 1; i >= 0; i--) {
let ball = balls[i];
if (paddle.collides(ball)) {
ball.vel.y = -3; // Bounce
score++;
}
if (ball.position.y > height) {
balls.splice(i, 1); // Remove ball
score--;
}
}
// Display score
fill(0);
textSize(24);
text(`Score: ${score}`, 10, 30);
}
✅ Why is this useful?
Instead of manually checking ball positions, p5play makes collision detection easy.
The game is now interactive and rewarding!
⏳ Step 7: Spawning More Balls Over Time
What’s new?
Every 60 frames (≈1 second), we add a new ball to keep the game challenging.
Code:
if (frameCount % 60 === 0) {
addBall();
}
✅ Why is this useful? This makes the game progressively harder, adding a natural difficulty curve.
🎉 Final Code
let paddle;
let balls = [];
let nBalls = 5;
let score = 0;
function addBall() {
let ball = new Sprite(random(50, width - 50), 50, 30, 30);
ball.shapeColor = color(200, 50, 100);
ball.speed = 2;
ball.direction = random(-200, -340);
ball.restitution = 0;
balls.push(ball);
}
function setup() {
new Canvas("1:1");
world.gravity.y = 1;
paddle = new Sprite();
paddle.width = 50;
paddle.height = 50;
paddle.collider = KINEMATIC;
for (let i = 0; i < nBalls; i++) {
addBall();
}
}
function draw() {
clear();
if (kb.pressing("left")) paddle.vel.x = -5;
else if (kb.pressing("right")) paddle.vel.x = 5;
else paddle.vel.x = 0;
paddle.position.x = constrain(paddle.position.x, paddle.width / 2, width - paddle.width / 2);
for (let i = balls.length - 1; i >= 0; i--) {
let ball = balls[i];
if (paddle.collides(ball)) {
ball.vel.y = -3;
score++;
}
if (ball.position.y > height) {
balls.splice(i, 1);
score--;
}
}
if (frameCount % 60 === 0) {
addBall();
}
fill(0);
textSize(24);
text(`Score: ${score}`, 10, 30);
}
🎯 Recap
p5play simplifies physics!
No need to manually check collisions!
Smooth movement with
vel.x
instead of updatingx
directly.Gravity, bouncing, and collision detection are built-in.
Would you like me to add extra challenges or an extension for this lesson? 😊
Last updated