X

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
These attributes will be updated continuosly by the particle system. 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.

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