Article·Tutorials·May 12, 2023

# Playing With P5.js: Implementing Game Logic

By Kevin Lewis
PublishedMay 12, 2023
UpdatedJun 13, 2024

This is the second in a three-part series on P5.js (from here 'P5') - a creative coding library that makes working with the Canvas API much easier. In part one, we covered how to draw elements on the screen and react to keyboard and mouse input.

Today, we're taking that theoretical knowledge and building some features you may need when creating a game. Then, in next week's final part, we will add voice functionality to our game using Deepgram.

## Collision Detection

Every element you draw in a P5 sketch has a specific placement and size. Collision detection in games lets you know when one element overlaps with another or touches a location such as a wall. This is often used to avoid users going through walls or floors or to 'pick up' items such as food or hearts.

Assuming a collision check between you (the 'player') and another entity (a 'pick up'), a collision detection relies on four conditional checks:

1. Is your x position greater than the leftmost x position of the pickup?

2. Is your x position less than the rightmost x position of the pickup?

3. Is your y position greater than the topmost y position of the pickup?

4. Is your y position less than the bottommost y position of the pickup?

Let's start putting this into practice. Create an index.html file, open it in your code editor, and add the following to it:

To see your sketch running, just double click the index.html file in your file explorer and it will open in your default browser. To see new changes once you save your code, refresh the browser.

If the player is bigger than a single pixel point, you need to offset the conditionals by the size of the player. Try this:

If you want to learn more about collision detection, check out this lovely video by Dan Shiffman.

### Example: Blocking Walls

The P5-provided width and height variables are always set to the canvas values provided in createCanvas(). You can use these along with the collision detection conditionals above to ensure a user cannot navigate outside of the canvas.

Expanding on our keyboard user input introduction in last week's post, try this:

If a player attempts to set playerX or playerY outside of the allowed bounds, they are set at the bounds. This means a player will see their square stop moving.

## Entity Management

Games often have many entities: players, enemies, and items. Entities of the same category likely have similar logic but need to maintain their own state. In P5 sketches, it's common to use JavaScript classes for game entity management. Classes provide a blueprint for an object. They have their own properties, including data and functions (called 'methods' in a class). Try this code, and then we'll walk through it:

Starting at the bottom with the Bubble class. When a new class instance is created, it expects a starting x and y value, which is made available inside of the class as member properties called this.x and this.y. Two other member properties are also created - xOff (x offset) and yOff (y offset). More on these later.

This class has two methods - you can name methods whatever you want, but move and display are common in P5 sketches.

The move() method uses the P5-provided noise() function to return a value in a Perlin noise sequence. Perlin noise generates a random value that exists in a more natural-looking sequence - by very slightly modifying the value passed into noise(), the bubbles look to follow a 'path.' The small changes in xOff and yOff are used to move the bubbles smoothly. Perlin noise is fascinating, and I encourage you to read more about noise().

The display() method draws a circle at the new values stored in this.x and this.y.

During setup(), 100 Bubble instances are created with a starting position of (250, 100) and stored in the bubbles array. Every draw(), each bubble has it's move() and display() methods run.

The next example combines collision detection and entity management:

What's changed?

1. The frameRate(10) function in setup() drastically slows down the rate at which draw() is run from about 60 times per second to 10. This is only done to make this game playable.

2. There are only ten instances of Bubble created instead of 100.

3. Two new properties are now included in Bubble - radius and touched. The radius is used in the collision detection and when drawing the bubble.

4. A new checkifTouched() method is included in Bubble. This method determines the distance (dist()) between the mouse position and the bubble center (x, y). If it is less than the radius, you know a collision has taken place and set this.touched to true.

5. The color of the bubble changed once touched.

6. The checkIfTouched() method is called for every bubble in draw().

## Keeping Score

Currently, every bubble currently tracks its own state, but there is no global indication of how a player has scored. This can be implemented with a global variable. Follow these steps:

1. Add a global variable called score with a value of 0.

2. Inside of the Bubble.checkIfTouched() method, before this.touched is set to true, check if this.touched is still false, and then also increment score.

3. In the draw() function, set the color to white using fill('white'), and then display the score by using text().

In case you don't remember the parameters for text() that we went over in the previous post, text() takes three arguments - the text to display, and the (x,y) coordinates.

For step 2, the additional check is required to stop score incrementing more than once. If successful, your sketch should function like this:

## Starting, Winning, and Losing

Most games have a number of states - a landing page on load, the game itself, and an endgame. This state can often be held in global scope, and code that runs in draw() can be altered as a result. Leaving your Bubble class unchanged, try this to implement game state management:

The win variable starts as false, and when the score reaches three or more, the game logic stops running, and the text 'You Win!' will be shown instead.

This is a simplistic example, but the same approach can be taken to implement more game states.

## In Summary

Together with the first post in this series, I hope you have the tools you need to build a fun game with P5.js with these game logic implementations. For further inspiration, here are some of my favorite P5 examples:

Next week in the third and final part of this series, we'll cover how to integrate voice into your P5 sketches. Until then, please feel free to reach out to us on Twitter at @DeepgramDevs if you have any questions or thoughts.

If you have any feedback about this post, or anything else around Deepgram, we'd love to hear from you. Please let us know in our GitHub discussions .

## Unlock language AI at scale with an API call.

Get conversational intelligence with transcription and understanding on the world's best speech AI platform.