Javascript Particle System Hello World
This is a very simple example to demonstrate how to create a basic object oriented
particle system using javascript and the html canvas element.
A particle system consist of number of particles, each particle has the following properties:
- position: the postion in the space, (x,y) coordinates
- velocity: the velocity of the particle, (vx,vy) vector
- life: the amount of time the particle is going to live
- time: the time elapsed since the particle was created
This is the class of the Particle object, it just has the fundamental attributes to make it work, but we can more attributes like weight or transparency for more complex systems. It also has a render method that just draw a circle.
//The Particle class
function Particle(){
//particle position
this.x = 0;
this.y = 0;
//particle velocity
this.vx = 0;
this.vy = 0;
this.time = 0; //the time elapsed since the particle was created
this.life = 0; //the amount of time the particle is going to live
this.color = "#000000";
this.setValues = function(x, y, vx, vy){
this.x=x; this.y=y;
this.vx=vx; this.vy=vy;
this.time=0;
this.life = Math.floor(Math.random()*500);
}
this.setColor = function(color){
this.color = color;
}
// renders the particle using the canvas element
this.render = function(){
ctx.save();
ctx.fillStyle = this.color;
ctx.translate(this.x, this.y);
ctx.beginPath();
ctx.arc(0,0,10,0,Math.PI*2,true); // draw a circle
ctx.fill();
ctx.restore();
}
}
The ParticleSystem class will contains an array of Particles that will be filled with random attributes in the init function.
The update function will update the velocity, position and life time of each particle, when a particle has consumed all it
life (time == life), it will be destroyed and a new one will be created with new random attributes.
//ParticleSystem creates an array of RainParticles and updates their attributes
function ParticleSystem(){
//origin rectangle of the this.particles
this.x0;
this.y0;
this.x1;
this.y1;
this.n = 0;
this.particles = [];
this.gravity = 0.01;
this.init = function(n, x0, y0, x1, y1){
this.n = n;
this.x0=x0;this.y0=y0;
this.x1=x1;this.y1=y1;
this.gravity = 1;
for(var i=0; i<n; i++){
this.particles.push(new RainParticle());
this.particles[i].setValues(Math.floor(Math.random()*this.x1)+this.x0,Math.floor(Math.random()*this.y1)+this.y0,0,1)
}
}
this.setParticlesColor = function(color){
for(var i=0; i<this.particles.length; i++)this.particles[i].setColor(color);
}
//update the attributes of every particle
this.update = function(){
for(var i=0; i<this.particles.length; i++){
if(this.particles[i].time < this.particles[i].life){
this.particles[i].vy = this.particles[i].vy + this.gravity;
this.particles[i].x = this.particles[i].x + this.particles[i].vx;
this.particles[i].y = this.particles[i].y + this.particles[i].vy;
this.particles[i].time += 1;
}
else{
this.particles[i].setValues(Math.floor(Math.random()*this.x1)+this.x0,Math.floor(Math.random()*this.y1)+this.y0,0,1);
}
}
}
this.render = function(){
for(var i=0; i<this.particles.length; i++)this.particles[i].render();
}
};
Here we set the initial values of the particle system and update and render the particles every 100 miliseconds
using the setInterval function.
var ctx = document.getElementById("canvas").getContext("2d");
setInterval(draw,100);
var ps = new ParticleSystem();
ps.init(50,0,0,800,50);
ps.setParticlesColor("#0099ff");
function draw(){
ctx.clearRect(0,0,800,600);
ps.update();
ps.render();
}
Just to make the particles prettier we can inherit from the Particle class and overload the render function
to draw a water drop.
// RainParticle inherits from Particle and overloads the render function to draw a drop instead of a circle
function RainParticle(){
this.render = function(){
var m=0.4;
ctx.save();
ctx.fillStyle = this.color;
ctx.translate(this.x, this.y);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.bezierCurveTo(0*m,5*m,0*m,10*m,5*m,15*m);
ctx.bezierCurveTo(10*m,20*m,12*m,26*m,10*m,30*m);
ctx.bezierCurveTo(6*m,40*m,-6*m,40*m,-10*m,30*m);
ctx.bezierCurveTo(-12*m,26*m,-10*m,20*m,-5*m,15*m);
ctx.bezierCurveTo(0*m,10*m,0*m,5*m,0*m,0*m);
ctx.fill();
ctx.restore();
}
}
RainParticle.prototype = new Particle; //inherit from Particle