Friday, 24 October 2008

Where does my bullet come from?

First in a series of "how do I use vectors in my game"

One problem we come across is how to instance a new entity that is meant to be created at a position relative to some pre-existing entity. A good example is the rocket coming out of your rocket launcher. You want to know where to start the rocket, what direction to fire it, and what initial velocity to give it.

firstly, you know that you want it to go in whatever direction the launcher was facing, so you can get the player's direction and use that, but about where it starts out...

well, if you imagine your launcher to be positioned, relative to yourself, then you have a local position for that launcher, giving it an xyz position relative to your centre. If you just add the local position of the launcher to your local position, what will happen?

launcher xyz1 + you xyz1 = xyz2 (uh oh, that's not right)

so, you need to convert your local position to a world relative position.
Firstly, we need to know what being sideways in player space means in the world, so we take the player's Right-Vector (or x row of their transform matrix), and multiply that by the launcher's local space x. This gives us a vector that tells us what the sideways component of the launcher means in world space.
Secondly, we need to know how the vertical position of the launcher is represented in world space, so we take the player's up vector (usually the same as the launcher for most FPS games as it's also the axis of rotation for left-right looking). We take the up-vector and multiply that by the launcher's local space y position. This gives us a vector telling us how the launcher's y position is represented in world space.
Thirdly, we want to know about how far backward or forward the launcher is, so we take the local space z value and multiply that by the direction vector of the player (the z row of the transform matrix, or the "Forward" vector) and get a world space representation of the local space z distance.
Lastly, yes we need the player's position added on to those three created vectors to build our final world space position for the launcher.

so that's launcher (L) and player (P)

world L is:
L.position.x * P.right +
L.position.y * P.up +
L.position.z * P.forward +
1 * P.position

and we already have a 1 in L.position.w because L.position is a position, so we can say
World L = L.position * P

In order to not have the rocket explode straight away because it's very close to the player when it is launched, we might decide to pretend it exists for a little while, then place it some distance along it's trajectory. To do this we need to add on the player direction to the existing calculated World position vector. let's see if we can do this.

WorldL = xyz1, player.forward = xyz0

adding these together will be valid as 1+0 = 1 (meaning the result is still a position)
we can add on a scalar multiplied version of the player's forward vector to give us any point along the line.

WorldL = L.postion * P + P.forward * speed * time

we can use this because speed is distance over time, and we want distance, so we cancel out the times by multiplying.

"d/t*t = d"

now we have our intially offset launched rocket!

No comments: