…in which we make our prototype a bit easier to work with and expand.
Last time we made good progress by expanding our unimpressive one-particle system into a proper system with a thousand or so particles all being born and dying and moving independently.
The price for this is a lot of arrays that seem a bit awkward and complicated. We’d like to now tidy up this code so it’s easier to work with. The result will be code that is neater and better-structured but does exactly what it did before; sometimes you have to spend some time on that before things get out of hand.
What is a particle? According to our code, it’s something with a position, a velocity (“movement”) and an age. But actually this isn’t true: this is what a particle is in our heads. There are no particles in the code, just arrays of PVectors and ints. This is what we will change today.
If you’ve never worked with classes before, consider this post a gentle introduction. For our purposes, a class is a type of thing. We have at least two types of thing to consider: particles and particle systems. A particle system should have an array of particles, but it also needs other information like how many particles there are, how they should move, what the emitter looks like and so on.
Also, be warned that you will probably lose track of what’s-going-where in this post. Screenshots aren’t a great vehicle for this. If you get in a muddle, check out the code in GitHub (below) and see how the final version looks.
For now we will make our particle system class very simple and put most of the work into the particle class. To make a class, click the down-arrow next to the tab your sketch code is in, choose “New Tab” and call it “Particle”. The result should be this:
In here we will define what it is to be a particle. Here is how it starts:
This is actually pretty usable as-is, but we’ll add one thing to make it more convenient. Usually we want to create a new particle with a certain position, movement and age. We can do this with a constructor, which looks like this:
The position, movement and age belong to the particle. The constructor, as you’ll see, is a way to build a new particle with a specific position (pos), movement (mov) and age (age). Note that the age being passed in has the same name as the variable storing the age inside the particle, but that’s OK because we use “this.age” to tell Processing we mean “the age variable that belongs to this particle, not the one that was just passed in”. Don’t worry too much if you’re new to this and it’s a bit opaque; this isn’t a series on object-oriented coding (though maybe we’ll do one in future).
[Note to OO folks: encapsulation is broken in Processing; there’s no point making things private and writing getters and setters and all that jazz. We’ll just access the members directly. Yes I know that’s nasty.]
Now let’s immediately go ahead and change our code to use this class. That means instead of the three arrays at the top we just have one (notice how we initialize it in setup() as well):
Now we have lots of fixing to do, but it’s very straightforward — just changes all references to the old arrays to references to the properties of the particles in the new arrays. Here’s how that works out in init():
and here’s how it works in draw():
We could improve this but now is a very good time to test it and see if it works. It does!
Now, this code is creating and managing particles for us, which is great, but really this is what a particle system should do, and in a final project we might want several particle systems all running at once. This is another good candidate for a class. Let’s create a basic one:
OK, now let’s happily move all the particle-management code out of our main sketch and into here. This takes a bit of thought. Here’s the easy part — initialise the array and move the init() command into the ParticleSystem (I just cut and pasted it, it’s off the bottom of the window in this screenshot):
Now when I use the particle system I want it to take responsibility to managing the ages, movements and initialization of its particles. So every frame of my main sketch, I probably want to advance the particle system one step. I’ll make an advance() function inside the ParticleSystem class to do this, and fill it with cut-and-paste code from draw():
I also want to be able to draw my particles. For now, I will put this functionality into the ParticleSystem, although later I might want to move it somewhere else, into a dedicated “particle renderer” of some kind. Let’s keep it simple for now — again, just cut-and-paste code from the old draw() function:
Phew! And here is what our sketch looks like now I’ve removed all the code that’s gone into Particle and ParticleSystem and used the latter instead:
Yes, that’s the whole file — almost all of the complexity of our previous project has been hidden away in the two classes we created (and most of that is in ParticleSystem).
Maybe this is reward enough for all the tedious code-shifting we just did, but next week we’ll add some more flexibility that will enable us to get different effects quickly an easily. Then we’ll hopefully get on to sprites! Note that this is a warts-and-all development log — I’m making it up as I go along so you can see what that looks and feels like, so consequently I can only make educated guesses about what’s going to happen next…
All the code for this series is available on GitHub.