# Time synched animation

**URL:** <https://discourse.processing.org/t/time-synched-animation/17685>\
**Category:** Coding Questions\
**Created:** [February 10, 2020, 9:22am UTC](https://discourse.processing.org/t/time-synched-animation/17685 "2020-02-10T09:22:51Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![BrokenCode](https://avatars.discourse-cdn.com/v4/letter/b/9de0a6/32.png) [@BrokenCode](https://discourse.processing.org/u/BrokenCode)\
**Post date:** [February 10, 2020, 9:22am UTC](https://discourse.processing.org/t/time-synched-animation/17685/1 "2020-02-10T09:22:51Z")

</div>

Hello everyone, here I’m trying to divide the screen with a grid, then fill each tile in a pre-determined amount of time: (this is the most simplified - even silly - example)

```auto
float timeToConsume = 7, timeToCancelBin;
int timer, counter;
ArrayList<GridPoint> points = new ArrayList<GridPoint>();
float tileWidth = 20, tileHeight = 20;

void setup() {
  size(1280, 720);
  noStroke();
  // creo una griglia in base a width e height e alla larghezza dei riquadri tileWidth e tileHeight
  // li aggiungo all'arraylist points in modo da poterli richiamare in seguito
  for (float x = 0; x < width; x += tileWidth) {
    for (float y = 0; y < height; y += tileHeight) {
      points.add(new GridPoint(x, y, tileWidth, tileHeight));
    }
  }
  
  timeToCancelBin = (timeToConsume * 1000) / points.size();
  println(points.size() + " " + timeToConsume + " " + timeToCancelBin);
}

void draw() {
  background(255);

  // controllo se la variabile black sia vera o falsa, nel caso colora il rettangolo di nero
  for (int i = 0; i < points.size(); i++) {
    if (points.get(i).black) {
      fill(0);
    } else {
      noFill();
    }
    points.get(i).show();
  }

  if (millis() - timer >= timeToCancelBin) {
    ruin();
    timer = millis();
  }
}

void ruin() {
  if (counter < points.size()) {
    GridPoint p = points.get(counter);
    p.black = true;
  }

  counter++;

  if (counter == (points.size())) {
    println(millis());
  }
}

class GridPoint {
  float x, y, tileWidth, tileHeight;
  boolean black = false;

  GridPoint(float x, float y, float tileWidth, float tileHeight) {
    this.x = x;
    this.y = y;
    this.tileWidth = tileWidth;
    this.tileHeight = tileHeight;
  }

  void show() {
    rect(x, y, tileWidth, tileHeight);
  }
}

```

My problem is that it doesn’t fill all the tiles in the given amount of time, and if you modify the width and the height (so the total number) of tiles it vary also the time…  
What am I doing wrong here? Thank you

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [February 10, 2020, 1:37pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/2 "2020-02-10T13:37:44Z")

</div>

The problem is that processing makes only 60 frames per second.

Hence, one frame is approx. 20 millis.

I made a print of the millis of every frame:

```auto
2304
 7.0 
timeToCancelBin: 3.0381944

140
162
177
194
211
228
245
261
278

```

Your timeToCancelBin is 3.03 millis, so much less than needed for one frame.

So when your condition ` if (millis() - timer >= timeToCancelBin) {` is met, much more time than timeToCancelBin has passed. But counter gets only increased by one. It should be increased by the amount of timeToCancelBin that has passed (like 15 times, with a for loop). That is one solution for example.

**My version**

Another approach:

Instead, I made a version were each rect knows the time when to turn black.

Much more than 1 rect gets black every frame.

```auto

float timeToConsume = 7.0, timeToCancelBin;
// int timer, counter;
ArrayList<GridPoint> points = new ArrayList<GridPoint>();
float tileWidth = 20, tileHeight = 20;

void setup() {
  size(1280, 720);

  noStroke();
  // creo una griglia in base a width e height e alla larghezza dei riquadri tileWidth e tileHeight
  // li aggiungo all'arraylist points in modo da poterli richiamare in seguito
  int k=0; 
  for (float x = 0; x < width; x += tileWidth) {
    for (float y = 0; y < height; y += tileHeight) {
      points.add(new GridPoint(x, y, tileWidth, tileHeight, 0));
      k++;
    }
  }

  timeToCancelBin = (timeToConsume * 1000.0f) / points.size();
  println(points.size() + "\n " + timeToConsume + " \ntimeToCancelBin: " + timeToCancelBin);

  // tell each rect when to turn black 
  for (int i = 0; i < points.size(); i++) {
    points.get(i).time=i*timeToCancelBin;
  }
}

void draw() {
  background(255);

  for (int i = 0; i < points.size(); i++) {
    points.get(i).show();
  }

  // finished? 
  if (points.get(points.size()-1).black) {
    println("finished "+millis());
    noLoop();
  }
}

// ======================================================================================

class GridPoint {

  float x, y, 
    tileWidth, tileHeight;
  boolean black = false;

  float time; 

  GridPoint(float x, float y, 
    float tileWidth, float tileHeight, 
    float time) {

    this.x = x;
    this.y = y;
    this.tileWidth = tileWidth;
    this.tileHeight = tileHeight;

    this.time = time;
  }//constr 

  void show() {
    if (millis() >= time)
      black=true; 

    // controllo se la variabile black sia vera o falsa, nel caso colora il rettangolo di nero
    if (black) {
      fill(0);
    } else {
      noFill();
    }

    rect(x, y, 
      tileWidth, tileHeight);
  }
  //
}//class
//

```

In another version, we can see how much rects turn black every frame (one star `*` is one rect in the list, one line is a new frame):

```auto
******
-----------------
*****
-----------------
******
-----------------
*****
-----------------
******
-----------------
*****
-----------------
*****

```

Chrisir

---

<div class="post-metadata">

**Author:** ![BrokenCode](https://avatars.discourse-cdn.com/v4/letter/b/9de0a6/32.png) [@BrokenCode](https://discourse.processing.org/u/BrokenCode)\
**Post date:** [February 10, 2020, 6:32pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/3 "2020-02-10T18:32:42Z")

</div>

This different point of filling the rects is very clever I must admit! I’m not sure if the result of having block of rects filling up is something as acceptable in terms of _“beauty”_ instead as having them go black one by one, but the approach is really interesting! 😁

Talking about my original method, your thought is that in theory I just need my `timeToCancelBin` to be greater than 20ms, in order to match the `frameRate` and it should works. But aren’t `millis()` and `frameRate` independent? I mean let assume that `timeToCancelBin = 10 ms`, then if one frame last `20 ms` then every frame I’ll get 2 filled rect. If `timeToCancelBin = 5 ms` then in the next frame I should see 4 rect black filled.

What I think is that the computer is too fast on keeping track of `millis()` that the fraction of time that needs to count `3 ms` is so little that it miss the `if statement`, and all this very little milliseconds delays sums up and in a very short amount of time they become seconds.

---

<div class="post-metadata">

**Author:** ![BrokenCode](https://avatars.discourse-cdn.com/v4/letter/b/9de0a6/32.png) [@BrokenCode](https://discourse.processing.org/u/BrokenCode)\
**Post date:** [February 10, 2020, 10:02pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/4 "2020-02-10T22:02:06Z")

</div>

Another consideration:  
with this approach the animation starts in the exact moment `millis()` starts.  
Is there a way to control when the animation should start / pause / reverse?  
The following code doesn’t work because of the behaviour of `millis()` (and the `for (int i = points.size()-1; i > 0; i--)` starts straight from the end and not from the point where i press the mouse) but it should give an idea:

```auto
float timeToConsume = 7.0, timeToCancelBin;
ArrayList<GridPoint> points = new ArrayList<GridPoint>();
float tileWidth = 20, tileHeight = 20;
int counter;

void setup() {
  size(1280, 720);
  noStroke();

  for (float x = 0; x < width; x += tileWidth) {
    for (float y = 0; y < height; y += tileHeight) {
      points.add(new GridPoint(x, y, tileWidth, tileHeight, 0));
    }
  }

  timeToCancelBin = (timeToConsume * 1000.0f) / points.size();

  for (int i = 0; i < points.size(); i++) {
    points.get(i).time = i * timeToCancelBin;
  }
}

void draw() {
  background(255);

  if (change) {
    for (int i = 0; i < points.size(); i++) {
      points.get(i).black();
    }
  } else {
    for (int i = points.size()-1; i > 0; i--) {
      points.get(i).notBlack();
    }
  }
}

boolean change = true;

void mousePressed() {
  change = !change;
}

class GridPoint {
  float x, y, tileWidth, tileHeight;
  boolean black = false;
  float time;

  GridPoint(float x, float y, float tileWidth, float tileHeight, float time) {
    this.x = x;
    this.y = y;
    this.tileWidth = tileWidth;
    this.tileHeight = tileHeight;
    this.time = time;
  }

  void black() {
    if (millis() >= time)
      black = true; 
    if (black) {
      fill(0);
    } else {
      noFill();
    }
    rect(x, y, 
      tileWidth, tileHeight);
  }

  void notBlack() {
    if (millis() >= time)
      black=false; 
    if (black) {
      fill(0);
    } else {
      noFill();
    }
    rect(x, y, 
      tileWidth, tileHeight);
  }
}

```

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [February 10, 2020, 10:34pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/5 "2020-02-10T22:34:04Z")

</div>

I don’t have time now

But to your very first post again

I tried to explain:

after every frame approx. 20 millis have passed. Condition

```auto
  if (millis() - timer >= timeToCancelBin) {

```

is ALWAYS true.

BUT counter is only increased by one.

Test it with println()

Chrisir

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [February 10, 2020, 10:41pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/6 "2020-02-10T22:41:09Z")

</div>

> something as acceptable in terms of _“beauty”_ instead as having them go black one by one

Err… there are too many rects than you can fill within 7 seconds. The frameRate is too low.

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [February 10, 2020, 10:44pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/7 "2020-02-10T22:44:09Z")

</div>

> [@BrokenCode](#):
>
> then if one frame last `20 ms` then every frame I’ll get 2 filled rect.

That’s wrong because counter gets only increased by one in every frame.

As I said you could do a for loop to increase counter by 2 or even 4.

> [@BrokenCode](#):
>
> What I think is that the computer is too fast on keeping track of `millis()` that the fraction of time that needs to count `3 ms` is so little that it miss the `if statement` , and all this very little milliseconds delays sums up

That’s wrong because the if checks for \>= so it cannot miss it.

It misses them because of the frame rate.

---

<div class="post-metadata">

**Author:** ![BrokenCode](https://avatars.discourse-cdn.com/v4/letter/b/9de0a6/32.png) [@BrokenCode](https://discourse.processing.org/u/BrokenCode)\
**Post date:** [February 13, 2020, 5:52pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/8 "2020-02-13T17:52:36Z")

</div>

> [@Chrisir](#):
>
> That’s wrong because the if checks for \>= so it cannot miss it.

Well if i run this:

```auto
int timer;
void draw() {
  if (millis() - timer >= 20){
    println(millis() - timer);
    timer = millis();
  }
}

```

I get this values in the post window:

```auto
181
33
33
34
33
34
33
33
34
33
33
33
33
33
34
34
32
34
33
33
34
33
33
34
33
34
33
33
34
34
33
33
34
33
32
35
32
34
41

```

That means that there is something that skip through the 20 ms limits. And this is with no other threads or calculations. If I try the real sketch I get reasonably values only with limits around 150 ms

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [February 13, 2020, 7:10pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/9 "2020-02-13T19:10:52Z")

</div>

> [@BrokenCode](#):
>
> println(millis() - timer);

Try please

println(millis() );

---

<div class="post-metadata">

**Author:** ![BrokenCode](https://avatars.discourse-cdn.com/v4/letter/b/9de0a6/32.png) [@BrokenCode](https://discourse.processing.org/u/BrokenCode)\
**Post date:** [February 13, 2020, 7:19pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/10 "2020-02-13T19:19:37Z")

</div>

This is the result I get running this code:

```auto
int timer;
void draw() {
  if (millis() - timer >= 20){
    println(millis());
    timer = millis();
  }
}

```

```auto
192
224
258
290
324
358
390
458
490
524
557
590
624
656
691
724
758
790
823
857
891
923
957
992
1023
1058
1090
1123
1157

```

Thank you for helping 🙂

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [February 13, 2020, 7:20pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/11 "2020-02-13T19:20:46Z")

</div>

What does this prove? Where have I been wrong?

---

<div class="post-metadata">

**Author:** ![BrokenCode](https://avatars.discourse-cdn.com/v4/letter/b/9de0a6/32.png) [@BrokenCode](https://discourse.processing.org/u/BrokenCode)\
**Post date:** [February 13, 2020, 7:29pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/12 "2020-02-13T19:29:28Z")

</div>

To me, this seems to be the case where too fast calcutions are asked… counting milliseconds may be a demanding task and as you can see the most basic sketch (at least on my pc) can count `millis()` with a `~30ms` jump.  
This makes me think that if I set `timeToCancelBin` too low, ex `15` the pc isn’t fast enough to stop at `15`, because it immediatly jump at `30`. A `15ms` offset, in a second becomes `~400ms` and in `10s` there will be a `4s` offset

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [February 13, 2020, 7:35pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/13 "2020-02-13T19:35:41Z")

</div>

maybe we just mean the same thing.

Your code `if (millis() - timer >= 20) ` asks to print something every 20 mills.

Your data

> [@BrokenCode](#):
>
> 34 32 34

shows that processing doesn’t reach this speed because it’s too slow. ( the output 258 - 290 - 324 shows the same).

In your sketch with the rects the sketch also was too slow and therefore to slowly doing the counter++ command. To tackle this, you could measure **how often** the `timeToCancelBin` has been missed since the last call. You need to increase counter by this number.

So, no, the the computer isn’t too fast as you wrote previously, if it were, the measurement of millis() would stop him.

It’s too slow.

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [February 14, 2020, 7:43pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/14 "2020-02-14T19:43:22Z")

</div>

Hello,

Some code to show what happens each frame (framecount) at the 20 ms condition for 60 fps and 30 fps:

```auto
int timer;
int timeLast;

void setup()
  {
  //frameRate(60); //1000/60 = 16 (integer) 16.666666 float
  //println(1000/60);
  //println(1000.0/60);
  
  frameRate(30); //1000/30 = 16 (integer) float 33.333332
  println(1000/30);
  println(1000.0/30);
  
  delay(2000);
  }

void draw() 
  { 
  //Prints only when condition met; once every two frames  
  if (millis() - timer >= 20)
    {
    println();
    println(frameCount, millis());
    timer = millis();
    }
  //Prints time between frames; once per frame
  println(frameCount, millis()- timeLast);  
  timeLast = millis();
  }

```

30 fps (left) and 60 fps (right):

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/2/2b8fe50deaef68d765e467082a0e4b42606f9c3e.png) ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/7/7df3b0fb73a2485fe1b1d45bbd650c91e038232f.png)

’ 🙂 ’

---

<div class="post-metadata">

**Author:** ![BrokenCode](https://avatars.discourse-cdn.com/v4/letter/b/9de0a6/32.png) [@BrokenCode](https://discourse.processing.org/u/BrokenCode)\
**Post date:** [February 15, 2020, 1:57pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/15 "2020-02-15T13:57:58Z")

</div>

Thanks glv, this can be useful to know if the animation is delaying each frame!  
I tried to lowering the time condition to just `3 ms` and this is what I got:

```auto
int timer;
int timeLast;

void setup(){
  frameRate(60); //1000/60 = 16 (integer) 16.666666 float
  println(1000/60);
  println(1000.0/60);

  //frameRate(30); //1000/30 = 16 (integer) float 33.333332
  //println(1000/30);
  //println(1000.0/30);

  delay(2000);
}

void draw() { 
  //Prints only when condition met; once every two frames  
  if (millis() - timer >= 3)
  {
    println();
    println("TIMER "+ frameCount, millis() - timer);
    timer = millis();
  }
  //Prints time between frames; once per frame
  
  println("FRAME " + frameCount, millis() - timeLast);  
  timeLast = millis();
}

```

```auto
TIMER 2 18
FRAME 2 18

TIMER 3 17
FRAME 3 17

TIMER 4 16
FRAME 4 16

TIMER 5 17
FRAME 5 17

TIMER 6 17
FRAME 6 17

TIMER 7 17
FRAME 7 17

```

Does this means that you can’t have a condition less than `16 ms` at `60 fps` and less than `33 ms` at `30 fps`?

---

<div class="post-metadata">

**Author:** ![jeremydouglass](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jeremydouglass/32/20_2.png) [@jeremydouglass](https://discourse.processing.org/u/jeremydouglass)\
**Post date:** [February 19, 2020, 6:45pm UTC](https://discourse.processing.org/t/time-synched-animation/17685/16 "2020-02-19T18:45:53Z")

</div>

> [@BrokenCode](#):
>
> Does this means that you can’t have a condition less than `16 ms` at `60 fps` and less than `33 ms` at `30 fps` ?

Yes, 1000 milliseconds divided by 60 frames = 16.667 milliseconds per frame.

If you are only going to perform one operation per frame, then you only get 60 operations a second. If you insist on changing only one unit per frame at 60fps then you cannot set a time goal – you can only find out how long it will take given the constraints you chose. If there are 600 then it will take ~10 seconds or more – on average and when not under load, frame rate varies and is a minimum, not a maximum.

You can set any conditions you want, but you can’t expect them to perform. For example, I can say “I want people to enter the subway through this single turnstile one at a time, one per second. Also, I want to let 100,000 people in an hour.” Well, that would take one person moving through the turnstile every 0.036 seconds. Turnstiles and people can’t move that fast, so that isn’t going to happen. You set the rules, but your goal doesn’t matter – what will _actually_ happen is that you well let in about 3600 people. You can either let in fewer people per hour, OR you can add more turnstiles. Either one, your choice. If you want to install rocket turnstiles that go 300 miles per hour (frameRate(300)) you may need special hardware!

You can also make the approach adaptive by looking at your goal, estimating how many frame you have until your goal, and addressing that many units (1, 10, whatever). This is what grocery stores try to do when they open extra checkout lanes. When the lines start building up, they change their customer throughput.
