With Gravity Lab, I’ve built what I think is a decent particle simulation framework. Which brings me to my hidden agenda: something I’ve wanted to do for a long time, but could only do incrementally, since the complexity of the entire task was just too overwhelming. So I present to you another particle simulator, codenamed Charges.
It was a no-brainer, really. Ok, sure — there’s no money in educational apps. There’s that. But the thing was practically already done. Electric forces are just like gravitational forces: obeying inverse square law (read more here, or here). There’s just a matter of inverting the polarity, i.e., introducing “negative masses”. And change some constants.
Or so I thought.
It turns out a charged particle simulator is pretty useless by itself: particles always recombine (i.e., neutralize each other), or fly far away from each other until they get garbage-collected.
What I needed were solid (metallic) objects, which could trap the particles — so I could observe the forces, make capacitors, simulate cathode ray tubes (CRT), and generally bring the “static” into “electrostatic”. So I decided to implement objects. And this is an epic journey of a developer, struggling with an interesting problem and generating much flow™ in the process. 🙂
Simple enough, I decided to support rectangles and circles only. Why? Because this way, it can be quite easily checked whether a particle has hit the wall. When you tap the screen, I simply loop through an array of all objects and check if you tapped inside a body. If I find that to be true, I set the parent of the particle to the ID of the body. Then, when calculating the motion of the particle (which is done by summing all the forces of all the other particles), I only need to check if the particle has hit the parent object’s wall. If parent object is a rectangle, it’s really simple, like this:
if rectangle if parent.left_wall.x < particle.x < parent.right_wall.x move freely (left or right) else dont move along x axis end if parent.bottom_wall.y < particle.y < parent.top_wall.y move freely (up or down) else dont move along y axis end end
With circles, I’ve already hit the first obstacle. You can’t separate x and y coordinate checking into separate conditions, because they are dependent. I tried many options without real success and particles always got stuck in some kind of deadlocked state. What finally proved to be the most efficient solution, was checking if the particle’s future position is too far away from the circle center (more than circle radius away), and projecting it back onto the circle boundary. Like this:
if circle if (x^2 + y^2 < circle.radius^2) move freely along x and y else phi = atan2(y,x) x = circle.radius * cos(phi) y = circle.radius * cos(phi) end end
It worked like a charm. But I faced a more dire problem, one that could not be solved in my limited particle-has-a-single-parent model. Namely, my particles couldn’t migrate from one parent to the next. Which would, of course, happen in nature: if you bring together a charged metallic object and an uncharged metallic object, some of the charge from the first one will be forced out into the second one.
I wanted that, and it obviously couldn’t be done. Indeed, the composite objects made of circles and rectangles can become quite complex; how could one force the particles to stay within an object in such simple terms as shown above?
I slept on it, and slept some more. And for the first time I can remember, the solution suddenly blinded me one morning. Yesterday’s morning, that is. And it goes like this.
Let me explain. If a particle happens to be inside an overlap of two or more metallic objects (i.e, inside two or more objects at the same time), cycle through all of them every n frames of the animation. Let them all be parents, but not at the same time. And let the electrostatic forces that drive the particles away from each other do all the work.
The bottom right particle in the picture above desperately wants to break away, to the South-East direction (down and to the right). If we bring in another body, the particle now has 2 parents (overlap). We iterate through both of them and let the particle just savor the moment for a while. And the moment it is assigned to object 2 above, it is propelled towards South-East, no longer bound by the first object. When there’s no more overlap, the time-sharing doesn’t happen any more. Voila.
So hopefully, a new and amazing simulator will soon hit the App store. Stay tuned.