Im looking for a function that is called once and is then rearmed according to a boolean state.
After some hacking around I found Pauls answer below was an effective way of executing / rearming a function inside the draw loop.
However I have found while incorporating this code with a class with more than one instance inside a for loop the function is being triggered and reset multiple times per instance. as per my example code below.
let instances = [];
function setup() {
createCanvas(400, 400);
for (let i = 0; i < 4; i++) {
instances.push(new Ball(50, random(30,370)));
}
}
const [happenOnce, reset] = makeRunOnce(() => {
console.log("ball has crossed the line!");
});
function makeRunOnce(fn) {
let hasRun = false;
return [
// run
() => {
if (!hasRun) {
fn();
hasRun = true;
}
},
// reset
() => {
hasRun = false;
}
]
}
function draw() {
background(220);
line(200, 0, 200, height);
for (let i = 0; i < instances.length; i++) {
instances[i].showBall();
instances[i].moveBall();
if(instances[i].returnTrue()) {
happenOnce();
} else {
reset();
}
}
}
class Ball{
constructor(x, y) {
this.x = x;
this.y = y
this.r = 10;
this.t = random();
}
showBall() {
ellipse(this.x, this.y, this.r * 2);
}
moveBall() {
this.x += this.t;
}
returnTrue() {
return this.x + this.r > 200;
}
}
Anyone have any suggestions on how I can have the function execute once when the class method returns true and resets when false for every instance?
It seems like you might be over complicating things a little bit, but all you need here is the ability to reset that executed flag back to false. Here is an example with a helper function makeRunOnce which takes a function and returns two functions in an array. The first function runs the original function only the first time it is called (either initially or after a reset), and the second function resets the state back to uncalled. To test this example, clicking draws a circle the first time you click, additional clicks will be ignored, until you double click which resets the state such that the next click will draw another circle.
function setup() {
createCanvas(windowWidth, windowHeight);
}
const [drawCircleOnce, resetDrawCircle] = makeRunOnce(() => {
ellipse(mouseX, mouseY, 20, 20);
});
let mouseHasBeenClicked = false;
function draw() {
if (mouseHasBeenClicked) {
drawCircleOnce();
} else {
resetDrawCircle();
}
}
// Note: instead of setting the mouseHasBeenClicked flag here
// we could just call drawCircleOnce() directly, and then
// resetDrawCircle() in doubleClicked. The draw() function would
// then be a no-op. I've use this flag to more closely
// approximate the apparent structure of your code.
function mouseClicked() {
mouseHasBeenClicked = true;
}
function doubleClicked() {
// reset
mouseHasBeenClicked = false;
}
function makeRunOnce(fn) {
let hasRun = false;
return [
// run
() => {
if (!hasRun) {
fn();
hasRun = true;
}
},
// reset
() => {
hasRun = false;
}
]
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>