…in which we direct traffic with physics.
What so far all of our particles start from the same spot and move away from that spot at a constant, random velocity. They obey Newton’s First Law, which is basically the physics you get when nothing interesting is happening. We can get some nice effects this way, but we can do a lot better.
One thing to try is expanding the emitter from a mere point; we’ll do that, but not today.
Another is to restrict the range of initial directions the particles can start off in. We’ll do that today. Then we’ll start thinking about what kinds of things can affect the motion of the particles, so they might move along curves rather than straight lines.
We can control the direction and spread of the particles pretty easily using some more basic ideas from trigonometry. Rather than explaining all that here, make this small change and have a play with the result:
The block of four lines here reads the mouse’s X and Y positions and uses them to control the spread and direction (respectively) of the jet of particles. Putting your mouse near the bottom of the screen lets them out in a full circle, but near the top it’s more like a concentrated jet.
(I realise that if you don’t know much maths, this just looks like magic. I guess I owe you a post or two about trigonometry. But anyway, it isn’t magic: sin and cos and PI are all about circular motion, so in a sense we’re doing the most obvious possible thing with them here.)
This suggests that we should give ParticleSystem variables to describe the angle and spread of particles so we can “drive” these programmatically.
As usual we’ll define the variable and set them up via the constructor — which, as I’ve mentioned before, is getting a bit out of hand but we’ll worry about that another day:
Now we change init() to use these instead of mapping the mouse position:
Don’t forget to add two more parameters to the line where you create the ParticleSystem in your sketch (they can be anything you like):
And don’t forget we can change these value in draw() if we want to, so we can still animate them or even have them respond to the mouse:
But I’m going to leave that out now and think about something else. The particles still come out in a straight line; can we subject them to some forces to make them change direction?
The cheapest possible thing we can do is add gravity, which just constantly nudged the movement in a downwards direction:
Some nice watery effects available here, so I changed colours:
Of course, in the virtual world gravity can go in any direction we like — more of the same trignometry idea we’ve been using all along makes that possible:
We should definitely make gravityStrength and gravityAngle into parameters of ParticleSystem and use them to stor the IntableFloatPair representing gravity in the system. Here we go:
(I’m regretting calling it “IntableFloatPair” now but whatever — we can rename it at the end when we tidy all this mess up.)
Now advance() can just use gravity directly, making it very simple:
Time to give it a quick test and see if it works. Nope, I forgot to add some gravity values to the constructor in the main sketch:
Now it works. Note that you can turn gravity off by passing in 0 for its strength, so this is an optional feature.
I want one more force in our basic physics: a force that pulls particle towards the central direction of the system. Recall that the system now has a dir and spread; particles spread out either side of dir in a fan-like shape. I would like them to be pulled back towards dir as they age, which should enable us to build a flame-like shape.
Let’s call this the conformingForce and for efficiency, let’s calculate and store it for each particle in init(). So in ParticleSystem’s constructor we’ll take in a float representing the strength of the force and we’ll initialise an array to hold the actual forces, which will be calculated in init():
For the next bit it turns out we’ll need one small thing — the ability to scale an IntableFloatPair up or down by a float:
Now let’s calculate the force in init():
A few steps were needed here! This is partly because of the not-very-nice way I defined add() and times() in IntableFloatPair. Oh well, here’s what’s happening. First dirVect is just an IntableFloatPair pointing in the direction of the prticle system (without any spread). What the next three lines do is take this away from the actual direction of the particle.
Thus, conformingForce[i] contains a number that is bigger the further away particle i is from the central direction. This will cause particles that are “spread out” further from the centre to accelerate more towards it. This is multiplied by the conformingForce, which controls how big the pull is.
Now we just add the conformingForce when to the motion of the particle in advance():
This works nicely. I added a little bit of sort-of-random drift to the dir variable and now I have a pretty nice flame:
The flickering detail isn’t too important but in case you want it it’s here:
…and of course in the GitHub code for today’s post. Next week we’ll look at building custom emitters, and at that point I think we’ll be done, although the code will need a tidy-up of course.