Leave without saving?

Your editor changes will be lost.

Breakout-3 renders bricks onto the screen. It implements bouncing behavior for the ball upon a collision with a brick. It also fixes our previous naive implementation of bouncing behavior between the ball and the paddle.

Important Algorithms

We want the player to control the trajectory of the ball based on where it hits the paddle. If the ball hits the center of the paddle, the ball should slow down and have a steeper angle. If the ball hits more towards the edges of the paddle, the ball should speed up and have a shallower angle. The code for this is explained in the next section.

For brick collision, we must check which edge of the ball is not inside the brick:

if left edge of ball is outside brick and dx is positive:
trigger left-side collision
else if right edge of ball is outside brick and dx is negative:
trigger right-side collision
else if top edge of ball is outside brick:
trigger top-side collision
else
trigger bottom-side collision

This is a fairly simple collision algorithm, so it is not the most accurate, particularly when faced with corner-cases, but it works 99% of the time. For a more robust solution, check out this alternative method.

Important Code

  • In SpriteManager.js you’ll notice that we’ve added another method, generateBallSprites(), to extract the brick sprites from the sprite sheet.

  • Brick.js creates our brick class:

    • constructor() initializes a brick. Importantly, we include an inPlay flag to serve as a signal for whether a brick is still in play or if it should disappear from the screen. In the context of this Breakout game, this is an effective shortcut, but do note that in larger programs, it would be better practice to free memory that is not being used instead of just hiding it from view.
    • hit() hides a brick by toggling the inPlay flag to false.
    • render() renders a brick to the screen.
  • PlayState.js references a new class, LevelMaker.js, which encapsulates all the logic for generating new levels (i.e. different layouts for the bricks). It also checks for collisions between the ball and the bricks, hiding bricks as needed, and renders the “in play” bricks to the screen.

  • To create a level, LevelMaker.js randomly generates an array of bricks that can be rendered to the screen. Read through the LevelMaker.createMap() function carefully.

  • In Ball.js, we’ve added an handlePaddleCollision() function to reflect the collision algorithms mentioned above:

    Ball.js
    const paddleBallDistance = paddle.x + paddle.width / 2 - this.x;
    const scaleFactor = 8;
    const minimumVelocity = 50;
    if (this.x < paddle.x + paddle.width / 2 && paddle.dx < 0) {
    this.dx = -minimumVelocity + -(scaleFactor * paddleBallDistance);
    } else if (this.x > paddle.x + paddle.width / 2 && paddle.dx > 0) {
    this.dx = minimumVelocity + scaleFactor * Math.abs(paddleBallDistance);
    }
    • First, we calculate the distance between the paddle and the ball to scale the ball’s dx.
    • scaleFactor and minimumVelocity are values that are used to control the ball’s dx depending on where it hit the paddle.
    • Then perform this operation on either side of the paddle based on the paddle’s dx. If on the right side, the differential will be negative, so we need to call Math.abs() to make it positive, then scale it by a positive amount so dx becomes positive.
  • And below that, we’ve added a handleBrickCollision() function based on the pseudocode in the section above. We slightly increase the ball’s velocity after a collision:

    Ball.js
    if (this.x < brick.x && this.dx > 0) {
    this.dx = -this.dx;
    } else if (this.x + this.width > brick.x + brick.width && this.dx < 0) {
    this.dx = -this.dx;
    } else if (this.y < brick.y) {
    this.dy = -this.dy;
    } else {
    this.dy = -this.dy;
    }
    this.dy *= 1.02;
Powered by WebContainers
Files
Preparing Environment