1

So I want to have a delay in my Draw function so that when I want to do

Xoffset = Xoffset + 1.5

I do not go from 0 to 30 in a secnd, but I want there to be some delay in the code so that I can easily manage it. I usually use scratch and if you are unfimiliar to that the command for a code delay is

Wait(Insert amount of seconds you want to delay here)

So when you start a part of the code, and the Wait is set to 2, the input will go off, wait 2 seconds, and then move on the the line of code below. I am trying to replicate that but in p5.js.

  • Have a look [here](https://stackoverflow.com/questions/12417937/create-a-simple-countdown-in-processing/12421641#12421641) , there's a p5.js example at the bottom. Out of curiosity, what's the connection between p5.js and mit-scratch for your problem ? – George Profenza Nov 18 '21 at 16:38
  • Have you tried using `setTimeout`? – CoderTang Nov 21 '21 at 17:34

2 Answers2

3

To detail my comment above, you could do something like this:

var xOffset = 0;

// time delay vars
// current time "snapshot" (imagine pressing the lap time button)
var time;
// the interval to wait between time "snapshots": 2s (2000 milliseconds) in this case
var wait = 2000;

function setup() {
  createCanvas(300, 300);
  
  //store the current time
  time = millis();
}

function draw() {
  background(220);
  //check if the difference between now and the previously stored time
  // is greater than the wait interval
  if(millis() - time >= wait){
    console.log(wait, "ms passed");
    //if it is, do something
    xOffset = xOffset + 1.5;
    //also update the stored time
    time = millis();
  }
  
  circle(xOffset, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>

I'm not sure what the main purpose of the delay is:

  1. is it to slow things down for debugging purposes
  2. is to go into a series a states (e.g. ball moves up for 2s, then right 2s, etc.),
  3. is to animate/smoothly interpolate between two positions within a given time ?

Maybe something else completely ?

If you simply want to slow things down, perhaps it might be simpler to adjust the frameRate():

var xOffset = 0;

function setup() {
  createCanvas(300, 300);
  
  // update 1 frame every two seconds => 0.5 fps
  frameRate(0.5);
}

function draw() {
  background(220);
  
  xOffset = xOffset + 1.5;
  
  circle(xOffset, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>

Processing still has a delay() function, but p5.js doesn't. Personally I'm not a fan of blocking behaviour like this and prefer the millis() options even though it's more verbose. That being said, if the program/demo you write is super simple delay() might just be enough.

Even if delay() is missing you could use js setTimeout() with a Promise, but that's getting into more advanced JS as Paul already mentioned:

var xOffset = 0;

function setup() {
  createCanvas(300, 300);
  // prevent p5's default draw() updates
  noLoop();
}

function draw() {
  background(220);
  
  xOffset = xOffset + 1.5;
  
  circle(xOffset, 150, 60);
  
  // wait 2s then call draw() manually
  delay(2000).then(draw);
}

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>

Now, if you want to create a smooth animation from a start x offset to an end offset in a set amount of seconds you'd need a different approach. You can find a p5.js example at the of this answer:

var startTime;
var duration = 2000;
var startValue = 0;
var endValue = 300;
var currentValue = startValue;

function setup(){
  createCanvas(300, 300);
  textAlign(RIGHT);
  startTime = millis();
}
function draw(){
  background(255);
  moveCircle();
  drawCircle();
}
function drawCircle() {  
 circle(currentValue, 150, 60);
}

function moveCircle(){
  var progress = (float)(millis()-startTime)/duration;//millis()-startTime = difference in time from start until now
  if(progress < 1.0) currentValue = startValue + (endValue * progress);//the current value is the final value scaled/multiplied by the ratio between the current duration of the update and the total duration
}
function mousePressed(){//reset value and time
  currentValue = startValue;
  startTime = millis();
}
function keyPressed(){//update duration
  if(key == '-') if(duration > 0) duration -= 100;
  if(key == '=' || key == '+') duration += 100;
  console.log("duration: " + duration);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>

And if you're comfortable using external libraries you could simply use a tweening library such as gsap:

var x = 0;

function setup(){
  createCanvas(300, 300);
  // animate "this" global object's x property to 300 in 2 seconds
  gsap.to(this, {x: 300, duration: 2});
}

function draw(){
  background(255);
  circle(x, 150, 60);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js"></script>

Notice the animation has a bit of easing (default ease out) which could be nice.

George Profenza
  • 50,687
  • 19
  • 144
  • 218
2

In JavaScript, unlike Scratch, there is not a good way to delay synchronous* code. The reason for this is that all the functionality of a webpage is run using a single thread. Which means that while there can be multiple sequences of instructions performing different pieces of functionality, only one of those sequences can execute at a time. Therefore if you did something to delay the execution of JavaScript within the draw() function, it would block all other functionality, making the browser tab unresponsive (and potentially causing the browser to halt your JavaScript altogether).

Instead of pausing a series of JavaScript statements like one would do in Scratch, it is necessary to either use the amount of time that has elapsed as part of a condition that determines whether some code should run (which is what the example George shared in the comments does), or to use the built in setTimeout() function to schedule some code to run some number of milliseconds in the future (but you would not want to call setTimeout() from draw() because it would repeatedly schedule the code every frame).

* note: there are also ways to create delays using asynchronous javascript code, but this is a more advanced topic

Paul Wheeler
  • 18,988
  • 3
  • 28
  • 41