HTML5 Game Development Tutorial: Breakout Part III – Collisions, Scoring and Sound

In the second tutorial, we used setInterval() to add some animation and capture keydown and keyup events to respond to user input.

In this tutorial, we will bring back the bricks we drew before, handle the ball colliding with these bricks, and finally increase the score when a brick gets destroyed. We will also add some sound effects to make the game more fun.

First we add back two lines at the beginning of the animate() function to draw the scoreboard and the bricks.

JavaScript

1

2

3

4

5

functionanimate(){

context.clearRect(0,0,canvas.width,canvas.height);

createBricks();

displayScoreBoard();

Right now the ball will move over the bricks without bouncing off them.

We need the ball to reverse X direction if it hits the sides of the bricks, reverse Y direction if it hits the top or bottom of the bricks and damage the bricks every time it touches them.

Lets create functions to check whether the ball is colliding with a brick along the X or Y direction, and to damage the brick if it collides.

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

functioncollisionXWithBricks(){

varbumpedX=false;

for(vari=0;i<bricks.length;i++){

for(varj=0;j<bricks[i].length;j++){

if(bricks[i][j]){// if brick is still visible

varbrickX=j*brickWidth;

varbrickY=i*brickHeight;

if(

// barely touching from left

((ballX+ballDeltaX+ballRadius>=brickX)&&

(ballX+ballRadius<=brickX))

||

// barely touching from right

((ballX+ballDeltaX-ballRadius<=brickX+brickWidth)&&

(ballX-ballRadius>=brickX+brickWidth))

){

if((ballY+ballDeltaY-ballRadius<=brickY+brickHeight)&&

(ballY+ballDeltaY+ballRadius>=brickY)){

// weaken brick and increase score

explodeBrick(i,j);

bumpedX=true;

}

}

}

}

}

returnbumpedX;

}

functioncollisionYWithBricks(){

varbumpedY=false;

for(vari=0;i<bricks.length;i++){

for(varj=0;j<bricks[i].length;j++){

if(bricks[i][j]){// if brick is still visible

varbrickX=j*brickWidth;

varbrickY=i*brickHeight;

>if(

// barely touching from below

((ballY+ballDeltaY-ballRadius<=brickY+brickHeight)&&

(ballY-ballRadius>=brickY+brickHeight))

||

// barely touching from above

((ballY+ballDeltaY+ballRadius>=brickY)&&

(ballY+ballRadius<=brickY))){

if(ballX+ballDeltaX+ballRadius>=brickX&&

ballX+ballDeltaX-ballRadius<=brickX+brickWidth){

// weaken brick and increase score

explodeBrick(i,j);

bumpedY=true;

}

}

}

}

}

returnbumpedY;

}

functionexplodeBrick(i,j){

// First weaken the brick (0 means brick has gone)

bricks[i][j]--;

if(bricks[i][j]>0){

// The brick is weakened but still around. Give a single point.

score++;

}else{

// give player an extra point when the brick disappears

score+=2;

}

}

The collisionXWithBricks() and collisionYWithBricks() functions return true when they bounce against a brick and automatically call explodeBrick() to weaken the brick and update the score. To start using these functions, we modify the collision checking conditions in moveBall() slightly.

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// If top of the ball touches the top then reverse Y direction

if(ballY+ballDeltaY-ballRadius<0

// or if ball collides in Y direction with bricks

||collisionYWithBricks()){

ballDeltaY=-ballDeltaY;

}

// If side of ball touches either side of the wall then reverse X direction

//left of ball moves too far left

if((ballX+ballDeltaX-ballRadius<0)||

//or right side of ball moves too far right

(ballX+ballDeltaX+ballRadius>canvas.width)

// or if ball collides in Y direction with bricks

||collisionXWithBricks()

){

ballDeltaX=-ballDeltaX;

}

At this point, the ball bounces off the bricks as expected and weakens the brick when it hits them. Once the brick is completely destroyed, it disappears and gives the player an extra points.

Not bad. The game works fine, however there is still something missing.

A little sound tends to give players a much more immersive experience and will make the game more fun. With HTML5 Audio, implementing sound is surprisingly easy.

To play sounds, we load files using the Audio() object and play them using its play() method. Browsers are still a little inconsistent about which formats they support. The OGG file format is an open format supported by both Chrome and Firefox (my favorites), which is why we will stick with them for now.

To create the sound we place the two files at the same location as the HTML file and load them by creating new Audio() objects and storing them in variables. The OGG sound files used here are included with the source code.

JavaScript

1

2

varbouncingSound=newAudio("bounce.ogg");

varbreakingSound=newAudio("break.ogg");

To play these sounds, all we need to do is invoke the play() method.

We can play the breaking sound whenever a brick is completely destroyed (inside the explodeBrick() function).

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

functionexplodeBrick(i,j){

// First weaken the brick (0 means brick has gone)

bricks[i][j]--;

if(bricks[i][j]>0){

// The brick is weakened but still around. Give a single point.

score++;

}else{

// give player an extra point when the brick disappears

score+=2;

breakingSound.play();

}

}

And the bounce sound anytime we change X or Y direction for the ball (inside the moveBall() function)

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

functionmoveBall(){

// First check if we will bump into something

// If top of the ball touches the top then reverse Y direction

if(ballY+ballDeltaY-ballRadius<0

// or if ball collides in Y direction with bricks

||collisionYWithBricks()){

ballDeltaY=-ballDeltaY;

bouncingSound.play();

}

// If the bottom of the ball touches the bottom of the screen then end the game

if(ballY+ballDeltaY+ballRadius>canvas.height){

endGame();

}

// If side of ball touches either side of the wall then reverse X direction

//left of ball moves too far left

if((ballX+ballDeltaX-ballRadius<0)||

//or right side of ball moves too far right

(ballX+ballDeltaX+ballRadius>canvas.width)

// or if ball collides in Y direction with bricks

||collisionXWithBricks()

){

ballDeltaX=-ballDeltaX;

bouncingSound.play();

}

// if bottom of ball reaches the top of paddle,

if(ballY+ballDeltaY+ballRadius>=paddleY){

// and it is positioned between the two ends of the paddle (is on top)

if(ballX+ballDeltaX>=paddleX&&

ballX+ballDeltaX<=paddleX+paddleWidth){

ballDeltaY=-ballDeltaY;

bouncingSound.play();

}

}

// Move the ball

ballX=ballX+ballDeltaX;

ballY=ballY+ballDeltaY;

}

That’s really all there is to it. We have a game with sound effects, animation, keyboard control and increasing scores written entirely in HTML and Javascript.

To make the game more fun, we can add more interesting brick types, sounds and game mechanics.

In my version of the game, the bricks start falling down, we have Cash bricks to give money, Bomb bricks that explode everything nearby, Laser Ammo bricks that let us shoot laser from the paddle and Spider bricks that shriek and start crawling down at the user. Check out the game to see what you think. Leave a comment if you enjoy the game.

I don’t see much point showing people how to implement the exact same features in a game, because at this point it is fairly simple to do. However if you have an interesting idea that you would like to add to the game, leave me a comment below. If we get a few interesting ideas, we can have one more tutorial where we implement the ideas and create our own new version of the game.