6. Strafing

Strafing in the context of Half-Life physics refers to the act of pressing the correct movement keys and moving the mouse in a precise way, typically with the aim of gradually increasing the horizontal speed or cornering without losing too much speed. Strafing is commonly accompanied by a series of jumps intended to keep the player off the ground, as ground movements are subject to friction. This combination of techniques is simply bunnyhopping. Since the strafing part of bunnyhopping is much more interesting than the jumping part, we will focus only on the former in this chapter.

Strafing is so fundamental to speedrunning, that a speedrunner ought to “get it out of the way” while focusing on other techniques. This applies to TASes as well: we want to optimise strafing as much as possible so that we can pretty much forget about it when TASing, allowing us to concentrate on the “general picture” and specific tricks.

While this is not the first mathematical treatment of this topic, this documentation strives to be more precise and less ad hoc. Other attempts at mathematical treatments like this by injx, this by flafla2, this by Kared13, this by ZdrytchX, and this by jrsala, have flaws that make them less suited for further analyses (e.g. surfing analysis, speed-preserving strafing, curvature analysis, minimal-time paths) or indeed for implementation.

Caution

Before venturing further in this chapter, be sure to familiarise yourself with the fundamentals of player movement described in Player movement basics. Without the prerequisite knowledge, this chapter can be hard to follow.

6.1. Basic intuition

Before delving into the mathematics, it may be helpful to have a geometric intuition of how strafing works. In Half-Life, and indeed in real-life classical mechanics, the velocity and acceleration are defined as Euclidean vectors with a length (or magnitude) and a direction, typically drawn as an arrow in the Euclidean space. In the strafing context, we are only interested in vectors drawn on a 2D space. When a body in Half-Life accelerates in a frame, the acceleration vector, scaled by frame time, is added to the velocity vector to obtain a new velocity vector,

This may be interpreted geometrically as putting the acceleration arrow after the velocity arrow to obtain a new velocity arrow. The diagram looks like a triangle, as seen in Fig. 6.1.. Now, notice that the new velocity arrow is longer than the previous velocity arrow. This means that the speed (represented by the arrow length) has been increased.

_images/strafing-intuition-1.png

Fig. 6.1. Depiction of how strafing increases speed (i.e. the length of the velocity vector). On the left, the directions of the vectors have significance. On the right, we have rotated the vectors to that they line up, but therefore do not point to the correct direction (though having the correct length or magnitude).

In Half-Life physics, the magnitude or length of the acceleration vector may be depend on the current speed and the angle between the velocity and itself, which in turn is controlled by the viewangles, as explained in Air and ground movements. The task of finding the right angles is the topic of this chapter.

6.2. Building blocks

Before exploiting the fundamental movement equation (FME) for our own gains, there are a few mathematical building blocks we should be aware of to make analyses easier. Firstly, write , where is already given in Air and ground movements. Expanding each yields

(6.1)

This can be done because the dot product satisfies the distributive law. Equation (6.1) is sometimes called the scalar FME, often used in practical applications as the most general way to compute new speeds given .

Tip

This is a very common and useful trick that can be used to quickly yield an expression for the magnitude of vectorial outputs without explicit vectorial computations or geometric analyses. Half-Life physicists ought to learn this technique well.

From equation (6.1), we can further write down the equations by assuming and respectively, to eliminate . These new equations can be found by expanding , again already given previously. We get

(6.2)

These equations will be important in the exploitative analyses of the FME shortly.

However, computing speeds is sometimes not sufficient. We sometimes want to also compute velocity vectors endowed with both directionality and magnitude, but without worrying about player viewangles and . We can achieve this by parametrising in terms of a rotation of by an angle of . This may be expressed as

This is a matrix multiplication of by a rotation matrix. The benefit of writing the FME in this form is that we no longer need to worry about calculating and , which, recalling from View vectors, depend on the yaw angle in the 2D case. We also no longer need to worry about , , and needed to compute . All we need to know is the angle between velocity and acceleration vectors. This can make efficient computations easier as well, because the angle is easily computed (as we will see shortly) in just a few lines of code.

Caution

Remember from Notations Used that vectors in this documentation are row vectors. Therefore, the order of multiplication is different from those in standard linear algebra textbooks. In fact, the components in are also ordered differently.

With this idea in mind, we can rewrite the FME as

(6.3)

Note that the precaution is needed so that the unit vector is well defined. This is one downside of this form of parametrisation, where the special case of zero velocity must be handled separately by replacing (and assuming as usual) in (6.3), thereby involving the viewangles in the computations.

When written in the form of (6.3), positive gives clockwise rotations, while negative gives anticlockwise rotations. If this convention is inconvenient for a particular application, one can easily reverse the directionality by reversing the signs of the elements in the rotation matrix.

6.3. Maximum acceleration

Airstrafing to continuously gain speed is one of the oldest speedrunning tricks. It is of no surprise that one of the earliest inquiries into Half-Life physics has to do with the question of how to strafe with the maximum acceleration, when research began circa 2012 by the author of this documentation. In this section, we will provide precise mathematical descriptions of how maximum-acceleration strafing works in a way that can readily be implemented in TAS tools.

6.3.1. Arguments of the maxima

Let be the current player velocity, the velocity after strafing, and the frame time. Maximising the acceleration means to maximise the per-frame acceleration

It turns out that maximising the per-frame acceleration gives rise to the global optimum. In other words, optimising only the individual frames result in the optimal “overall” acceleration as well. This is perhaps owing to good luck, because it is by no means a universal rule that local maxima yield a global maximum in other instances.

Now, we will assume the frame time is independent of any other variables. Therefore, we can ignore the factor, and the task of maximising acceleration boils down to maximising the new speed . Looking at (6.2), observe that the speed is invariant to the transformation , because both and are even functions. Therefore, for simplicity, we will consider only . Define such that implies , or

Here, the symbols have already been defined earlier in Air and ground movements. Now, we make a few critical observations.

  1. The curves and against intersect only at , provided exists. That is, the two equations for new speed in (6.2) only equal each other when .
  2. is decreasing in . This is because is decreasing in this range.
  3. is increasing in and decreasing in . This is because behaves as such.
  4. If exists, if , and if . If does not exist, then for all , if , or if .

Therefore, we claim that to maximise we have optimal angle such that

(6.4)

We can immediately see that there are three distinct cases for the optimal strafing angle.

6.3.1.1. Case 2

To see the justification for case 2, suppose exists and . This implies the second case in (6.4). By observation 1 and 2, the always decreasing curve of intersects that of at . But crucially, the intersection point lies in the increasing part of the latter curve, keeping in mind that the latter curve is increasing for due to observation 3. On top of that, to the left of the intersection point where is the domain of the latter curve, which is increasing, while to the right of the intersection point is the domain of the former curve, which is decreasing. Therefore the optimal angle is simply at the point of intersection of the two curves, which happens to be the maximum or the peak within .

These deductions assume exists. In order for case 2 in (6.4) to hold true, we must have because the cosine of numbers larger than one is undefined in real numbers. This implies

Note that the lower bound is instead of because we are assuming . This inequality may be simplified to

which is exactly the condition for case 2 in (6.4).

6.3.1.2. Case 1

What if this condition for case 2 fails? Then it can fail in three different ways as one of the following failure conditions:

Suppose the condition fails the first way. We have , thus breaking our earlier assumption about in the previous discussions. By observation 3, the two speed curves intersect when the curve is decreasing. This means that the maximum of this curve is also the global maximum, which occurs at , thus the case 1 in (6.4). Now suppose the condition fails the second way. Then by observation 4, we see that the for all . Therefore, again, the global maximum occurs at . Since the optimal angle under both failure conditions is the same, we can merge failure conditions 1 and 2 to form the condition for case 1, given simply as

which is seen in (6.4).

6.3.1.3. Case 3

Now, suppose the third failure condition holds. Then, by observation 4 again, we simply have for all . Since the curve is decreasing in this range, the maximum occurs at . This is seen in case 3 in (6.4).

Have a look at Fig. 6.2. which illustrates cases 1 and 2.

_images/optang-1.png

Fig. 6.2. Graphs of new speed against when and when . The green curve represents the new speed if throughout regardless of , while the blue curve represents the new speed throughout. The red curve is the actual curve of the new speed by taking as per the FME. From these graphs, it becomes clear where the maximum points are in each case.

6.3.2. Speed equations

Knowing the formulae for optimal , it is a matter of simple substitutions into (6.2) to obtain the new speed after one frame of strafing as

(6.5)

For airstrafing, we can solve the recurrence relations easily and obtain formulae for the speed after frames of strafing as follows:

(6.6)

These equations can be quite useful in planning. For example, to calculate the number of frames required to airstrafe from ups to ups at default Half-Life settings and 1000 fps, we solve

In addition, under airstrafing again, we can integrate the speed equations to obtain distance-time equations. Before doing this, we must make a change of variables by assuming continuous time and writing . Then we compute

for each case.

For groundstrafing, however, the presence of friction means simple substitutions may not work. In more complex cases, it may be desirable to simply calculate the speeds frame by frame using the scalar FME.

6.3.3. Effects of frame rate

The frame rate can affect the acceleration significantly. Looking at the first case of (6.5), the acceleration per frame is

One can immediately see that the lower the (that is, the higher the frame rate), the higher the acceleration. The second case is similar. For the third case, however, frame rate has no effect on the acceleration, because the frame rate simply disappears from the expression for acceleration.

6.3.4. Effects of friction

There is a limit to the speed achievable by perfect groundstrafing alone. There will be a critical speed such that the increase in speed exactly cancels the friction, so that , that is the speed reaches steady state. For example, suppose the optimal angle is and geometric friction (see Ground friction) is at play. Then from the second case of (6.5) we write

Solving for , we obtain the maximum groundstrafe speed for this particular configuration, keeping in mind that is dependent on :

Take the case of default Half-Life settings at 1000 fps, we calculate

This is then the absolute maximum speed achievable by groundstrafing alone in vanilla Half-Life. At another common frame rate of 100 fps, we instead obtain the steady state speed of . There is nothing we can do to groundstrafe beyond this speed!

6.3.5. Growth of speed

By obtaining (6.6), we can immediately make a few important observations. In the absence of friction and if , the speed over time grows sublinearly, or . This implies that the acceleration gradually decreases over time, but never reaches zero. It is notable that the acceleration at lower speeds can be substantial (more than linear acceleration) compared to that at higher speeds. To see why, write new speed , then taking the derivative with respective to to obtain acceleration, yielding

for some . Now observe that, at , the acceleration as initial speed decreases .

6.3.6. Air-ground speed threshold

The acceleration of groundstrafe is usually greater than that of airstrafe. It is for this reason that groundstrafing is used to initiate bunnyhopping. However, once the speed increases beyond the acceleration will begin to decrease, as the friction grows proportionally with the speed. There will be a critical speed beyond which the acceleration of airstrafe exceeds that of groundstrafe. This is called the air-ground speed threshold (AGST), admittedly a rather non-descriptive name.

Analytic solutions for AGST are always available, but they are cumbersome to write and code. Sometimes the speed curves for airstrafe and groundstrafe intersects several times, depending even on the initial speed itself. A more practical solution in practice is to simply use Equation (6.1) to compute the new airstrafe and groundstrafe speeds then comparing them.

6.4. Effects of bunnyhop cap

It is impossible to avoid this mechanism when jumping. In speedruns a workaround would be to ducktap instead, but each ducktap requires the player to slide on the ground for one frame, thereby losing a bit of speed due to friction. In addition, a player cannot ducktap if there is insufficient space above him. In this case jumping is the only way to maintain speed, though there are different possible styles to achieve this.

One way would be to move at constant horizontal speed, which is . The second way would be to accelerate while in the air, then backpedal after landing on the ground until the speed reduces to before jumping off again. Yet another way would be to accelerate in the air and on the ground, though the speed will still decrease while on the ground as long as the speed is greater than the maximum groundstrafe speed. To the determine the most optimal method we must compare the distance travelled for a given number of frames. We will assume that the maximum groundstrafe speed is lower than .

It turns out that the answer is not as straightforward as we may have thought.

TODO!!

6.5. Speed preserving strafing

Speed preserving strafing can be useful when we are strafing at high . It takes only about 4.4s to reach 2000 ups from rest at . While making turns at 2000 ups, if the velocity is not parallel to the global axes the speed will exceed sv_maxvelocity. Occasionally, this can prove cumbersome as the curvature decreases with increasing speed, making the player liable to collision with walls or other obstacles. Besides, as the velocity gradually becomes parallel to one of the global axes again, the speed will drop back to sv_maxvelocity. This means, under certain situations, that the slight speed increase in the process of making the turn has little benefit. Therefore, it can sometimes be helpful to simply make turns at a constant sv_maxvelocity. This is where the technique of speed preserving strafing comes into play. Another situation might be that we want to groundstrafe at a constant speed. When the speed is relatively low, constant speed groundstrafing can produce a very sharp curve, which is sometimes desirable in a very confined space.

We first consider the case where friction is absent. Setting in Equation (6.1) and solving,

If then we must have , or

At this point we can go ahead and write out the full formula for that preserves speed while strafing

On the other hand, if friction is present, then we have

By the usual line of attack, we force which implies that , giving the formula

and the necessary condition

We can check that if friction is absent, then and the condition becomes what we have obtained earlier. If this condition failed, however, then we instead have

Note that we took the negative square root, because needs to be as large as possible so that the curvature of the strafing path is maximised, which is one of the purposes of speed preserving strafing. To derive the necessary condition for the formula above, we again employ the standard strategy, yielding

Observe that we need and . Then we square the inequality to yield the converse of the condition for , as expected. Putting these results together, we obtain

Note that, regardless of whether friction is present, if then we might resort to using the optimal angle to strafe instead. This can happen when, for instance, the speed is so small that the player will always gain speed regardless of strafing direction. Or it could be that the effect of friction exceeds that of strafing, rendering it impossible to prevent the speed reduction. If is greater than the maximum groundstrafe speed, then the angle that minimises the inevitable speed loss is obviously the optimal strafing angle.

6.6. Curvature

The locus of a point obtained by strafing is a spiral. Intuitively, at any given speed there is a limit to how sharp a turn can be made without lowering acceleration. It is commonly known that this limit grows harsher with higher speed. As tight turns are common in Half-Life, this becomes an important consideration that preoccupies speedrunners at almost every moment. Learning how navigate through tight corners by strafing without losing speed is a make-or-break skill in speedrunning.

It is natural to ask exactly how this limit can be quantified for the benefit of TASing. The simplest way to do so is to consider the radius of curvature of the path. Obviously, this quantity is not constant with time, except for speed preserving strafing. Therefore, when we talk about the radius of curvature, precisely we are referring to the instantaneous radius of curvature, namely the radius at a given instant in time. But time is discrete in Half-Life, so this is approximated by the radius in a given frame.

6.6.1. 90 degrees turns

Passageways in Half-Life commonly bend perpendicularly, so we frequently make 90 degrees turns by strafing. We intuitively understand how the width of a passage limits the maximum radius of curvature one can sustain without colliding with the walls. This implies that the speed is limited as well. When planning for speedruns, it can prove useful to be able to estimate this limit for a given turn without running a simulation or strafing by hand. In particular, we want to compute the maximum speed for a given passage width.

_images/90-degrees-bend-c2a2e.jpg

Fig. 6.3. A common 90 degrees bend in the On A Rail chapter in Half-Life. Shown in this figure is one such example in the map c2a2e. In an optimised speedrun, the player would be moving extremely fast in this section due to an earlier boost.

_images/90-degrees-strafe-radius.png

Fig. 6.4. Simplifying model of a common scenario similar to the one shown in Fig. 6.3..

We start by making some simplifying assumptions that will greatly reduce the difficulty of analysis while closely modelling actual situations in practice. Referring to Fig. 6.4., the first assumption we make is that the width of the corridor is the same before and after the turn. This width is denoted as , as one can see in the figure. This assumption is justified because this is often true or approximately true in Half-Life maps. The second assumption is that the path is circular. The centre of this circle, also named the centre of curvature, is at point . As noted earlier, the strafing path is in general a spiral with varying radius of curvature. Nevertheless, the total time required to make such a turn is typically very small. Within such short time frame, the radius would not have changed significantly. Therefore it is not absurd to assume that the radius of curvature is constant while making the turn. The third assumption is that the positions of the player before and after making the turn coincide with the walls. This assumption is arguably less realistic, but the resulting path is the larger circular arc one can fit in this space.

By trivial applications of the Pythagorean theorem, it can be shown that the relationship between the radius of curvature and the width of the corridor is given by

This formula may be used to estimate the maximum radius of curvature for making such a turn without collision. However, the radius of curvature by itself is not very useful. We may wish to further estimate the maximum speed corresponding to this .

6.6.2. Radius-speed relationship

The following figure depicts the positions of the player at times , and . The initial speed is . All other symbols have their usual meaning.

_images/radius-estimate-xy.png

Based on the figure, the radius of curvature may be approximated as the -intercept, or . Obviously, a more accurate approximation may be achieved by averaging and . However, this results in a clumsy formula with little benefit. Empirically, the approximation by calculating is sufficiently accurate in practice. In consideration of this, it can be calculated that

(6.7)

Note that this is the most general formula, applicable to any type of strafing. From this equation, observe that the radius of curvature grows with the square of speed. This is a fairly rapid growth. On the other hand, under maximum speed strafing, the speed grows with the square root of time. Informally, the result of these two growth rates conspiring with one another is that the radius of curvature grows linearly with time. We also observe that the radius of curvature is directly influenced by , as experienced strafers would expect. Namely, we can make sharper turns at higher frame rates.

From Equation (6.7) we can derive formulae for various types of strafing by eliminating . For instance, in Type 2 strafing we have . Substituting, we obtain a very simple expression for the radius:

Or, solving for , we obtain a more useful equation:

For Type 1 strafing, the formula is clumsier. Recall that we have and

To eliminate , we can trivially rewrite the equation in this form

Then we proceed by substituting, yielding

We cannot simplify this equation further. In fact, solving for is non-trivial as it requires finding a root to a relatively high order polynomial equation. As per the usual strategy when facing similar difficulties, we resort to iterative methods.