While we wait for some resources to clear before releasing our demo game, King of War, let me give you a sneak preview by releasing the physics engine that’s at the core of it.
The physics of the game basically require a plane (2d area) with circles that can collide. I’ve considered using box2d or related libraries, but as usual decided to do it myself. In hindsight, I’m not sure whether that decision was the best. It might be, because I’m sure box2d would have given me implementation headaches as well. Regardless, I did the engine myself. Which meant diving into some hardcore math. Let me take you through it
Let’s start with the basics. We will have only moving circles and we’ll need to properly handle collisions. First we want to be able to detect a collision between two circles. You can do that by checking the distance between the two circles and comparing that to the sum of their radii. If the distance between their center is smaller than the sum of their radii, it must mean that they are overlapping somehow. The formula for the distance between two points is called the Pythagoras theorem and goes like this (where A and B are your points and C is your distance):
We could check for this after every frame and then try to correct for it, but why would we want to do that when we can detect collisions before they happen and act accordingly? Let’s try that route.
First we take a look at collision detection between two circles where one circle is idle and the other is moving on a straight path, this resembles our basic most case.
We have two circles, A and B. A has a speed and a course (in radians, not that it really matters). The speed is the number of pixels that A moves for each step (one game frame). Each step A moves on the line A-AA (or A-A’, but I think primes are a bit harder to detect and write in code so I’ll use AA for the end point). We want to know whether A collided with B anywhere while moving on the line A-AA.
To compute this we create a new circle, C. C has a radius of A.radius+B.radius and the same center as B. We can now say that A collides with B while moving on the line A-AA if and only if A-AA intersects with C anywhere (within this step, of course). Turns out there’s a pretty simple algorithm to detect this exact thing.
All we have to do now is to check t1 and t2. If either of them is 0<=t<=1, then the collision will happen this step. t1 and t2 indicate where on the line the collision occurs and where exactly, relative to the line drawn. In our case that means it starts at A and ends at AA. If the number is negative, A might collide with B if it could go exactly backwards. If either t is bigger than 1 than A might collide with B in the future, but not this step.
Now that we have the computation when B is idle, let’s take a look how to do it when B is also moving. Since that’s how it will be a lot of the times in the game. And I tried getting away with it but that won’t work. The problem is too obvious. So how do we do the trick above on two moving bodies instead of one?
I’ve thought a bit about this but couldn’t hack it. I could only come up with extremely complex computations and formula’s. None of them were worth the trouble of even trying to implement them. The horror…
Then I found a nice little trick online that worked brilliantly; You simply deduct one vector from the other and apply the above algorithm on the result. Wow! Ok, so we’ve got that to work. Now what?
When we know where exactly a collision occurs, we must move the stone to that position. If you do this, the stones will be touching exactly. You must then determine what they do next. What happens to the speed and course when two stones collide? After giving that some thought, I’ve concluded (and observed) that it’s actually fine and easy to simply let one stone (the slower stone) move in the original course of the faster stone (this also helped). The faster stone will start moving in a course that makes a line that’s tangent to the exact point of collision. Whether it moves left or right on that line depends on the original angle of approach. This actually works out quite well.
In the demo below both circles have a speed (they’ll follow their blue line at the same fixed speed). The orange line is the delta vector and we can see that a collision will occur if that orange line crosses the outer (grey) circle, just like the example above.
To determine the new speed of the two stones I cheated a little and add a fraction of the original speed of the faster stone to the slower stone and return the remainder to the other stone. This division also depends on the angle of approach, meaning that a stone that barely touches another stone will keep most of its velocity and only changes course slightly. A perfectly head-on collision causes the faster stone to transfer all its velocity to the other stone and become idle. The other stone will continue its path in the original course of the first stone at the same speed of the first stone. You could also play with decreasing the velocity to account for the collision itself, but I didn’t and it still looked fine to me.
Oh and there’s more, much more. If we take a look at an imminent high-speed collision where one of the stones will almost immediately hit another stone after the collision, we’ll see that we must take chaining collisions into account. This means that in the same step, one stone can hit multiple other stones. The thing we must prevent is that we don’t warp the stone by limitlessly moving an attacking stone adjacent to its target (as described above). In some cases this would otherwise cause the stone to warp across the screen and this feels very wrong.
Instead each stone will get a variable that tracks how much time it has used moving while inside a single step. For instance, if a stone would move 50 pixels this step, but it collides after moving 35 pixels, it still has 30% time left in this step. This time is then applied to the new speed and the stone is moved accordingly. At the end of the collision detection cycle, a stone will move the remaining time percentage of the speed it currently has to finish it’s move.
The side effect of this approach is on the one hand that the collisions look much smoother now. But it also means that collision chaining just became a heckuvalot more complex. Because now you have to keep checking for collisions and scan all the stones again after every collision. I’ve had cases where this meant considerate pauses. So it’s a good idea to arbitrarily cut this short. There’s no point in simulating 50 collisions this way. Remember that it’s all about the user. It only has to perceive to be correct.
Here’s a final demo with the entire physics engine at work.
I’ve turned this engine into a plugin. You can find it on https://github.com/bonsai-plugins/circle-physics and include it in your own projects. The Item class is exposed through the Phsyics constructor (so Physics.Item). I suggest subclassing that class.
Hope you enjoyed this article