Ethan Nguyen
Ethan Nguyen

Reputation: 163

How to wait in p5.js

I'm trying to create a program that does something, waits for a set amount of time does another thing, then waits again. However, what actually happens is the program waits at the beginning then does both things without any delay between them.

var start, current
function setup() {
  createCanvas(500, 550);
}

function draw() {
  background(220);
  print('a');
  wait(500);
  print('b');
  wait(500);
}

function wait(time)
{
  start = millis()
  do
  {
    current = millis();
  }
  while(current < start + time)
}

Upvotes: 3

Views: 23906

Answers (3)

Real
Real

Reputation: 191

As mentioned, the problem in your attempt is that you're waiting inside the draw() loop. This doesn't work, because draw() is going to be called continually.

A simple way to do it is the following:

function setup() {
  //...
}

let task_done = false;
let last_done = 0;

function draw() {
  const delay = 1000 //ms
  if(!task_done) {
    /* do something */
    doSomething();
    task_done = true;
    last_done = millis();
  }
  else {
    if(millis() - last_done > delay) {
      task_done = false;
    }
  }
}

function doSomething() {
  //...
}

It only executes something every delay ms.

Upvotes: 1

RemyDekor
RemyDekor

Reputation: 76

The draw() function is executed several times per seconds (around 60 times per second, see framerate in the doc). This is also what we call a "draw loop".

Your logic seems to be very sequential (do this, then wait and to that, then wait and do another thing...), and maybe you should consider an other flow for your program than the draw loop.

If you want animation, the easy answer would be to stick to the answer provided by Rabbid76. (read and compare elapsed time millis every time the draw loop executes).

If you want one-time events (things that happen only once when a wanted duration is reached), you should look into Promises (or async-await functions), also known as asynchronicity. This subject can be confusing for beginners, but is very important in javascript.

Here is an example:
(link with p5 editor)

// notice we are NOT using the draw() loop here
function setup()
{
  createCanvas(400, 400);
  background('tomato')
  
  // try commenting-out one of these:
  doScheduleThings();
  doAsyncAwaitThings();
}


// you can wait for a Promise to return with the javascript 'then' keyword
// the function execution's is not stopped but each '.then(...)' schedules a function for when the Promise 'sleep(...)' is resolved
function doScheduleThings()
{
  sleep(2000).then(function() {
    fill('orange')
    ellipse(30,30, 50, 50)
  })
  sleep(1000).then(function() {
    fill('yellow')
    ellipse(130,30, 50, 50)
  })
}


// you can also wait for a Promise to return with an async-await function
// the function's execution is stopped while waiting for each Promise to resolve
async function doAsyncAwaitThings()
{
  await sleep(4000)
  fill('blue')
  rect(200,200, 50, 50)
  await sleep(1000)
  fill('cyan')
  rect(300,200, 50, 50)
}


// a custom 'sleep' or wait' function, that returns a Promise that resolves only after a timeout
function sleep(millisecondsDuration)
{
  return new Promise((resolve) => {
    setTimeout(resolve, millisecondsDuration);
  })
}

Upvotes: 5

Rabbid76
Rabbid76

Reputation: 211220

You cannot wait in the draw callback. The canvas is just updated when after draw was executed. You must evaluate the time in draw:

function draw() {
    background(220);

    let ms = millis()
    if (ms < 500) {
        // [...]
    }
    else if (ms < 1000) {
        // [...]
    }
    else {
        // [...]
    } 
}

Upvotes: 4

Related Questions