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”) ![]()
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 ![]()
![]()