Before starting to code, we need to define a couple of things, as well as defining the basic elements that compose a particle inside our system. Our minimum time unit will be a frame. This allows us to execute all the changes in the system on a per-frame basis. It does not matter that a frame takes shorter or longer to execute, a frame will be our time unit regardless of real time.
Next, we need to define what a particle is. In the most basic system, a particle is composed of a position, which is a bidimensional vector and another one that tells us the speed, or how the vector changes its position with time in both axes of the plane. On top of this, to make it a little bit more complicated, I added an acceleration vector, which modifies the speed.
We need to define as well the relations between all those vectors. For every time unit, the position changes as specified by the speed, and the speed changes as stated by the acceleration. This schema explains the relationships between all the variables.
Even though the code will use the vector utilities provided by the library, it is of good use to remember how vector addition works in practice. Without getting into a lot of mathematical details (that you can find in any basic Algebra book) this is all you need to know about vectors for the current purpose.
And that is all the physics and maths that you need to know in order to code a basic particle system.
The Particle Class
My design contains the following methods:
- Constructor(position, speed, acceleration) – Creates and initializes the particle, all three parameters are vectors, created by using the Vector class and utilities from P5.
- update() – Updates the status of the particle as if time advanced a single unit.
- draw(color, radius) – I decided to give the particle the aspect of a circle, so this function draws the particle in the current P5 drawing context with the specified color and radius. The aspect is absolutely arbitrary. Color is a P5 color and radius is just an integer.
- canBeRemoved(minX, maxX, minY, maxY) – This function establishes whether a particle is outside of the area of interest (which is a rectangle with those minimum and maximum coordinates) in order to remove it. In the example, the function is used to check whether the particle is outside of the canvas, which uses the full screen.
The code can be checked in the file P52DParticleLib.js in the GitHub repository of the Museum of Funky Animations.
The Example Code
The example sets up a canvas and populates it with particles up to a hard limit that is imposed by the nParticles constant. It also sets a preferred framerate of 60 FPS. The population of particles is stored on an array, which is used to update and remove the particles when they are not visible anymore. As depuration information, it shows the current real FPS as measured by P5 and the current number of particles on the screen. It is also responsive to screen resize. When that happens, the particle population is reset and everything starts again from scratch. In order to see it in action, clone the repository and open particles.html with your favorite modern browser. The acceleration of the particles is zero.
Performance-wise, the system keeps up 60 FPS on my laptop with 500 particles. The test system has an Intel i7 processor and an NVidia GeForce GTX 960M graphics card, neither of them especially powerful. It was tested in Chrome, which provides some hardware acceleration for the canvas in the 2D context. It is expected to see better performance using WebGL and it is to be noted as well that the P5 library can create some overhead.
The code is not optimized at all either, as the goal was to create something that was as easy to understand as possible.
2D animation on the canvas is easy and fun. I will add more code to the Museum of Funky Animations as long as I am learning. If you are interested, let me know on Twitter. Ideas so as to what to implement next are more than welcome!