QW physics air

Previous part

QW physics: moving in air, bunnyhopping.

Here we looking into code that determines player movement in air. First of all vector of so called wish velocity is calculated.

When in air this vector is always horizontal. We have received from client following values: forwardmove, sidemove, upmove.

Wish velocity is calculated from these values. upmove is discarded. This vector is a sum of 2 vectors: 1)horizontal vectors with length forwardmove with direction along projection of view direction to horizontal plane. 2) horizontal vector with length sidemove, directed sideway.

Gravitation effect is calculated separatly. Next step in code: applying server restriction V_max (320 for TDM and from 230 to 450 in TF). If length of wish velocity is bigger than V_max it is now eqal to V_max.

After vector wished direction(wishdir, its length is 1) and value of wished speed are calculated. Wish speed equal V_max usually unless we want to move slow for some reason.

Now we are in function PM_PlayerAccelerate

Value of wish speed is restricted with value 30: wishspd = min(wishspd, 30);

Projection of current velocity to wishdir is calculated: currentspeed = DotProduct (pmove.velocity, wishdir);

Difference between wishspd and currentspeed is calculated. If result is negative then speed does not change: addspeed = wishspd - currentspeed; if (addspeed <= 0) return;

After that calculated value accelspeed = accel * wishspeed * pm_frametime = 10 * 320 * 0.014 = 44.8. It is a bit messy but it is how it is done in code: wishspeed is not wishspd but a value of wish speed before applying restriction of 30, that is usually it is V_max.

accel is determined with variable sv_accelerate. (Funny but it looks like variable sv_airaccelerate has no effect.)

After that minimal of addspeed and accelspeed is selected: accelspeed = min(accelspeed, addspeed);

Vector with length of selected value and direction wishdir is added to current velocity vector: VectorMA(pmove.velocity, accelspeed, wishdir, pmove.velocity);

Algorithm is described. No we can analize it.

If player is in air and does not press buttons his velocity remains the same (as mentioned previousle gravitation is accounted separatly).

If player has zero speed pressing +forward immediately gives him speed 30 directed forward.

Now we can look to bunnyhopping.

Jumping just changes vertical speed so we can concider that player is always in air.

We concider that player did not set cl_sidespeed, cl_forwardspeed, cl_backspeed below server limits.

Nice fact about bunnihopping in QW is that it does not matter where player looks to but only wishdir has effect

Let accel = a pm_frametime = T.

T = 0.013, if we have 77fps physics and T = 0.014, if 72fps physics (TF2003 standard).

Let angle between horizontal velocity v and wishdir is gamma



wishspd = min(wishspd, 30) = 30 for given conditions.

addspeed = min(30 - v * cos(gamma),  a * T * V_max)

Dependency of addspeed from cos(gamma):



Graphic concists of 2 parts Break point - cos(gamma_k). Here 30 -  v * cos(gamma_k) ==  a * T * V_max,

cos(gamma_k) = (30 - a * T * V_max) / v.

Do not forget that cosinus values are within [-1; 1]. Break point goes off this limit when cos(gamma_k) = -1. Then v=14.8 in TDM. In TF this value is also small. As we know speed of 30 can be gained in one frame. Thus we can concider that break point is always within [-1; 1].

Lets see what maximum speed gain may give horizontal part of graphic.

From cosinus theorem: v_new^2 = v^2 + (a*T*V_max)^2 +2*v*(a*T*V_Max)*cos(gamma). The bigger cos(gamma) the bigger speed gain. That is best point on horizontal part is break point which lies also on inclined part.

Lets see what maximum speed gain may give inclined part of graphic.

v_new^2 = v^2 + (30 - v*cos(gamma))^2 + 2v*(30 - v*cos(gamma))*cos(gamma)

Then v_new^2 = v^2 + 30^2 - (v*cos(gamma))^2

The nearer cos(gamma) to 0 the bigger speed gain.

Break point cos(gamma_k) < 0, if 30 < a * T * V_max, that is V_max > 30 / (a * T) = 230.8 if 77 fps  and 214 and 72 fps physics.

It means that maximum acceleration is when cos(gamma_best) == 0.

(The only exception is hwguy with 77fps phisics. For him best point is break point cos(gamma_best) = (30 - a * T * V_max) / v. Here 30 - a * T * V_max = 0.1, that is when V > v_max=230 0 < cos(gamma_best_hwg_77) < 4.34e-4. This value is very small so we can just neglect it.

)

With cos(gamma) = 0 v_new^2 = v^2 + 30^2

d(v^2)/dt = 30^2/T. Ideal acceleration just in air which starts with just jump on place(no moving on ground): v(t) = 30 * sqrt(t / T).

dv/dt = 30^2/(2*v*T).

Acceleration with 77 fps physics is bigger than with 72fps for 7.7%.

In one frame velocity vector rotates for delta_fi = arctg(30/v), that is angle speed omega = (1/T)*arctg(30/v). If v>>30 omega = 30 / (vT).

It means the bigger speed the slower you need to rotate.

Theoretically you can reach speed 200 in 58 seconds with 77fps physics.

Player must keep correct direction of wishdir. He can do it by rotating and pressing keys correctly.

Moving on ground is described in next part: