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 using- new 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 - xand- y.
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-in- kb.pressing().
- We update the paddle’s velocity ( - paddle.vel.x), instead of setting- paddle.xdirectly.
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 than- keyIsDown().
🔄 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.xinstead of updating- xdirectly.
- Gravity, bouncing, and collision detection are built-in. 
Would you like me to add extra challenges or an extension for this lesson? 😊
Last updated
