Using Timers in p5.js

Objectives and Overview

Lesson Objectives


Timing Events In Sketches

By now you’ve created enough sketches to understand the basic flow. The content inside the draw() loop repeats at a default rate of 60 frames per second, and once at the end of the code inside draw it loops back to the start and cycles. However, you may have had an idea that required you to utilize timing so that you could control when certain things happen. For example, what if you want a certain animation, change, or motion to occur after 5 seconds? This would be difficult to program since everything inside the draw() function repeats. This is where you’ll need to use another p5 command: millis().

Introducing millis()

P5 shares the millis() command with Processing and Arduino. Essentially, millis() is the amount of milliseconds elapsed since the sketch began. When you call millis() the returned value is the amount of milliseconds since the sketch started. This counter starts at 0 when you first run the sketch and increments until the sketch is stopped or the window is closed. What makes millis() so useful is that it provides a counter that is independent of the draw() loop. The value doesn’t reset to 0 every time through the draw() cycle.

When you first start using millis() as a timing tool it can be somewhat confusing. However, once you realize the way that the counter works you can choreograph powerful changes in your sketches that are extremely precise. Let’s take a look at some examples!

A Simple Counter

Using millis() returns the value of elapsed milliseconds, but this number can be hard to comprehend since it’s so large. This sketch converts the millis() value to seconds, and displays the total number of seconds the sketch has been running. Let’s look at the code:

function setup() { createCanvas(400, 400); } function draw() { background(0); fill(255, 0, 100); textSize(24); text(`${round(millis()/1000)} seconds have gone by!`, 20, height/2); }
Code language: JavaScript (javascript)

Running this sketch produces a timer that displays the seconds that the sketch has been active. In effect, it functions as a timer that counts up by 1 each second. Here’s a quick GIF of the sketch:

Animation of a p5 sketch using millis() as a timer

Note: The example starts at 2 seconds because I needed to hit record!

Now, let’s break down the code. You know that millis() constantly returns the current amount of elapsed milliseconds, but how does the code convert this to seconds?

Code Analysis

The conversation can be achieved by using three pieces of code: round(), millis(), and then dividing the value by 1000 to convert to seconds:

milliseconds / 1000 = seconds

The round() function is extremely useful. This takes the huge value returned by millis() and rounds it to a more digestible value. The return value of millis() divided by 1000 is passed as a parameter into round(). Let’s isolate that piece of code from the example: round(millis()/1000)

Note: This is a snippet from the longer example above and won’t run on its own.

In this snippet, the entire parameter passed into round is actually this: (millis() / 1000). This first converts the millis() value into seconds, and then rounds the seconds to the nearest whole integer. Go ahead and run this code to test it out!

Going Further: Tweaking the Code

When you run the sketch you’ll notice that it says “1 seconds have gone by!” which isn’t the correct way of saying this. This can be resolved by using some conditional logic to display another string if the value of millis() is 1 second. Try to solve this yourself before looking at the code example.

The output should look like this when the current time is 1 second, and then like the previous example for all other time values:

p5 sketch showing the output of changing 'second' to 'seconds' from a conditional logic check

Here’s one way of achieving this result:

function setup() { createCanvas(400, 400); } function draw() { background(0); fill(255, 0, 100); textSize(24); if ((round(millis()/1000)) == 1) { text(`${round(millis()/1000)} second has gone by!`, 20, height/2); } else { text(`${round(millis()/1000)} seconds have gone by!`, 20, height/2); } }
Code language: JavaScript (javascript)

There’s more than one way to solve this issue. The above code example uses a conditional statement to check if the current rounded value of millis() is equal to 1 and then outputs a specific text string.

The above examples should provide a foundation for using millis(). Next, let’s look at how to schedule events with millis()!

Scheduling Events With millis()

Once you’re comfortable with manipulating the value returned by millis() and how it converts to seconds elapsed in the sketch, you can start choreographing events that happen at specific points. For example, what if you want the background to change every second? Let’s take a look at an example of a sketch with a background that changes color every second.

Animation of a p5 sketch with a background color changing every second

If you leave the sketch running long enough, you may notice that it sometimes is out of sync with the console log time report. This is due to the rounded values in the console log. That is included to provide a visual counter showing that the background color is actually changing each second.

Here’s the code for this sketch:

let timer = 1000; let nextChange = timer; //syncs the timer and change rate function setup() { createCanvas(400, 400); } function draw() { if (millis() > nextChange) { r = random(0, 255); g = random(0, 255); b = random(0, 255); background(r, g, b); nextChange = millis() + timer; console.log(`time elapsed: ${round(millis() / 1000)}`); } }
Code language: PHP (php)

There are a few interesting pieces to note in the code. Work through it yourself first and try to understand it before moving forward to the code analysis.

Code Analysis

Let’s break down the pieces of code relating to scheduling the background change every second. At the top of the sketch, there are two global variables:

let timer = 1000; let nextChange = timer; //syncs the timer and change rate
Code language: JavaScript (javascript)

The timer variable represents milliseconds. Since the goal is to schedule a background change every second, this value is set to 1000.

Next, there is the nextChange variable that is set equal to timer. This initial declaration syncs the timer and the change rate. Go ahead and set this to 0 and see what happens!

Now let’s jump to the draw() function and examine the relevant code:

function draw() { if (millis() > nextChange) { r = random(0, 255); g = random(0, 255); b = random(0, 255); background(r, g, b); nextChange = millis() + timer; console.log(`time elapsed: ${round(millis() / 1000)}`); } }
Code language: PHP (php)

There is code to randomize the background color, but this has nothing to do with scheduling the timer. There are two pieces of code that comprise the core of the sketch.

The first core piece is the conditional statement: if (millis() > nextChange). Remember, the value returned by millis() is the current amount of time elapsed in the sketch. This code checks that the current time value is greater than the value of nextChange. Since nextChange is initialized to be the value of timer (1000 milliseconds), this code won’t start until 1 second has passed. Then, the next crucial piece of code kicks in:

The other core piece is this statement: nextChange = millis() + timer. This sets the value of nextChange to the current time plus 1 second. This is how the animation is able to be triggered every second. You’re essentially saying, “in 1 second, I want the background to change.” One second in the future is represented as the current time plus 1 second. The sketch considers every upcoming second as the current time plus 1 second.

Next Steps

The above examples provide a foundation for scheduling timed events. Now it’s time to try it out for yourself! Go ahead and work through the challenge below.

Challenge: What piece of code do you need to change to make something occur every 2 seconds or every 5 seconds? You can do this by only changing one thing. Try it out!

After you’ve solved this challenge, create a sketch that has an event that occurs after a set amount of time has elapsed.