How to run a function every n frames in Processing? A mini callback tutorial

The draw() loop runs 60 times per second. That’s great for animation, but what if you want something to happen only every n frames?

A quick way to do it is to use frameCount and the modulo operator, like so:

if(frameCount % 60 == 0) {
  // something to do once every 60 frames
}

That works well, and is all you need for a one-off. But if you find yourself reaching for that pattern often, it’s worth wrapping it into a helper function.

Besides, this will be a good excuse to learn about a Java feature that I haven’t really seen in Processing tutorials before: passing a function as an argument (also known as a “callback function”) :smiley:

In Java we do this with a Runnable, a small wrapper that represents a function as a value.

Say we have a function changeScene() that we want to call every 60 frames.

We start by storing it in a Runnable variable using a method reference:

Runnable onNextScene = this::changeScene;

Note: this refers to your sketch, which extends PApplet under the hood.

If you prefer, you can write the same thing as a lambda (both are equivalent):

Runnable onNextScene = () -> changeScene();

Now that changeScene is stored as a value, we can call it with .run():

onNextScene.run(); // calls changeScene()

And since it’s just a variable, we can pass it to another function as an argument:

doEvery(60, onNextScene);

That’s all doEvery needs to do its job. It receives a Runnable and calls .run() at the right moment:

void doEvery(int frameInterval, Runnable callback) {
  if (frameCount % frameInterval == 0) {
    callback.run();
  }
}

Here’s the full sketch putting it all together:

Runnable onNextScene;

color bg = color(175);
int shapeType = 0;

void setup() {
  size(400, 400);
  colorMode(HSB);
  
  // Equivalent to onNextScene = () -> changeScene();
  onNextScene = this::changeScene;
}

void draw() {
  background(bg);

  doEvery(60, onNextScene);
  
  stroke(255);
  strokeWeight(2);
  
  switch(shapeType) {
    case 0: ellipse(200, 200, 150, 150);            break;
    case 1: rect(125, 125, 150, 150);               break;
    case 2: triangle(200, 125, 275, 275, 125, 275); break;
  }
}

void changeScene() {
  bg = color(random(255), random(240, 255), random(200, 255));
  shapeType = (shapeType + 1) % 3;
}

// Run the given callback function every frameInterval frames
void doEvery(int frameInterval, Runnable callback) {
  if (frameCount % frameInterval == 0) {
    callback.run();
  }
}

Credit to @neill for the p5.js-based inspiration :blue_heart::cherry_blossom:

Here are some other examples of probability functions taking inspiration from this p5.js sketch by @neill:

Runnable onColorChange;

color bg = color(175);
int shapeType = 0;
int lineWeight = 1;

void setup() {
  size(400, 400);
  colorMode(HSB);
  onColorChange = this::randomizeBackground;
}

void draw() {
  background(bg);
  
  // 5% chance of changing background each frame. Try tweaking this!
  sometimes(0.05, onColorChange);
  
  // 10% chance of changing shape each frame
  occasionally(() -> {
    shapeType = (shapeType + 1) % 3;
  });
  
  // Coin flip each frame: nudge position and randomize stroke weight
  fiftyFifty(() -> {
    translate(random(-4,4), 0);
    lineWeight = (int)random(1, 10);
  });
  
  stroke(255);
  strokeWeight(lineWeight);
  noFill();
  
  switch(shapeType) {
    case 0: ellipse(200, 200, 150, 150);            break;
    case 1: rect(125, 125, 150, 150);               break;
    case 2: triangle(200, 125, 275, 275, 125, 275); break;
  }
}

void randomizeBackground() {
  bg = color(random(255), random(180, 200), random(200, 210));
}

// Call the callback with the given probability (0.0–1.0)
void sometimes(float probability, Runnable callback) {
  if (random(1) < probability) {
    callback.run();
  }
}

// Call the callback 50% of the time
void fiftyFifty(Runnable callback) {
  sometimes(0.5, callback);
}

// Call the callback 10% of the time
void occasionally(Runnable callback) {
  sometimes(0.1, callback);
}