How to Create a Particle Engine in Javascript

Written by radarboy3000 | Published 2017/01/04
Tech Story Tags: javascript | programming | learning-to-code | art | creative-coding

TLDRvia the TL;DR App

Building autonomous objects

Part1 and Part 2

All the code and libraries for these tutorials can be found here: https://github.com/GeorgeGally/creative_coding

We’ve been doing some fairly basic stuff, so let’s pump it up a notch.

In the previous articles I showed you how to have a ball bouncing around the screen. What if we wanted many balls?

But before we get there, it’s always good to clean up the code a bit and separate the drawing and the computing parts into separate functions. Which would get us to something like this:

var ctx = createCanvas("canvas1");var ball_size = 20;var ball_x = width/2;var ball_y = height/2;var speed_x = randomInt(-15, 15);var speed_y = randomInt(-15, 15);ctx.fillStyle = rgb(randomInt(255),randomInt(255),0);

function draw(){

//ctx.background(255, 0.2);moveBall();drawBall();

}

function moveBall(){

ball_x = ball_x + speed_x;ball_y = ball_y + speed_y;

if (bounce(ball_x, 0, w, ball_size)) {speed_x *=-1;ctx.fillStyle = rgb(randomInt(255),randomInt(255),0);}

if (bounce(ball_y, 0 ,h, ball_size)) {speed_y *=-1;ctx.fillStyle = rgb(0, randomInt(255),randomInt(255));}

}

function drawBall(){ctx.fillEllipse(ball_x, ball_y, ball_size, ball_size);}

And let’s extract out our code more, by building the ball into an object. This allows us to access the balls variables via the dot syntax. We create an object like so:

var ball = {x: width/2,y: height/2,speed_x: random(-5, 5),speed_y: random(-5, 5),size: 20,colour: rgb(0)}

Now we can access the ball’s properties like so:

ball.x = ball.x + ball.speed_x;

The complete refactored code now looks something like this:

var ctx = createCanvas("canvas1");

var ball = {x: width/2,y: height/2,speed_x: random(-5, 5),speed_y: random(-5, 5),size: 20,colour: rgb(0)}

function draw(){

//ctx.background(255, 0.2);moveBall();drawBall();

}

function moveBall(){

// bounce() is a function I created, essentially the same as going// if (ball.x < ball.size/2 || ball.x > w - ball.size/2)if (bounce(ball.x, 0, w, ball.size)) {ball.speed_x *=-1;ctx.fillStyle = rgb(randomInt(255),randomInt(255),0);}

if (bounce(ball.y, 0 ,h, ball.size)) {ball.speed_y *=-1;ctx.fillStyle = rgb(0, randomInt(255),randomInt(255));}

ball.x += ball.speed_x;ball.y += ball.speed_y;

}

function drawBall(){ctx.fillEllipse(ball.x, ball.y, ball.size, ball.size);}

It’s time to talk about arrays. I’ll go quickly, because there’s lots of stuff covering this everywhere online. Arrays are essentially just containers that can hold objects, variables and strings, separated by a comma. Like so:

var my_array = [ 1, 2, 3 ];

The first value of the array is accessed by my_array[0] and the second my my_array[1] etc. And we can get an array’s length by saying my_array.length. So…

var balls = []; // declare a variable with an empty arrayvar colours = ['red', 'green', 'blue', 'indigo', 'violet'];

console.log(colours.length); //outputs 5console.log(colours[0]); //outputs redconsole.log(colours[4]); //outputs violet

And if we want to add something to the end of the array we can use push:

var colours = ['red'];console.log(colours); //outputs redcolours.push('green'); //add to the front of the arrayconsole.log(colours); //outputs red, green

Another best friend of coding is the for loop, which looks like this:

// this will loop 10 timesfor (var i = 0; i < 10; i++) {// do something}

The for loop loops until a specific condition is met. In this case we increment our temporary variable i from 0 by one until it no longer meets the condition of being less that 10.

You can read more about the for loop here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration

Our particle system is simply an array for balls. And we build this by creating a ball object and then pushing that into the array:

var number_of_balls = 10;var balls = [];

// push a ball and it's values into the array

for (var i = 0; i < number_of_balls; i++) {

var ball = {x: 200,y: height/2,speed_x: random(-5, 5),speed_y: random(-5, 5),size: 20,colour: rgb(0)}

balls.push(ball);

}

To access our ball’s properties we can now go:

console.log(ball[2].x); //outputs 200

And we can loop through all our balls like so:

for (var i = 0; i < balls.length; i++) {

balls[i].x += balls[i].speed_x;balls[i].y += balls[i].speed_y;

}

But when manipulating and drawing our particles, typing out balls[i] is tedious and repetitive, so we can instead assign a temporary variable to represent balls[i], like so:

for (var i = 0; i < balls.length; i++) {

var b = balls[i];b.x = b.x + b.speed_x;b.y = b.y + b.speed_y;

}

Any changes we make to this temporary variable, will change the actual particles values as well.

Putting it all together we now have:

var ctx = createCanvas("canvas1");var number_of_balls = 10;var balls = [];

// push a ball and it's values into the arrayfor (var i = 0; i < number_of_balls; i++) {var ball = {x: width/2,y: height/2,speed_x: random(-5, 5),speed_y: random(-5, 5),size: 20,colour: rgb(0)}balls.push(ball);}

function draw(){

//ctx.background(255, 0.2);moveBall();drawBall();

}

function moveBall(){

for (var i = 0; i < balls.length; i++) {var b = balls[i];b.x = b.x + b.speed_x;b.y = b.y + b.speed_y;

if (bounce(b.x, 0, w, b.size)) {b.speed_x *=-1;b.colour = rgb(randomInt(55),randomInt(255),0);}

if (bounce(b.y, 0 ,h, b.size)) {b.speed_y *=-1;b.colour = rgb(0, randomInt(255),randomInt(55));}

}

}

function drawBall(){for (var i = 0; i < balls.length; i++) {var b = balls[i];ctx.fillStyle = b.colour;ctx.fillEllipse(b.x, b.y, b.size, b.size);}}

And boom, we have a particle system:

Look Ma, particles!!

Uncomment the ctx.background to see the individual balls, and let’s increase the number of balls to 100:

ctx.background(255, 0.2);

Let’s add balls when we move our mouse. Let’s make an addBall() function, that set’s the new ball’s position to the mouse’s position:

function addBall(){var ball = {x: mouseX,y: mouseY,speed_x: random(-5, 5),speed_y: random(-5, 5),size: 20,colour: rgb(0)}balls.push(ball);}

To check if we’ve moved the mouse, to save us the hassle, I’ve added a listener and global variable in my library called mouseMoved:

// check if mouse has moved and add if so, add a new ballif (mouseMoved) {addBall();}

The mouseMoved variable in my library is build with an eventListener:

var mouseMoved = false;window.addEventListener('mousemove', function(e) {mouseMoved = true;});

And then in my requestAnimationFrame() loop I just reset it to false.

If we keep moving the mouse around, eventually there’ll be so many balls, that our computer will slow down and eventually freeze, so we need a way of removing balls, preferably the oldest ball, and that’s pretty simple, by adding a check for maximum balls length to the end of our addBall() function:

// syntax: splice(start, length)if (balls.length > 1000) balls.splice(0,1);

Splice simply cuts an array from a certain point by a certain amount, in our case from position 0 of our balls array (and the oldest of our balls) by 1.

If we decrease the number to say 20 then we start to get some interesting trail effects:

var ctx = createCanvas("canvas1");var max_balls = 10;var balls = [];

// push a ball and it's values into the arrayfunction addBall(){var ball = {x: mouseX,y: mouseY,speed_x: random(-5, 5),speed_y: random(-5, 5),size: 20,colour: rgb(randomInt(55),randomInt(255),0)}balls.push(ball);if (balls.length > max_balls) balls.splice(0,1);}

function draw(){

ctx.background(255, 0.2);if (mouseMoved) {addBall();}moveBall();drawBall();}

function moveBall(){

for (var i = 0; i < balls.length; i++) {var b = balls[i];b.x = b.x + b.speed_x;b.y = b.y + b.speed_y;

if (bounce(b.x, 0, w, b.size)) {b.speed_x *=-1;b.colour = rgb(randomInt(55),randomInt(255),0);}

if (bounce(b.y, 0 ,h, b.size)) {b.speed_y *=-1;b.colour = rgb(0, randomInt(255),randomInt(55));}

}

}

function drawBall(){for (var i = 0; i < balls.length; i++) {var b = balls[i];ctx.fillStyle = b.colour;ctx.fillEllipse(b.x, b.y, b.size, b.size);}}

Mousetrails

So, that’s it for Part 3. Play around by try reducing the balls size as it grows older and remove it once it’s too small. Mess around with colours and the background transparency and whatever else makes to happy. Till next time, happy coding…

Follow me on Instagram here: https://www.instagram.com/radarboy3000/

And like my Facebook Page here: https://www.facebook.com/radarboy3000

Introduction to Creative Coding Part 1: https://medium.com/@radarboy3000/creative-coding-basics-4d623af1c647#.hn9zzliob

Introduction to Creative Coding Part 2: https://medium.com/@radarboy3000/introduction-to-creative-coding-part-2-d869832d9ffb#.fzxcom541

All the code and libraries for these tutorials can be found here: https://github.com/GeorgeGally/creative_coding


Published by HackerNoon on 2017/01/04