Game Development Reference
In-Depth Information
We also need to add some code to the
ParticleSystem
to prune old particles. We will do this in a very
simple way by using a new array for the particles that are still alive. This is not very efficient (it produces
quite a bit of garbage), but it is very easy to implement and often good enough. The updated
update()
function will look like this:
ParticleSystem.prototype = {
update: function(td) {
var alive = [];
for(var i = 0; i < this.particles.length; i++) {
var particle = this.particles[i];
for(var j = 0; j < this.forces.length; j++) {
var force = this.forces[j];
force(particle, td);
}
if(particle.update(td)){
alive.push(particle);
}
}
this.particles = alive;
}
};
The last step is simply to define a
maxAge
for our firework particles. As always, making the value a bit fuzzy
will make it look much more realistic.
particle.velocity.x = Math.cos(alpha)*radius;
particle.velocity.y = Math.sin(alpha)*radius;
particle.image = spark;
particle.maxAge = fuzzy(0.5, 2);
Rendering
Our fireworks now behave quite realistically. But they still don't look very good. Luckily, we can change this
with a few little tweaks.
Our firework particles are emitting light; because of this, we should change the blend mode to be additive, so
two lights on top of each other will be brighter than one alone. When using the canvas tag, we can do additive
blending by setting the
globalCompositeOperation
to lighter. The
globalCompositeOperation
is very similar
to layer modes in image editing software. It's important that we reset the
globalCompositeOperation
back to
its default value of '
source-over
' after drawing the particles to avoid side effects.
ctx.globalCompositeOperation = 'lighter';
renderCanvasImage(ctx, system.particles);
ctx.globalCompositeOperation = 'source-over';
Moving bright lights on a dark background usually leaves a trail because of motion blur. We can emulate
this effect by changing the alpha of the background value that we use to clear the frame.
system.update(1/30);
ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
ctx.fillRect(0, 0, canvas.width, canvas.height);