Create p5.js Instances Sequentially in For Loop But Only After the Previous One Finishes

The basic question is in the title. I use a function to define a p5.js instance with a particular set of parameters. The sketch itself runs an in-browser video game. When any one out of a set of events occurs in the game, the sketch is removed, ending the game. Given an array of parameter values for the sketch, I use a for-loop to construct a sketch defined using each element of the array. I expected that in a single iteration of the for-loop, the defined sketch would complete (i.e. run until removal) before the for-loop progresses and the next sketch is defined and run. However, what actually happens is that as soon as a sketch is defined, the loop progresses and defines the next sketch. This results in all sketches running in the browser simultaneously.

How do I ensure that each sketch finishes before the next one runs? My guess is that I probably need to pass some variables to each sketch that call noLoop() and Loop() appropriately, but Iā€™m not sure. Below is a minimal working example in the form of an HTML file:

<!DOCTYPE html>
<html>
    <head>
        <script src="https://cdn.jsdelivr.net/npm/p5@1.2.0/lib/p5.js"></script>
    </head>
    <body></body>
    <script>

        /* Function to define sketch with parameter 'a' */
        function defineSketch(a) {
            let sketch = function(p) {
                let x = 100;
                let y = 100;

                p.setup = function() {
                    p.createCanvas(700, 410);
                };

                p.draw = function() {
                    p.background(0);
                    p.fill(255);
                    p.rect(x, y, a*50, a*50);
                };

                /* Remove sketch on mouse press */
                p.mousePressed = function() {
                    p.remove();
                };
            };
        }

        /* Initialize sketch variable */
        let trialSketch;

        /* Array of parameters */
        let param_seq = [0, 1, 2];

        /* For loop to sequentially run sketches with different parameters */
        for(let i = 0; i < param_seq.length; i++ ) {
            trialSketch = defineSketch(param_seq[i]);
            new p5(trialSketch);
        }

    </script>
</html>

Hi,

Welcome to the forum! :wink:

Why do you need to create different instances of p5 instead of running your game using the global context mode ?

I know that your example is a simplified one but passing arguments to each instance is the same as changing parameters in your sketch when the mouse is pressed for example :wink:

Hi josephh, thanks for your reply. I need multiple instances because the game is a task within a psychological experiment. Different types of experimental conditions take the form of different versions of the game, each of which is its own instance. I need to use instance mode and not global mode because I need to control the sequence of tasks, instruction windows, and surveys outside of the context of the sketch.

Hi nguzman,
you can set a boolean to check if a sketch is running or not, and set a listener on it as following ;

<!DOCTYPE html>
<html>
    <head>
        <script src="p5.min.js"></script>
    </head>
    <body></body>
    <script>

        // listened variable
        // we set a listner which wiil be fired each time the value of bool is changed.
        let sketchIsRunning = {
            $: false,
            listener: function(val) {},
            set bool(val) {
                this.$ = val;
                this.listener(val);
            },
            get bool() {
                return this.value;
            },
            registerListener: function(listener) {
                this.listener = listener;
            }
        };

        /* Function to define sketch with parameter 'a' */
        function defineSketch(a) {
            return function(p) {
                let x = 100;
                let y = 100;

                p.setup = function() {
                    p.createCanvas(700, 410);
                    console.log('cool')
                };

                p.draw = function() {
                    p.background(0);
                    p.fill(255);
                    p.rect(x, y, a*50, a*50);
                };

                /* Remove sketch on mouse press */
                p.mousePressed = function() {
                    p.remove();
                    sketchIsRunning.bool = !sketchIsRunning.bool
                    console.log('sketch is running ?', sketchIsRunning.bool)
                };
            };
        }

        /* Initialize sketch variable */
        let trialSketch;

        /* Array of parameters */
        let param_seq = [0, 1, 2];

        // we nest a call to the function itself to loop through the param.seq array
        const instanceP5sketches = (i  = 0) => {
            sketchIsRunning.$ = !sketchIsRunning.$;
            trialSketch = defineSketch(param_seq[i]);
            new p5(trialSketch);

            sketchIsRunning.registerListener(function(val) {
                if (param_seq.length - 1 >= i){
                    instanceP5sketches(i+1);
                } else {
                    console.log('No more sketches.')
                }
            });
        }

        instanceP5sketches();

    </script>
</html>

When the boolan is changed, we fire the change and create a new instance of p5. You can take a look to the MDN documentation to go further

2 Likes