Code structure

Code gets too complex after a while. Following one simple rule can help you from preventing your code to become too complex:

Every time you duplicate code, you’ll have to die a little inside.

Reduce the amount of duplicate code by grouping code in functions and classes.

code_duplication_meme
Don’t duplicate code!

Duplicating objects

How to duplicate objects on the canvas while not duplicating code?

Don’t do this:

let xPositionBlob1;
let yPositionBlob1;
let xVelocityBlob1 = 2;
let yVelocityBlob1 = 3;

let xPositionBlob2;
let yPositionBlob2;
let xVelocityBlob2 = -2;
let yVelocityBlob2 = 4;

//etc...

Instead use classes to “bundle” variables together. A class is like a “recipe” for an object, in this case a Blob.

// The class is like a recipe
class Blob {

    constructor(){
        this.xPosition = 0;
        this.yPosition = 0;
        this.xVelocity = 2;
        this.yVelocity = 3;
    }
}

To make the actual “dish” (an object) you have to use the “recipe” (the class). This is called “instantiating” the class. You can make as many blobs as you want.

graph TD A[Class] --instatiates--> B[Object] A --instatiates--> C[Object] A --instatiates--> D[Object] A --instatiates--> E[...]

Here’s how you make two blobs:

// The class is used like any datatype (such as int, float, String, etc.)
Blob blob =  new Blob();
Blob blob2 = new Blob();

void draw(){
    circle(blob.xPosition, blob.yPosition, 10);
    circle(blob2.xPosition, blob2.yPosition, 10);

    // Update the variables in the objects
    blob.xPosition+=blob.xVelocity;
    blob.yPosition+=blob.yVelocity;
    blob2.xPosition+=blob2.xVelocity;
    blob2.yPosition+=blob2.yVelocity;
}

Still messy. Lot’s of copied code. Lets make the blob update and draw itself:

class Blob {

    constructor(){
        this.xPosition = 0;
        this.yPosition = 0;
        this.xVelocity = 2;
        this.yVelocity = 3;
    }

    update(){
        this.xPosition+=this.xVelocity;
        this.yPosition+=this.yVelocity;
    }

    draw(){
        circle(this.xPosition, this.yPosition, 10);
    }
}

Now the draw function is much cleaner:

Blob blob =  new Blob();
Blob blob2 = new Blob();

function setup(){
    createCanvas(400, 400);
}

function draw(){
    blob.update();
    blob.draw();
    blob2.update();
    blob2.draw();
}

Lots of blobs

Using an array it’s possible to store and draw lots of blobs.

// with the previously described "blob" class included:

// Make a lost to put blobs in:
let blobs = [];

void setup(){
    createCanvas(400, 400);

    // Add 100 blobs to the list
    for (let iBlob=0; iBlob<100; iBlob++)
        blobs.push(new Blob());
}

void draw(){
    // Traverse the list and update each blob
    for (let iBlob=0; iBlob<100; iBlob++){
        blobs[iBlob].update();
    }

    // Use a for-each loop to draw each blob
    blobs.forEach(blob => blob.draw());
}
Spawning 100-blobs example

Determine start position and start velocity

Using the constructor, the function that is called when a blob is created, you can give new blobs a starting position.

class Blob {
    constructor(x, y, vX, vY){
        this.xPosition = x;
        this.yPosition = y;
        this.xVelocity = vX;
        this.yVelocity = vY
    }

    // etc...
}

Add new blobs

Add a new blob to the list when the mouse is pressed.

function draw(){
    
    // Somewhere in the frame:
    if (mousePressed){
        blobs.add(new Blob(mouseX, mouseY, random(-4,4), random(-4, 2)));
    }

    // etc.
}
Click the mouse in the canvas to spawn a some blobs.