**Half-Life Position, Velocity, and Angles**
This guide is intended for newbies with a desire to learn about position, velocity, and angles. The goal is for you to be comfortable manipulating these variables in Pawn in AMXx in Half-Life.

**Dimensions**
dimension - a property of space; extension in a given direction

There really is no dimension here--it's the 0th dimension, after all. You can think of it as an infinitely small point. It does not extend in any direction.

We cannot specify a location in this dimension.

Now we have a line in one direction. You can only change the length of the line. Many problems in physics are idealized to one-dimensional problems for simplicity. For example, falling bodies are often idealized to fall straight down with no deviation.

We can specify a location in this dimension with one number.

For example, a straight line starting from your floor going up to your ceiling. Let's say the floor is 0, the ceiling might be 2.5 (in meters, let's say). Any point in between would be between 0 and 2.5.

In code, you can hold the position with a variable like this:

I'm only talking about the first dimension, so, strictly speaking, there is no explicit direction. You can only go back and forth.

However, you can say the variable from my example exists in the Y-direction because our world is in three dimensions and saying "Y-direction" implies that we are talking about going up and down, in general.

Depending on the context, you might say that a one-dimensional variable is in the X-direction or Z-direction. Typically, you only say that it is in the X or Y directions.

Finally! Now we can move up, down, left, and right (and any combination of these directions). More complicated physics problems are idealized in two dimensions. For example, a projectile's motion is idealized in two dimensions.

We can specify a location in two dimensions with a pair of numbers. We call this pair of numbers

*coordinates*. In writing, you usually see coordinates written like this (X, Y). The X-direction means left and right. The Y-direction means up and down.

In code, you can hold the position with a variable like this:

Code:

new Float:fPosition[2]

The variable is called an array and it holds two values. The first value, fPosition[0], should hold the position in the X-direction. The second value, fPosition[1], should hold the position in the Y-direction. (You can also use [1] for the X-direction and [0] for the Y-direction, but it's nice to do things in a standard way so others can understand your code quickly.)

Code:

public MakeHudMessage( id )
{
// X values range from 0 to 1, 0 is left edge of the screen, 1 is right edge of the screen
// Y values range from 0 to 1, 0 is top edge of the screen, 1 is bottom edge of the screen
new Float:fPosition[2]
fPosition[0] = 0.2 // x position
fPosition[1] = 0.5 // y position
set_hudmessage( 200, 100, 0, fPosition[0], fPosition[1], 0, 6.0, 12.0, 0.1, 0.2, 4 )
// red = 200, green = 100, blue = 0
// x position = 0.2, y position = 0.5
// effects = 0
// fxtime = 6.0
// holdtime = 12.0
// fadeintime = 0.1, fadeouttime = 0.2
// channel = 4
show_hudmessage( id, "Hi this is a hudmessage!" )
}

**set_hudmessage** prepares a hud message with position, color, effects, and time

**show_hudmessage** shows text in the way specified by set_hudmessage

OH BOY! Now we can move up, down, left, right, forwards, backwards AND any combination of these directions.

We can specify a location in three dimensions with a group of three numbers. In writing, you usually see coordinates written like this (X, Y, Z). The Z-direction means forwards and backwards.

BUT WAIT! The Z-direction means forwards and backwards *in the picture above*, but it actually means up and down in Half-Life. Why? The programmers of Half-Life decided to make the Z-direction up/down. So, forward/back/left/right are handled with the X and Y directions.

In code, you can hold the position in three dimensions with a variable like this:

Code:

new Float:fPosition[3]

fPosition[0] holds the position in the X-direction, fPosition[1] holds the position in the Y-direction, and fPosition[2] holds the position in the Z-direction.

Code:

public PlayWithOrigins( id )
{
new iOrigin[3]
get_user_origin( id, iOrigin )
// move the player 20 units in the Z-direction (upwards)
iOrigin[2] += 20
set_user_origin( id, iOrigin )
}

**Vectors**
So far, I've covered the 0th, 1st, 2nd, and 3rd dimensions. The code examples have dealt with coordinates representing

*positions*, but I have hinted at a different use for three-dimensional arrays with my physics examples.

You need to learn two new words: vector and scalar

vector - a quantity possessing both magnitude and direction, represented by an arrow the direction of which indicates the direction of the quantity and the length of which is proportional to the magnitude

scalar - representable by position on a scale or line; having only magnitude

When we are dealing with positions, like the position of a player in a map or the position of text on the screen, we are dealing with scalar quantities. Scalar values have no direction, only magnitude (size). When you say a player is located at (X, Y, Z), you know nothing about whether or not he is moving. If he is moving, you don't know where.

Velocity is a vector quantity. Let's jump into an example:

Code:

new Float:fVelocity[3]
pev( id, pev_velocity, fVelocity )

**pev** is a FakeMeta function used to retrieve values from entities

**pev_velocity** tells pev() which value we are retrieving

**fVelocity** holds the value we are retrieving, it must be a 3-dimensional array

After executing this code, let's say that our velocity is now (100, 200, 0). This means we have a velocity in the X-direction of 100 units per second, a Y-velocity of 200 units per second, and a Z-velocity of 0 units per second. The numbers directly indicate the magnitude of the velocity. How can we find the direction? (Vector values have both magnitude AND direction.)

Here is the situation, in picture form:

Notice that the vectors both start at the origin (0, 0, 0) and extend away from it.

To get the direction, you must combine all three component vectors (X, Y and Z) into one. (Components are pieces.)

So, now we can see that

**fVelocity** holds a vector value. That means you can discover the magnitude AND direction of the velocity by interpreting the values it holds.

They are not the same. Speed is a scalar quantity and velocity is a vector quantity. You can store speed in a variable like this:

To store velocity, you must have a variable like this:

Code:

new Float:fVelocity[3]

Speed means distance/time, like miles per hour (mph) or meters per second (m/s). It does not tell you where you are going.

Velocity, when you're NOT dealing with code, is written in two parts. First, you say the speed like 40 mph (yes, speed is one part of velocity). Next, you must say the direction. For example, North. When we're dealing with code, you don't have two parts. Instead, you have to interpret the 3 values to figure out speed and direction.

**Extracting Speed from Velocity**

Remember Pythagoras? He has this nifty theorem:

Code:

c * c = a * a + b * b

In English: C squared equals a squared plus b squared

If you glance at the above image with the red, green, and pink arrows, you can see how this works. C is the length of the pink arrow, a is the length of the green arrow, and b is the length of the red arrow.

In three dimensions, it's like this:

Code:

hypotenuse * hypotenuse = x * x + y * y + z * z

(Hypotenuse is a fancy word for the sloped part of a right triangle. A right triangle is a triangle with a 90 degree angle.)

Here's what we were looking for:

Code:

speed * speed = x vel * x vel + y vel * y vel + z vel * z vel

Or, in real code:

Code:

new Float:fVelocity[3]
// store some velocity into fVelocity
// slow, inefficient way (but you get to see what it looks like)
New Float:fSpeed = floatsqroot( fVelocity[0] * fVelocity[0] + fVelocity[1] * fVelocity[1] + fVelocity[2] * fVelocity[2] )
// fast, efficient way
New Float:fSpeed = vector_length( fVelocity )

**Extracting Direction from Velocity**

We don't have North, South, East, and West in Half-Life. We just have angles, so that's how we'll represent the direction of our velocity.

The math is more complicated, so let's leave it at this:

Code:

new Float:fVelocity[3]
new Float:fAngle[3]
// store some velocity
vector_to_angle( fVelocity, fAngle )

So, let's do something

~~useful~~ useless with our new knowledge. We are going to save the player's position, launch him in a random direction, and finally move him back to his original position.

Code:

public UselessFunction( id )
{
new Float:fOrigin[3]
new Float:fVelocity[3]
// save his origin
pev( id, pev_origin, fOrigin )
// create a random velocity
fVelocity[0] = random_float( 100.0, 500.0 ) * ( random_num(0,1) ? 1.0 : -1.0 )
fVelocity[1] = random_float( 100.0, 500.0 ) * ( random_num(0,1) ? 1.0 : -1.0 )
fVelocity[2] = random_float( 100.0, 500.0 ) * ( random_num(0,1) ? 1.0 : -1.0 )
// set his velocity, WOOSH
set_pev( id, pev_velocity, fVelocity )
// put him back to his original position in 2.0 seconds
set_task( 2.0, "PutMeBackPLZ", id, _:fOrigin, 3 )
}
public PutMeBackPLZ( iOrigin[3], id )
{
// set his origin, YAWN
set_pev( id, pev_origin, iOrigin )
}

**set_pev** is a FakeMeta function used to set various values for entities

**random_float** generates a random number between two numbers

**random_num** does the same thing, but returns an int rather than a float

**set_task** is used to call a function after a few seconds

**Angles**
There is another use for three-dimensional arrays (variables like fVelocity[3]). They are used to store an entity's angles.

I'm going to use your imagination to make this easy to understand. Imagine a hotdog and place it on the desk in front of you with one end pointing at the monitor.

**pitch** - lift one end of the hotdog while the other end stays on the desk

PUT IT BACK DOWN!

**yaw** - now, spin the hotdog on the desk

POINT IT AT THE MONITOR AGAIN!

**roll** - now, roll the hotdog along the desk

Now do the same actions you did to the hotdog, but move your head instead of the hotdog. (Tilt your head up/down, rotate left/right, and then roll it.) You should begin to feel a sort of satisfaction now that you understand the meaning of pitch, yaw, and roll. If not, yell at me.

Here's a nice image that explains pitch, yaw, and roll. Thanks arkshine! (And thanks to the creator, whoever it is.)

In Half-Life, the angles are stored thusly:

Code:

new Float:fAngle[3]
fAngle[0] // pitch
fAngle[1] // yaw
fAngle[2] // roll

You can use pev() to retrieve the angles, just like we did with velocity or origin, but there are several different angles in Half-Life. You'll have to experiment with them to get a good idea of the purpose they serve.

**pev_angles** - orientation of the entity

**pev_v_angle** - orientation of the camera, (player's view), v_angle = view angle

**pev_punchangle** - deviation from the view angle (POW! I punched you in the kisser and now your face rotated over there but you will slowly return back to your v_angle)

You can get/set these just like the others, with FakeMeta or Engine:

Code:

// FakeMeta
new Float:fAngles[3]
pev( id, pev_angles, fAngles )
set_pev( id, pev_angles, fAngles )
// Engine
entity_get_vector( id, EV_VEC_angles, fAngles )
entity_set_vector( id, EV_VEC_angles, fAngles )

What's a normal? Is it the opposite of a weird? Wow, I'm tired.

More vocabulary for your hungry, hungry mind:

plane - a flat or level surface

normal - the dictionary definition is confusing, so here's mine: a line that is perpendicular to the plane

Why is this useful? Well, it get's complicated.

My

Wall Text plugin makes use of positions, vectors, angles, and normals.

The goal of the plugin is to aim at a wall and paint text on it.

Here's the step-by-step process:

1. Get the position on the wall where the user is aiming.

2. Get the normal of the wall. (The wall is a plane and the normal points out of the wall into the world where the player exists.)

3. Make a vector pointing the to left (from the perspective of the wall's normal).

4. PAINT!

5. Move over to the left, using the vector we calculated.

6. Repeat steps 4-5 until finished.

If you're observant, you'll notice that I've neglected to do this calculation for sloped surfaces like ramps. The plugin will work for perfectly vertical walls at any angle, but it will fail if you want to do a multi-line message on a sloped wall like a ramp, because I was too lazy to write the extra code.

Here's the code:

Code:

CreateNewMessage( id, szMessage[MESSAGE_LEN] )
{
new Float:fAimOrigin[3]
new Float:fPlayerOrigin[3]
new Float:fAimVector[3]
new Float:fNormalVector[3]
new Float:fTextVector[3]
// user's view angle
pev( id, pev_v_angle, fAimVector )
// vector pointing in that direction
angle_vector( fAimVector, ANGLEVECTOR_FORWARD, fAimVector )
// user's origin
pev( id, pev_origin, fPlayerOrigin )
// lengthen vector and move it to user's origin
fAimVector[0] = fAimVector[0] * 9999.0 + fPlayerOrigin[0]
fAimVector[1] = fAimVector[1] * 9999.0 + fPlayerOrigin[1]
fAimVector[2] = fAimVector[2] * 9999.0 + fPlayerOrigin[2]
// execute traceline, grab normal vector and end position
new iTr = create_tr2()
engfunc( EngFunc_TraceLine, fPlayerOrigin, fAimVector, IGNORE_MONSTERS, id, iTr )
get_tr2( iTr, TR_vecEndPos, fAimOrigin )
get_tr2( iTr, TR_vecPlaneNormal, fNormalVector )
free_tr2( iTr )
// convert normal vector to angles
vector_to_angle( fNormalVector, fTextVector )
// get vector pointing to the right, from the perspective of the normal vector
angle_vector( fTextVector, ANGLEVECTOR_RIGHT, fTextVector )
// lengthen by width of one character, and point towards the left (from the perspective of the normal vector)
fTextVector[0] *= -1.0 * CHAR_WIDTH
fTextVector[1] *= -1.0 * CHAR_WIDTH
fTextVector[2] *= -1.0 * CHAR_WIDTH
// ...
}

__________________