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

Life

Our next organism has the very creative name of "organism1". Unlike spore, organism1 has a few interesting behaviours; it swims in a direction, it feeds on spores to gain energy, and when it has enough energy it will look for a breeding partner. If it runs out of energy, it will die, releasing spores back into the system.

Constructor

Go to the file ORGANISM1.js. We'll fill in the constructor function Organism1, this is all pretty similar to what we did for spore, only now we're also randomising a direction for our organism to head in.


function Organism1(x1, y1, x2, y2) {
    this.settings = org1Settings;

    // randomise position //
    this.position = new Point(tombola.range(x1, x2), tombola.range(y1, y2));
    this.lastPositions = [];

    // randomise angle //
    this.angle = tombola.rangeFloat(0, TAU);
    this.angleDest = this.angle;

    // randomise other properties //
    this.size = tombola.rangeFloat(this.settings.small, this.settings.large);
    this.speed = tombola.rangeFloat(this.settings.minSpeed, this.settings.speed);
    this.energy = tombola.rangeFloat(7,8);
}
        

Drawing

Now lets look at the draw method. A little more to it this time; as well as some regular line drawing, we have a loop where we connect a line between a stored history of previous positions, creating a trailing tail. We're also rotating the drawing context to match the direction the organism is headed:


Organism1.prototype.draw = function() {
    // set color //
    ctx.fillStyle = this.settings.color;
    ctx.strokeStyle = this.settings.color;

    // set scale //
    ctx.lineWidth = 4 * scale;
    var s = this.size;

    // tail //
    if (this.lastPositions.length) {
        ctx.beginPath();
        ctx.moveTo(this.lastPositions[0].x, this.lastPositions[0].y);
        for (var j=0; j<this.lastPositions.length; j+=4) {
            ctx.lineTo(this.lastPositions[j].x, this.lastPositions[j].y);
        }
        ctx.stroke();
    }

    // head //
    ctx.save();
    ctx.translate(this.position.x, this.position.y);
    ctx.rotate(this.angle);

    ctx.beginPath();
    ctx.moveTo(s * 0.75, s/2);
    ctx.lineTo(0, s * 1.25);
    ctx.moveTo(s * 0.75, -s/2);
    ctx.lineTo(0, -s * 1.25);

    ctx.moveTo(0, s/2);
    ctx.lineTo(s/2, 0);
    ctx.lineTo(0, -s/2);

    ctx.stroke();
    ctx.restore();
};
        

Movement

Now let's move onto the update method. We've got several types of behaviour to code here, but let's start with movement. Instead of adding random numbers to x-axis and y-axis movement like in spore, here we add random number fluctuation to our angle, creating more of a swimming motion.


Organism1.prototype.update = function() {
    // 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);
};
        

Okay, that's the basic setup, movement and drawing done, let's generate some instances and call update and draw on each, same as we did with spore.

Instances

Head back to MAIN.js. We'll be replicating the steps we did with spore. First go to the function draw and inside it add:


for (var i=0; i<org1.length; i++) {
    org1[i].draw();
}
        

Next go to the function update, and inside it add:


for (var i=0; i<org1.length; i++) {
    org1[i].update();
}
        

Move up to the empty function generateOrganism1 and fill it in like we did before:


function generateOrganism1(n, x1, y1, x2, y2) {
    for (var i=0; i<n; i++) {
        org1.push( new Organism1(x1, y1, x2, y2) );
    }
}
        

And finally move up to the function init, and inside of it, beneath where we added generateSpores add:


generateOrganism1(8, 0, 0, width, height);
        

Go and refresh index.html, we should now have some new organisms swimming around! Now let's move onto those more advanced behaviours.

Further Learning:
en.wikipedia.org/wiki/Radian
Back
Up Next: Behaviour