Maths – Urgh, Eccch, YUCK ! But, like it or not, vectors are crucial to quake coding. Every time you fire a rocket, you need vectors. In fact, you could say that „if you don’t wanna go down, you betta get up with da vecta“.

#### WHAT IS A VECTOR

In a 3-dimensional world such as quake, a vector is simply three numbers – an x component, a y component and a z component. In **q_shared.h** at line 258 we can see the C code definition of**vec3_t** :

```
typedef float vec_t;
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
typedef vec_t vec5_t[5];
```

If you’re new to C, a **typedef** associates a complicated datatype with another name. Above, the first typedef states that a single dimensional vector type, **vec_t**, is a **float**ing point number (e.g. 23.4567, as opposed to integers like 23). The next **typedef**’s define 2,3,4 and 5 dimensional vector types. The most common vector type is the 3-dimenstional one, **vec3_t** – it is simply an array of three **vec_t**’s (in other words, an array of three **float**’s). These three floats represent what we call the **x**, **y** and **z** components.

#### THE ORIGIN

Ok, the most basic vector is the **origin** vector. Let’s write it down like this : **(0.0, 0.0, 0.0)**. The x, y and z components are all zero. Let’s create an origin vector in C code.

```
vec3_t origin;
origin[0] = 0.0;
origin[1] = 0.0;
origin[2] = 0.0;
```

Now let’s create a vector to represent the position of player0, at (55.0, -23.0, 12.5).

```
vec3_t player0pos;
player0pos[0] = 55.0;
player0pos[1] = -23.0;
player0pos[2] = 12.5;
```

Now, where is player0 standing ? Well, that depends on something called…

#### THE CO-ORDINATE SYSTEM

Let’s assume that our quake map is three dimensional (and multi-levelled). A space map, for example. Let’s also assume that the location (0.0, 0.0, 0.0) is right on top of a platform somewhere in the middle of the map, with bits of the map extending in directions both left and right, forwards and back, and up and down. But, what defines ‚left-right‘, ‚forwards-backwards‘ or ‚up-down‘ ?

Quake uses what we call a ‚left handed 3d co-ordinate system‘. This means, take your left hand and point your arm forwards. Point your thumb upwards, your index finger forwards and your middle finger directly to the right. Let’s assume that we are standing at the origin in our space map, facing northwards.

Now, your middle finger is pointing in the direction of positive x co-ordinates, your index finger is pointing to positive y co-ordinates, and your thumb is pointing to positive z co-ordinates.

So, by holding out our 2 fingers and thumb (remember, LEFT hand!) imagine that we are sitting at the origin looking north. We can see that **player0pos** is a position to the right of us (x=55.0 is positive), behind us (y=-23.0 is negative) and above us (z=12.5 is positive).

If we wanted to suddenly teleport player0 64 units eastwards and 64 units up into the air, how would we do it ? Maybe :

```
player0pos[0] += 64.0;
player0pos[2] += 64.0;
```

There is a better way to do this, however…

#### VELOCITY VECTORS

Ok, all the vectors we’ve been working with so far have been **positional** vectors – an (x,y,z) position in the game world. There is also another use for vectors – to represent **velocity** (Note:**velocity** is different to **speed**, more later). How do we represent the velocity of rocket that is moving eastwards, and 45 degrees upwards, at 900 units/second ? A vector.

This may be a little confusing, since the rocket will have a **position** and a **velocity**, and both are represented by **vec3_t**.

```
vec3_t rocketpos;
vec3_t rocketvel;
rocketpos[0] = 0.0;
rocketpos[1] = 0.0;
rocketpos[2] = 0.0;
rocketvel[0] = 636.39;
rocketvel[1] = 0.0;
rocketvel[2] = 636.39;
// now let's 'move' the rocket, assume one second has gone by.
rocketpos[0] += rocketvel[0];
rocketpos[1] += rocketvel[1];
rocketpos[2] += rocketvel[2];
// another second goes by... etc
rocketpos[0] += rocketvel[0];
rocketpos[1] += rocketvel[1];
rocketpos[2] += rocketvel[2];
```

The result: after 1 second our rocket is located at (636.39, 0, 636.39). But why did we use 636.39, not 900 ? Well the answer to that lies in the fact that if you move in two dimensions (in our case, eastwards and up) the total distance travelled is measured along the long side of a right-angled triangle, where the short sides of the triangle measure the distances moved in those two dimensions. And we know that the long side of a right-angled triangle is calculated from the good ol‘ **c = sqrt (a squared + b squared)**. So if a and b are 636.39, c works out to be… 900. In three dimensions the maths gets even stickier.

#### DIRECTIONS

Rather than worry about getting 636.39 from 900, there’s a better way to work with a velocity of 900 units/second eastwards and upwards at 45 degrees. We simply break it into two components – a **direction** and a **speed**.

Now for some definitions, a **direction vector** is a vector in any direction where the length is precisely 1.0. For example, (1.0, 0.0, 0.0) or (0.707, 0.0, -0.707) etc. We call any vector with a length of precisely 1.0 a **normalized vector**.

A **speed** is a linear quantity (NOT a vector!!). For example, 900.0, 0.0 or -450.0. A speed of 0.0 represents standing still whilst negative speeds represent moving backwards.

Why is this easier ? Well, there is a simple equation that allows us to ‚move‘ an entity through space – **endpos = startpos + speed * direction**. For example, let’s model our rocket :

```
vec3_t rocketpos;
vec3_t rocketdir;
float rocketspeed;
rocketpos[0] = 0.0;
rocketpos[1] = 0.0;
rocketpos[2] = 0.0;
rocketdir[0] = 0.707;
rocketdir[1] = 0.0;
rocketdir[2] = 0.707;
rocketspeed = 900.0;
// now let's 'move' the rocket, assume one second has gone by.
rocketpos[0] += rocketspeed * rocketdir[0];
rocketpos[1] += rocketspeed * rocketdir[1];
rocketpos[2] += rocketspeed * rocketdir[2];
```

But again, why is this easier ? Well, firstly – quake provides us with several **direction** vectors at many points in the code. For example, we quite often see the **forward** vector. This vector is always pointing in the direction we are aiming. To fire a rocket ? Give it a veclocity of **forward** multipied by 900. To fire a railgun, trace along the **forward** vector for8192 units. Etc. As luck would have it, Carmack has given us a mini-library of…

#### VECTOR FUNCTIONS

Since vectors are used so much in quake, it makes sense to define functions that take care of all the common vector manipulation tasks (copying, adding, multiplying, etc). Not only is it good practice to make use of these functions (since they’re already written, DUH!), it’s important to realize that the operators **+**, ***** etc CANNOT be used – this is because **vec3_t** is an array, and the common mathematical operators cannot be used on arrays in C (in the way we expect them too, anyway). For example,

```
// the stuff below is WRONG.
vector_a *= 100.0; // WRONG!
vector_c = vector_a + vector_b; // WRONG!
// we use functions to do addition, multiplication, etc.
VectorScale (vector_a, 100.0, vector_a); // CORRECT!
VectorAdd (vector_a, vector_b, vector_c); // CORRECT!
```

Here’s a complete list (from **q_shared.h** line 357) :

**VectorSubtract(a,b,c)**– subtract b from a, result is c**VectorAdd(a,b,c)**– add a to b, result is c**VectorCopy(a,b)**– copy a to b**VectorScale(v,s,o)**– make v s units long, result in o**VectorMA(v,s,b,o)**– make b s units long, add to v, result in o**VectorClear(a)**– too easy**VectorNegate(a,b)**– flip a, result in b**VectorSet(v,x,y,z)**– another easy one**Vector4Copy(a,b)**– used for 4 dimensional vectors**SnapVector(v)**– round a vector to integer values

Got it all ? Notice how most of these functions take one, two or three parameters and save the output in a second, third or forth output parameter (the exceptions are **VectorClear()** and**VectorSet()** ). For example, calling **VectorSubtract(a,b,c)** will not modify **a** or **b** – the result will be places in vector **c**. (Unless of course, we say **VectorSubtract(a,b,a)**, which is quite ok to do).

#### VectorMA(v,s,b,o)

You might be wondering what this function does. It’s a useful function that combines a vector multiply and a vector addition. It’s used all over the place so it’s important to understand what it does. Let’s go back to our „rocket moving eastwards and upwards at 900 units/second“ example, using the vector functions…

```
vec3_t rocketpos;
vec3_t rocketdir;
float rocketspeed;
VectorClear(rocketpos);
VectorSet(rocketdir, 0.707, 0.0, 0.707);
rocketspeed = 900.0;
// now let's 'move' the rocket, assume one second has gone by.
VectorMA(rocketpos, rocketspeed, rocketdir, rocketpos);
```

Notice that we did *exactly* the same thing as before, but in half the amount of code. And it’s much neater because we’ve used the vector functions. VectorMA is particularly useful – get to know it like an old girlfriend. Innit.

#### PUTTING IT ALL TOGETHER

Ok, let’s throw all this into action. Open up **g_missile.c** and look at lines 390-393 :

```
VectorCopy( start, bolt->s.pos.trBase );
VectorScale( dir, 900, bolt->s.pos.trDelta );
SnapVector( bolt->s.pos.trDelta ); // save net bandwidth
VectorCopy (start, bolt->r.currentOrigin);
```

First, we assume that **start** is where the rocket is firing from (just in front of the player, at waist height). And **dir** is the direction that the player is facing (a normalized vector, right ?). And a rocket moves at 900 units/second.

So the code simply does this :

- Copy the
**start**vector to the bolt’s**trBase** - Multiply the
**dir**vecotr by 900 and leave the result in**trDelta** - Snap trDelta (convert from floats to integers)
- Copy the
**start**vector to the bolt’s**currentOrigin**

That’s all there is to it. Have a look through some other functions like **fire_plasma** and **weapon_railgun_fire** – see if you can work out (for example) how fast does plasma move ? What is the range of the railgun ? Or the lightning gun ?

If you can answer all those questions – congratulations, you’re a vector geek !

by **SumFuka**