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!

Thursday, 23 October 2008

You are not a good designer.

Big design up front is a way of being sure that you're going to be wrong. You can keep at it day after day and eventually your design will be so big that the probability that it's all right is nearing zero.

We have a solution to this problem, it's called approximation and evolutionary prototyping.

Orgel's second rule : "evolution is cleverer than you" applies to the science of software creation just as it does to advancing biological forms. If you work on a piece of software, you're better off refactoring it than starting again. It's quite simple really, in the old not good enough code is a bunch of stuff that works. Every time you try to do it from scratch, you forget and in turn reduce the complexity (and capacity) of the software. Sometimes the reduction in complexity is good, and refactoring could have done it too, but sometimes it's disasterous (which refactoring doesn't do).

Consider these two alternatives when you next start writing that great new piece of code that is going to be just like X but better.

Thursday, 2 October 2008

Directions in 3D space are 2D

In something of a response to one of the whinges about my previous post (that all vectors are a direction and a magnitude), I hereby declare that all directions in 3D space are in fact 2D, therefore do not count as 3D vectors.

Eh?

okay, imagine any vector for a direction in 3D space, you can map it to a sphere (remember, directions are unit vectors, so there's no 0,0,0, nor any vector of any length other than 1), and as you know, places on this world can be pinpointed on a map.

... yes? more?

if you don't need anything other than 2 dimensions to fully describe a vector of values, then that's how many dimensions it's got. Any production of more values from the lower order vector of values is just a function of them.

consider this, if you were told that foward acceleration was a vector, you could say that it was not true, in fact it was a 1 dimensional vector (scalar), because any acceleration that wasn't forward didn't classify as a forward acceleration, therefore you only need one value to descibe the acceleration.

3D -> 1D

Care for more?

How about the horizon? point to somewhere on the horizon... you can give me a value, a single value, back, and i can know where you were pointing. That's right, up and down, left and right, and how far away the thing you were pointing at can be reduced down to one number.

Wednesday, 1 October 2008

matrices and vectors and positions

A 3 dimensional vector has three components: x,y,z
It specifies a direction and a magnitude.
You can use it to describe a velocity, a direction (if it's unit), an acceleration, momentum, displacement between two positions, and angular velocity (using magnitude and direction), but you can never use it as a position.

A 3 dimensional positoin has thre components: x,y,z
It specifies where in space a point exists.
You can use it for the position of a vertex, the centre of a sphere/circle/shape, the target of a camera, but you can never use it as a vector.

Why so strict?

A vector is usually defined by having it's w value set to 0 and a position equally by a w of 1.
This means that to do any mathematics with these two constructs, you must follow some simple rules that can be found out by trying out the maths on the four element vector:

1. a position can never be added to another position
2. the difference between two positions is a vector (displacement)
3. the sum of a position and a vector is a position
4. the sum of two vectors is a vector
5. you cannot dot product a position with anything
6. you cannot multiply a position by a scalar

okay, so vectors point, and positions place...

And a matrix is made of three vectors telling you which way each of the matrices axis point, and a position to tell you where in space it is.

don't beleive me?

a matrix is really

x2x, x2y, x2z, 02w
y2x, y2y, y2z, 02w
z2x, z2y, z2z, 02w
w2x, w2y, w2z, w2w

which means any vectors (with w of 0) will be transformed by just the rotation part...
and any positions (with a w of 1) will be transformed, then have the position added...

which is right if you think about it for a moment.

so... time to typesafe your math library yet and save cycles while still behaving like a full matrix transform library?