4. Player movement basics

In this chapter, we will focus on the fundamental governing equations for the air and ground player movements, and the exploitation of some of the miscellaneous physical phenomena. This chapter also serves as a prerequisite to Strafing.

4.1. Gravity

Like other entities in the Half-Life universe, the player experiences gravity. Whenever the player is in the air, a constant downward acceleration will be applied. The gravity in the Half-Life universe works in a similar way to the Newtonian gravity in the real world. Namely, a free falling object experiences a constant acceleration of , with value specified by

where is may be called the entity gravity, which is a modifier that scales the default gravity. Typically, , though it can take a fractional value in Xen, for example. The consequence of a constant acceleration is that the velocity and position of the object at time is

(4.1)

Recall that the Half-Life universe runs at quantised time, that is assuming constant frame rate we may write . Or, after one frame. In Half-Life physics, the new position is not updated directly using the position equation above, but rather, it is obtained by integrating the velocity, namely . This position update step is done in the PM_FlyMove function in pm_shared.c.

Looking closely at the code of PM_PlayerMove, we see that the game applies half gravity to the player before position update by PM_AddCorrectGravity, and another half gravity after by PM_FixupGravityVelocity. To see why, ignoring Basevelocity, we write the vertical velocity after the first half of gravity as

The position update step follows from there, by computing the new vertical position

After this, the second half of gravity is applied to compute the correct final vertical velocity

Now observe that both and are correct in accordance to classical mechanics in (4.1). Had the gravity been calculated in any other way, the final vertical position and velocity would be incorrect. This technique of breaking up the acceleration is a variant of the leapfrog integration in the study of numerical integration. It can be shown that trajectory of player motion is indeed parabolic and independent of the frame rate. That is, the trajectory fits the parabolic curve generated using classical mechanics perfectly. Consequently, the jump height is also independent of frame rate. Vertically launching from a ladder, however, does result in frame rate-dependent heights (see Ladder exit).

On the other hand, the straightforward way of integrating gravity is to calculate the full (as opposed to half) gravity , followed by the position update . Notice that this means

In other words, the new vertical position is incorrect, because the term in red is incorrect compared to (4.1). Essentially, this approach is equivalent to the Euler’s method of integrating a differential equation. Not only would the errors accumulate over time, but also that the jump height will be dependent on the frame rate.

4.2. Basevelocity

The basevelocity is an extra velocity added to the player velocity for certain physics computations. For air and ground movement, the basevelocity is added only during the position update step of . That is, the correct position update equation is actually

This extra velocity is usually provided by a push trigger (see trigger_push) or a conveyor belt. For water movement, however, the basevelocity is added during both the acceleration step and position update step.

TODO

TODO

TODO

4.3. Ground friction

When the player is moving on the ground, friction will be applied to reduce the horizontal speed. The friction is applied before air and ground movement calculations (see Air and ground movements) in PM_Friction. The player friction differs from the friction applied to all other entities in that different types of friction is applied depending on the horizontal speed.

Let be the stop speed, the value of sv_stopspeed which is typically 100. Let be the value of

which is usually 4 and where is called the entity friction. The entity friction can be modified by a friction entity (see func_friction). The is the edgefriction which will be described in a moment. It is usually 1 but can often be 2. The two dimensional player velocity immediately after applying friction (but before air or ground acceleration) is now

(4.2)

Assuming . Now observe that the player speed is scaled by a constant factor (assuming and are constant) each frame, resulting in an exponential decrease. This may be called geometric friction, because the series of speeds in consecutive frames forms a geometric series. At higher horizontal speeds this type of friction can be devastating, because higher speeds are harder to achieve and maintain (owing to the sublinear growth of speed by pure strafing, see Strafing), but the factor scales down the speed by an amount proportional to it.

Assuming no other influences and the condition for geometric friction is always satisfied. At frame , the speed due to geometric friction is

Since time is discretised in the Half-Life universe, we have . Therefore,

From this equation, it can be shown, assuming sensible positive values for and , that the lower the frame rate, the greater the geometric friction. However, the difference in friction between different frame rates is so minute that it does not make much practical difference.

In the second case in (4.2), the type of friction being applied may be called arithmetic friction, because the speeds of consecutive frames form an arithmetic series. Namely, at frame , we have

This type of friction is independent of the frame rate, unlike the geometric friction.

In the third case of (4.2), where the speed is very low, the speed is simply set to zero. This case makes little practical difference.

4.3.1. Edgefriction

Edgefriction is a an extra friction applied to the player when the player is sufficiently close to an edge that is sufficiently high above from a lower ground.

TODO

Add maths descriptions

Although doubling seems minor at first glance, the effect is devastating. Prolonged groundstrafing towards an edge can drastically reduce the horizontal speed, which in turn affects the overall airstrafing acceleration after jumping off the edge. One way to avoid edgefriction is to jump or ducktap before reaching an edge and start airstrafing. In human speedrunning terms, the technique of ducktapping before an edge is sometimes called countjump. However, this is sometimes infeasible due to space or other constraints. The most optimal way to deal with edgefriction is highly dependent on the circumstances. Extensive offline simulations may be desirable.

4.4. Air and ground movements

The physics governing the player’s air and ground movements are of primary importance. With precise inputs, they can be exploited to allow mathematically unbounded speed gain (barring sv_maxvelocity). The consequences of the air and ground physics will be described in detail in Strafing.

Caution

All vectors in this section are two dimensional on the plane unless stated otherwise.

The air or ground accelerations are computed before position update. Assuming is the velocity after air or ground acceleration, and the player position. Ignoring collision (see Collision), the position update entails

Here, the new velocity is given by the fundamental movement equation (FME). Let the initial player velocity in two dimensions, namely the velocity immediately before friction and acceleration are applied. Then the FME is simply

Here, is called the unit acceleration vector, such that

A few notes to be made here. First, the and are the forwardmove and sidemove respectively, described in Forwardmove, sidemove, and upmove. Second, and are the unit forward and side view vectors described in View vectors. But more importantly, they are obtained by assuming , regardless of the player’s actual pitch. Consequently, they do not have a component in the axis.

Define such that

where is sv_maxspeed. Observe that is always capped by sv_maxspeed. Observe also that if and are not sufficiently large, one can end up with a smaller value of below sv_maxspeed, which results in lower accelerations, as we will see later. In addition, if , then and will be smaller compared to that when , and so will also be smaller. Therefore, it is undesirable to have any at all if we want as much horizontal acceleration as possible.

In the FME, we also have the coefficient. This coefficient may be written as

where

Recall that is the entity friction described in Ground friction. is the value of either sv_accelerate or sv_airaccelerate, used for ground and air movement respectively. is either or , for ground and air movement respectively. is the shortest angle between and .

We can observe that if , there will be no acceleration at all. This occurs when

Now observe that if , then this condition will never hold because the maximum value of is . That is to say, at lower speeds, the player will be able to accelerate regardless of (barring a few zero points). With speeds beyond , acceleration will not occur with angles

This is just one of the consequences of the FME. Exploitations of this equation will be detailed in Strafing.

4.5. Water movements

Water movement in Half-Life cannot be exploited to move faster than intended. Nevertheless, we will describe the physics here for completeness. Here, we assumes all vectors to be three dimensional.

Assuming a waterlevel of 2 or above. In player water physics, the acceleration vector is such that

And similar but not identical to that in the air or ground movement physics, is defined to be

The only difference is the presence of the factor. Then, the new velocity after water movement is given by

where is the basevelocity (see Basevelocity) and

and let be sv_accelerate,

Note that, unlike air and ground movement, the basevelocity is added before acceleration, rather than after.

To see why it is impossible to accelerate beyond a certain speed, observe that when the speed is sufficiently high, then regardless of view angles or other inputs, will become negative. This always sets , resulting in zero acceleration. In the absence of acceleration, the friction will reduce the speed rapidly.

4.5.1. Waterjump

Pressing the jump key in water has interested physics behaviour in Half-Life, though not one we can exploit to great effect for speedrunning. When the waterlevel is 2, and the jump key is held, then PM_Jump sets the vertical velocity to 100 ups, and leaving the horizontal components intact. This means that and will not be scaled down unlike the case where . A good thing about pressing the jump key instead of +moveup to swim up is that the jump key sets the vertical velocity upwards instantaneously, while +moveup takes time to accelerate the player up.

When the jump key is held while the waterlevel is bordering between 1 and 2, the player will likely be less submerged in the water, and therefore getting a waterlevel of 1. Suppose a frame such that, at the end of the frame, the waterlevel changes from 2 to 1 due to holding down the jump key. Despite leaving the water at the end of frame, the normal water physics would still be run, because the game does not detect the change until a PM_CatagorizePosition or PM_CheckWater is called. There is no such call between PM_Jump and PM_WaterMove.

After leaving the water, the normal air movement physics will take over, and gravity will be exerted onto the player. Due to the small vertical speed resulting from jumping, gravity will quickly bring the player back into water again. Suppose at some frame , the player falls back into the water. Then, the PM_CatagorizePosition immediately after PM_FlyMove will set the waterlevel to 2 or above. In the next frame , PM_Jump will set the player vertical velocity again, and normal water physics will run, which applies some amount of water friction to the player. It is likely that at frame , the player will be back in air again. The cycle will repeat, and this is sometimes called “sharking” in speedrunning.

When the player is close a ground, a different kind of “jumping” physics takes place.

TODO