CODE //
EXPLORE //
CREATE //
01
Building Musical Worlds

Behaviour

Let's go back to the file ORGANISM1.js and get straight to adding those additional behaviours.

Feeding

Within the update method, above where we added the movement, let's add the feeding behaviour, and let's also create a need for feeding by making the organism's energy gradually deplete over time:


    var partner = false;

    // FEEDING //
    if (!partner && this.energy < this.settings.feedCap) {
        var target = null;
        var range = this.settings.feedRange;
        for (j=0; j<spores.length; j++) {
            var organism = spores[j];
            if (organism.variant && distanceBetweenPoints(this.position, organism.position) < range ) {
                target = organism;
                range = distanceBetweenPoints(this.position, organism.position);
            }
        }
        if (target) {

            // point towards target //
            this.angleDest = angleBetweenPoints(this.position, target.position);

            // if close enough to target, eat it! //
            if (distanceBetweenPoints(this.position, target.position) < this.settings.feedProximity) {
                this.energy += (target.size * 1.5);
                target.kill();
            }
        }
    }


    // ENERGY //
    this.energy -= 0.005;
    if (this.energy <= 0) {
        this.kill();
    }
        

The above code checks to see if the organism needs to eat, then loops through all available food to see if there is any in range, and if so, adjusts its angle to point towards it.

Currently the organisms are chasing their food but not actually eating it. We need to make it so that both this organism and it's food can die. Scroll down to the method named kill and update it to look like:


Organism1.prototype.kill = function() {
    removeFromArray(this, org1);
    var area = 30 * scale;
    generateSpores(this.size * 0.72, this.position.x - area, this.position.y - area, this.position.x + area, this.position.y + area);
};
        

Now when an organism1 dies, it gets deleted from the array of instances, and creates a cloud of spores in its place.

We need to do the same for its food, spore. So go to the file SPORES.js and go to the kill method. Update it to:


Spore.prototype.kill = function() {
    removeFromArray(this, spores);
};
        

Breeding

OK so let's head back to the file ORGANISM1.js to add the last big behaviour. At the top of the update method, we need to replace this line:


    var partner = false;
        

with:


    // BREEDING //
    if (this.energy > this.settings.breedEnergy) {
        var partner = null;
        var range = this.settings.breedRange;

        // check for potential partners //
        for (j=0; j<org1.length; j++) {
            var organism = org1[j];
            if (organism!== this && organism.energy > this.settings.breedEnergy && distanceBetweenPoints(this.position, organism.position) < range ) {
                partner = organism;
                range = distanceBetweenPoints(this.position, organism.position);
            }
        }
        if (partner) {
            // point towards partner //
            this.angleDest = angleBetweenPoints(this.position, partner.position);
            if (this.speed < partner.speed) {
                this.speed -= this.settings.fluctuation;
            } else {
                this.speed += this.settings.fluctuation;
            }

            // if close enough to partner, breed! //
            if (distanceBetweenPoints(this.position, partner.position) < this.settings.breedProximity) {
                var area = 10 * scale;
                generateOrganism1(1, this.position.x - area, this.position.y - area, this.position.x + area, this.position.y + area);
                generateVisual(this.position, this.size);
                soundEvent(this.settings.soundVolume, this.settings.soundAttack, this.settings.soundRelease);
                this.energy -= 5;
                partner.energy -= 5;
            }
        }
    }
        

Similar to the feeding code, the breeding code checks if an organism has enough energy to breed before looping through any potential partners and seeing if they're close by. If so they'll head towards them, and when close enough, create brand new instances of organism1.

We've added a lot of code to the update method now! It could be improved in future by separating each behaviour into its own method. As it stands that whole function should look like this:


Organism1.prototype.update = function() {

    // BREEDING //
    if (this.energy > this.settings.breedEnergy) {
        var partner = null;
        var range = this.settings.breedRange;

        // check for potential partners //
        for (j=0; j<org1.length; j++) {
            var organism = org1[j];
            if (organism!== this && organism.energy > this.settings.breedEnergy && distanceBetweenPoints(this.position, organism.position) < range ) {
                partner = organism;
                range = distanceBetweenPoints(this.position, organism.position);
            }
        }
        if (partner) {
            // point towards partner //
            this.angleDest = angleBetweenPoints(this.position, partner.position);
            if (this.speed < partner.speed) {
                this.speed -= this.settings.fluctuation;
            } else {
                this.speed += this.settings.fluctuation;
            }

            // if close enough to partner, breed! //
            if (distanceBetweenPoints(this.position, partner.position) < this.settings.breedProximity) {
                var area = 10 * scale;
                generateOrganism1(1, this.position.x - area, this.position.y - area, this.position.x + area, this.position.y + area);
                generateVisual(this.position, this.size);
                soundEvent(this.settings.soundVolume, this.settings.soundAttack, this.settings.soundRelease);
                this.energy -= 5;
                partner.energy -= 5;
            }
        }
    }


    // FEEDING //
    if (!partner && this.energy < this.settings.feedCap) {
        var target = null;
        var range = this.settings.feedRange;
        for (j=0; j<spores.length; j++) {
            var organism = spores[j];
            if (organism.variant && distanceBetweenPoints(this.position, organism.position) < range ) {
                target = organism;
                range = distanceBetweenPoints(this.position, organism.position);
            }
        }
        if (target) {

            // point towards target //
            this.angleDest = angleBetweenPoints(this.position, target.position);

            // if close enough to target, eat it! //
            if (distanceBetweenPoints(this.position, target.position) < this.settings.feedProximity) {
                this.energy += (target.size * 1.5);
                target.kill();
            }
        }
    }


    // ENERGY //
    this.energy -= 0.005;
    if (this.energy <= 0) {
        this.kill();
    }


    // MOVEMENT //
    // Store a memory of previous positions //
    this.lastPositions.push( this.position.clone() );
    if (this.lastPositions.length > this.settings.tail) {
        this.lastPositions.shift();
    }

    // Randomly increase or decrease rotation & speed //
    this.angle = normaliseAngle(this.angle);
    this.angleDest += tombola.rangeFloat(-this.settings.fluctuation, this.settings.fluctuation);
    if ((this.angleDest - this.angle) > (TAU/2)) {
        this.angleDest -= TAU;
    }
    if ((this.angleDest - this.angle) < -(TAU/2)) {
        this.angleDest += TAU;
    }

    // smoothly transition to angle //
    this.angle = lerp(this.angle, this.angleDest, this.settings.rotationSpeed);
    this.speed += tombola.rangeFloat(-this.settings.fluctuation, this.settings.fluctuation);

    // Cap the max speed so it doesn't get out of control //
    this.speedCap();

    // Update the position by adding the seed to it //
    this.position.x += (this.speed * Math.cos(this.angle));
    this.position.y += (this.speed * Math.sin(this.angle));

    // Wrap around the screen boundaries //
    screenWrap(this);
};
        

Alright, let's finally add some visual and audio events!

Back
Up Next: Audio-Visual