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.
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
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
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.
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.
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
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.
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.
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.
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 collisions (see Collision), the new position is given by
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 setting in the equations, regardless of the player’s actual pitch. Consequently, they do not have a component in the axis.
Define such that
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
Recall that is the entity friction described in Ground friction. is the value of either
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
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.
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
to swim up is that the jump key sets the vertical velocity upwards
+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_CheckWater is called. There is no such call
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.
PM_CatagorizePosition immediately after
PM_FlyMove will set
the waterlevel to 2 or above. In the next frame ,
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.