HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Processing.js particle system

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
particleprocessingsystem

Problem

After about half an hour of fooling around with Processing.js/JavaScript, I got this fairly decent particle system set up:

// main particle constructor class
var Particle = function(position) {
    this.velocity = new PVector(random(-0.1, 0.1), random(-0.1, 0.1));
    this.acceleration = new PVector(random(-0.01, 0.01), random(-0.01, 0.01));
    this.lifeTime = 300;
    this.position = position.get();
};

// update the particle
Particle.prototype.update = function() {
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    this.lifeTime--;
};

// render the particle
Particle.prototype.render = function() {
    strokeWeight(2);
    stroke(161, 153, 153, this.lifeTime);
    fill(140, 135, 140, this.lifeTime);
    ellipse(this.position.x, this.position.y, 15, 15);
};

// check the bounds of a particle
Particle.prototype.checkBounds = function() {
    if(this.position.x >= 385) {
        this.acceleration = new PVector(random(-0.02, -0.01), random(-0.01, 0.01));
    }
    if(this.position.x = 385) {
        this.acceleration = new PVector(random(-0.01, 0.01), random(-0.02, -0.01));
    }
    if(this.position.y  0) {
        return false;
    } else {
        return true;
    }
};

// array containing particles
var particles = [];

// main draw loop
var draw = function() {

    // draw the background and push a new particle
    background(11, 100, 209);
    particles.push(new Particle(new PVector(mouseX, mouseY)));

    // iterate through particles and run their methods
    for(var p = particles.length-1; p >= 0; p--) {
        var particle = particles[p];
        particle.checkBounds();
        particle.update();
        particle.render();
        if(particle.particleDead()) {
            particles.splice(p, 1);
        }
    }
};


Now, I think that this could definitely be improved, as the Particle.prototype.checkBounds method seems to not work all the time. Anyways, what can I improve here?

Solution

Interesting question,

there are few things that could be improved:

-
Read up on the revealing module pattern, it would be excellent to

  • Reduce your usage of this



  • Make your class look like 1 piece of code



Something like this:

// main particle constructor class
function Particle(position) {

  var velocity = new PVector(random(-0.1, 0.1), random(-0.1, 0.1)),
      acceleration = new PVector(random(-0.01, 0.01), random(-0.01, 0.01)),
      lifeTime = 300,
      position = position.get();

  function update() {
    velocity.add(acceleration);
    position.add(velocity);
    lifeTime--;
  }

  function render() {
    strokeWeight(2);
    stroke(161, 153, 153, lifeTime);
    fill(140, 135, 140, lifeTime);
    ellipse(position.x,position.y, 15, 15);
  };

  return {
    update : update,
    render: render;
  }     
};


I obviously did not rewrite the whole thing, but you should catch my drift.

  • You keep using random(-0.1, 0.1), I would create a helper function for this



-
fill(140, 135, 140, lifeTime);

-
Do not use an if statement to determine true or false like you do :

// check if the particle is dead
Particle.prototype.particleDead = function() {
    if(this.lifeTime > 0) {
        return false;
    } else {
        return true;
    }
};


do this instead:

// check if the particle is dead
Particle.prototype.particleDead = function() {
    return this.lifeTime > 0
};


If you have time, read up on falsy values, you could also simply do return !this.lifetime

-
I am still playing with the code, I managed to fix the right hand side bounce with this:

if(this.position.x >= 385) {
  this.acceleration.x = random(-0.02, -0.01);
  this.velocity.x = random(-0.1, -0.01);
}


In essence you have to solve both the acceleration and the velocity.

I have to wonder, how do you access random? I can only access random as a function under the instance of Processing.

It is too bad that the snippets will now allow for localStorage access, so I can only give you a link to jsbin with my refactored version and the source code here in case jsbin ever dies:

var canvas = document.getElementById('partikals'),
    pjs = new Processing(canvas),
    width = 400,
    height = 400,
    padding = 15;

function Particle2(position) {

    var velocity = new PVector(pjs.random(-0.1, 0.1), pjs.random(-0.1, 0.1)),
        acceleration = new PVector(pjs.random(-0.01, 0.01), pjs.random(-0.01, 0.01)),
        lifeTime = 300;

    position = position.get();

    function update() {
        velocity.add(acceleration);
        position.add(velocity);
        lifeTime--;
    }

    function render() {
        pjs.strokeWeight(2);
        //Each particle is grey
        pjs.stroke(161, 153, 153, lifeTime);
        pjs.fill(140, 135, 140, lifeTime);
        pjs.ellipse(position.x, position.y, 15, 15);
    }

    function isDead() {
        return !lifeTime;
    }

    //I wonder if just *= -1 would work
    function bounce() {
        if (position.x > width - padding) {
            acceleration.x = -Math.abs(acceleration.x);
            velocity.x = -Math.abs(velocity.x);
        }
        if (position.x  height - padding) {
            acceleration.y = -Math.abs(acceleration.y);
            velocity.y = -Math.abs(velocity.y);
        }
        if (position.y = 0; p--) {
        var particle = particles[p];
        particle.bounce();
        particle.update();
        particle.render();
        if (particle.isDead()) {
            particles.splice(p, 1);
        }
    }
};

pjs.setup();

Code Snippets

// main particle constructor class
function Particle(position) {

  var velocity = new PVector(random(-0.1, 0.1), random(-0.1, 0.1)),
      acceleration = new PVector(random(-0.01, 0.01), random(-0.01, 0.01)),
      lifeTime = 300,
      position = position.get();

  function update() {
    velocity.add(acceleration);
    position.add(velocity);
    lifeTime--;
  }

  function render() {
    strokeWeight(2);
    stroke(161, 153, 153, lifeTime);
    fill(140, 135, 140, lifeTime);
    ellipse(position.x,position.y, 15, 15);
  };

  return {
    update : update,
    render: render;
  }     
};
// check if the particle is dead
Particle.prototype.particleDead = function() {
    if(this.lifeTime > 0) {
        return false;
    } else {
        return true;
    }
};
// check if the particle is dead
Particle.prototype.particleDead = function() {
    return this.lifeTime > 0
};
if(this.position.x >= 385) {
  this.acceleration.x = random(-0.02, -0.01);
  this.velocity.x = random(-0.1, -0.01);
}
var canvas = document.getElementById('partikals'),
    pjs = new Processing(canvas),
    width = 400,
    height = 400,
    padding = 15;

function Particle2(position) {

    var velocity = new PVector(pjs.random(-0.1, 0.1), pjs.random(-0.1, 0.1)),
        acceleration = new PVector(pjs.random(-0.01, 0.01), pjs.random(-0.01, 0.01)),
        lifeTime = 300;

    position = position.get();

    function update() {
        velocity.add(acceleration);
        position.add(velocity);
        lifeTime--;
    }

    function render() {
        pjs.strokeWeight(2);
        //Each particle is grey
        pjs.stroke(161, 153, 153, lifeTime);
        pjs.fill(140, 135, 140, lifeTime);
        pjs.ellipse(position.x, position.y, 15, 15);
    }

    function isDead() {
        return !lifeTime;
    }

    //I wonder if just *= -1 would work
    function bounce() {
        if (position.x > width - padding) {
            acceleration.x = -Math.abs(acceleration.x);
            velocity.x = -Math.abs(velocity.x);
        }
        if (position.x < padding) {
            acceleration.x = Math.abs(acceleration.x);
            velocity.x = Math.abs(velocity.x);
        }
        if (position.y > height - padding) {
            acceleration.y = -Math.abs(acceleration.y);
            velocity.y = -Math.abs(velocity.y);
        }
        if (position.y < padding) {
            acceleration.y = Math.abs(acceleration.y);
            velocity.y = Math.abs(velocity.y);
        }
    }

    return {
        update: update,
        render: render,
        isDead: isDead,
        bounce: bounce
    };
}

// array containing particles
var particles = [];

pjs.setup = function() {
    pjs.size(width, height);
    pjs.frameRate(24);
};

pjs.draw = function() {

    //Clear by drawing the background and push a new particle
    pjs.background(11, 100, 209);
    particles.push(new Particle2(new PVector(pjs.mouseX, pjs.mouseY)));

    // iterate through particles and run their methods
    for (var p = particles.length - 1; p >= 0; p--) {
        var particle = particles[p];
        particle.bounce();
        particle.update();
        particle.render();
        if (particle.isDead()) {
            particles.splice(p, 1);
        }
    }
};

pjs.setup();

Context

StackExchange Code Review Q#67745, answer score: 3

Revisions (0)

No revisions yet.