Hello everyone! For my first article ever, I thought I would go into detail about how to create physically accurate projectile motion (things arcing through the air) in 3D isometric perspective. This problem may appear daunting at first, but it's easier once we break it down into parts. And the finished product looks very impressive!
Really, there are two problems here. One is the physics problem: if we know where a particle is (x,y,z) , and we know its speed (dx,dy,dz) , then where should we put it in the next frame update? The other problem is: once we know where a particle is in x,y,z , where do we put it on the screen in isometric X,Y ? That second problem is subtle, but it should be clear with some examination. Let's take a look at that first.
PART I: ISOMETRIC PERSPECTIVE
For all my text notation, I'll denote normal 3D coordinates as (x,y,z) and isometric 2D coordinates as (X,Y).
Naturally, on a flat computer monitor, we're constrained to two dimensions! However, an isometric 2D view is different from normal 2D in that "X counts double." That is to say, on a straight line, for every two pixels in X, we move one pixel in Y. If you've worked on isometric graphics at all, you're surely familiar with this "fundamental law of isometric perspective."
This gives us our first two rules for moving from normal (x,y,z) to isometric (X,Y) :
And in fact, if you're doing 2D isometric, that's all you need. However, we also want to account for height (z). How do we do this?
The solution is to just add our height z to Y. We can picture this the following way: If we have a normal object sitting at (X,Y), what should happen if we raise its height constantly? It should rise up to the top of the screen- meaning its Y coordinate is increasing!
This also illustrates some of the ambiguity in an isometric projection. You can't tell just by looking if an object is far up the screen on the ground, or far down the screen with a height above ground. Figure 2 illustrates this, two points with different (x,y,z) that end up having the same Y coordinate.
So, putting this all together, we can write down formulae for (X,Y) given (x,y,z):
X = 2x
Y = y + z
PART II: 3D PROJECTILE PHYSICS
So we've found a completely general way to map from our imaginary (x,y,z) 3D space to your computer monitor in isometric perspective. Great! Now we need to work out the equations for a projectile moving in (x,y,z) .
For Klik games, it's really important that you use alterable values (variables) to store the projectile's values for x,y,z and dx,dy,dz . This allows us to use decimal values when computing the motion; then only at the end do we update the projectile's X,Y position to match the variables. Otherwise, you would lose all precision in the calculations, and the particle would behave badly.
We assume at the start that you know the particle's position in (x,y,z), and also its velocity (dx,dy,dz). This is entirely dependent on your game, it's up to you to provide these values!
The next thing we need to know is some basic physics: as a projectile flies through the air, the only force it feels is gravity - we will ignore air friction for this article. Since it only feels a pull down, dx and dy will stay constant while dz changes due to gravity. If you want to know why this works, then crack open an intro physics textbook sometime - you might even enjoy it!
We will want to code the following rules into our klik game so that they all run once per frame update:
x = x + dx
y = y + dy
z = z + dz
dz = dz - g
In the above formula, g is the gravity constant. You'll want to play with it to find the right amount, it should be small since it's being added on every frame. You can set it negative for anti-gravity, etc.
After the particle has its new (x,y,z) coordinates, we then move it to the right place on the screen, using the formulae developed in part I:
set position X = 2x
set position Y = y + z
And that will do it! For clarity's sake, you really should have projectiles drop a shadow, if z is greater than some small value. We know the shadow has to be at the particle's position, but at zero height. This translates to:
shadow X = 2x
shadow Y = y
There you have basic projectile motion!
PART III: BOUNCING?
What do we do once the particle hits z = 0, that is, the particle hits the ground? For non-bouncy things, you can just stop all motion here. Set dx = dy = dz = 0 and you're done.
Bouncing is an easy way to make the motion a little more realistic. As before, dx and dy do not change. dz, the velocity in the up/down direction, flips signs. To see this, consider a particle immediately before and after bouncing: first it has a large, negative dz (going down!) ; then it has a large, positive dz (going up!) .
The rule should be simple. Just throw it in with the subroutine that calculates the new positions and velocities:
if z <=0 then
set z = 0
set dz = dz * -1.0
Cool! But that will make our particle bounce forever. In reality, things lose a tiny bit of kinetic energy when they bounce like this, we call it an "inelastic collision." So as it bounces, it bounces lower and lower and lower... until it stops. We can model this with a slight change in the above rule:
if z <=0 then
set z = 0;
set dz = dz * -0.9
So now the projectile loses 10% of its vertical velocity with each bounce. Since this could go on forever, we should also include a "sanity rule" that cuts it off once dz gets small enough:
if z <= 0 and abs(dz) < 0.2 then
set dz = 0
dx = 0
dy = 0
Presto! Fancy 3D projectile motion in isometric perspective!
Oh wow thank you so much!!! I am working on a medieval isometric RTS game and I am about to program my archers and I was stumped as to how to make the arrows arch through the air. Could you please be so kind as to send me an example? I would appreciate heaps. cheers
I would tend to have the objects shadow be the basic collision detection, and then simply position the graphic above it appropriately in a similar manner makes the coll detection for isometric look a bit more real (Otherwise the camera perspective will be cause characters to collide from further distances on the vertical)
Sorta the reverse of what you said witha shadow
Then if you wanna check if an object if over something elseshead, you simply, on collision detection, test if the projectile's z is in a certain range (Say, 10 points either way of the target's Z)