Difference between revisions of "QW physics air"

From QWiki
*>Sss
(New page: QW physics: moving in air, bunnyhop. With commands +forward +back +moveleft +moveright +moveup +movedown +speed player sets up values of forwardmove, sidemove, upmov...)
 
*>Sss
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
QW physics: moving in air, bunnyhop.
+
Previous part [http://wiki.quakeworld.nu/QW_physics_user_commands]
  
 +
QW physics: moving in air, bunnyhopping.
  
With commands
 
  +forward
 
  +back
 
  +moveleft
 
  +moveright
 
  +moveup
 
  +movedown
 
  +speed
 
player sets up values of forwardmove, sidemove, upmove variables.
 
  
 +
Here we looking into code that determines player movement in air.
 +
First of all vector of so called wish velocity is calculated.
  
Those values are defined by variables
+
When in air this vector is always horizontal.
cl_sidespeed, cl_forwardspeed, cl_backspeed, cl_upspeed.
+
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.
  
Also command +speed increases them 2 times.
+
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.
  
If 2 opposite commands are (for example +forward and +back) then only earliest is really active.
+
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.
  
Valuses forwardmove, sidemove, upmove are sent to server and
+
Now we are in function PM_PlayerAccelerate()
also used in client to predict movement.
 
  
Code that processes player movement must be equal in client and server.
+
Value of wish speed is restricted with value 30:
 +
wishspd = min(wishspd, 30);
  
For example I have
+
Projection of current velocity to wishdir is calculated:
cl_forwardspeed 400 (ezquake default) and
+
currentspeed = DotProduct (pmove.velocity, wishdir);
also there is following line in my config which is executed at the client start:
 
+mlook;wait;+speed;wait;
 
  
Thus when pressing +forward
+
Difference between wishspd and currentspeed is calculated.
forwardmove = 2 * 400 = 800.
+
If result is negative then speed does not change:
 +
addspeed = wishspd - currentspeed;
 +
if (addspeed <= 0)
 +
return;
  
  
Movement of layers is processed in function PM_PlayerMove.
+
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.)
  
????
 
In ezquake under ktx server forwardmove = 800 for unknown (for me)
 
reasons become 508 в PM_PlayerMove.
 
???
 
  
Lets see player movement in air.
+
After that minimal of addspeed and accelspeed is selected:
So called vector of wished speed is calculated.
+
accelspeed = min(accelspeed, addspeed);
In air it is horizontal and is summed up from 2 components:
 
horyzontal vector with length forwardmove wich is directed along player view but horizontally
 
and of vector with length sidemove which is horizontal and perpendicular to 1st component.
 
  
 +
Vector with length of selected value and direction wishdir is added to
 +
current  velocity vector:
 +
VectorMA(pmove.velocity, accelspeed, wishdir, pmove.velocity);
  
      (Need picture.)
+
Algorithm is described.
 +
No we can analize it.
  
upmove is not used while in air. Only gravitation affects player movement in air.
 
  
Next , if length of received vector of wishspeed is grater than server restriction
+
If player is in air and does not press buttons
its length is decreased to meet restrictions.
+
his velocity remains the same
 +
(as mentioned previousle gravitation is accounted separatly).
  
This length is 320 for usual TDM and
+
If player has zero speed pressing +forward
changes from 230 to 450 depending on player class in TF.
+
immediately gives him speed 30 directed forward.
  
  
Next step. We are in function PM_PlayerAccelerate() and
 
we have vector of wished direction with length 1
 
and value of wished speed.
 
  
First of all value of wished speed is restricted by 30:
 
wishspd = min(wishspd, 30);
 
  
Then value of projection of current velocity to wished direction is calculated:
+
Now we can look to bunnyhopping.
currentspeed = DotProduct (pmove.velocity, wishdir);
 
  
Вычисляем разницу между желаемой скоростью и проекцией теущей скорости.
+
Jumping just changes vertical speed
Then difference between wished speed and projection of current velocity
+
so we can concider that player is always in air.
is calculated. If result is not positive then velocity does not change.
 
  
addspeed = wishspd - currentspeed;
+
We concider that player did not set
if (addspeed <= 0)
+
cl_sidespeed, cl_forwardspeed, cl_backspeed below server limits.
return;
 
  
 +
Nice fact about bunnihopping in QW is that
 +
it does not matter where player looks to but only wishdir has effect
  
Then calculated value
 
accelspeed = accel * wishspeed * pm_frametime =
 
            10 *320 * 0.014 = 44.8.
 
(wishspeed  - is not wishspd here)
 
  
Then minimal value between is taken:
+
Let
accelspeed = min(accelspeed, addspeed);
+
accel = a
 +
pm_frametime = T.
  
Final step: vector with length accelspeed and direction wishdir is added to current velocity.
+
T = 0.013, if we have 77fps physics
VectorMA(pmove.velocity, accelspeed, wishdir, pmove.velocity);
+
and T = 0.014, if 72fps physics (TF2003 standard).
  
 +
Let angle between horizontal velocity v and wishdir is gamma
  
Simpliest cases.
+
[[Image:Wishdir.png]]
If player is in air and does not press buttons his horizontal speed does not change.
 
  
If player has zero speed pressin +forward gives him speed 30 directed horizontally forward.
+
wishspd = min(wishspd, 30) = 30 for given conditions.
  
Now we can look into bunnyhop.
+
addspeed = min(30 -  v * cos(gamma),  a * T * V_max)
Wewill concider speed greater than server restriction (320 in TDM)
 
because player can gain that speed while he is on ground.
 
  
And of course we concder that player does not set too small values of
 
cl_sidespeed, cl_forwardspeed, cl_backspeed.
 
  
Nice fact about QW  is that it does not matter where player looking to.
+
Dependency of addspeed from cos(gamma):
Only his wishdir is important.
 
  
  
Let angle between horizontal velocity v и wishdir is gamma.
+
[[Image:Addspeed air fixed.png]]
  
wishspd = min(wishspd, 30) = 30 with conditions given above.
 
  
addspeed = wishspd - currentspeed = 30 -  v * cos(gamma)
 
  
Final value of accelspeed >=0.
+
Graphic concists of 2 parts
 +
Break point -  cos(gamma_k).
 +
Here  30 -  v * cos(gamma_k) ==  a * T * V_max,
  
When bunnyhopping we want to increase speed so we must have
+
cos(gamma_k) =  (30 - a * T * V_max) / v.
  
cos(gamma) > 0
+
Do not forget that cosinus values are within [-1; 1].
addspeed = 30 - v * cos(gamma) > 0
+
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].
  
When bunnyhopping value  accel * wishspeed * pm_frametime is not important.
 
Really 44.8  > 30 -  v * cos(gamma) if cos(gamma) > -14.8/v
 
that is only if we are decaccelerating.
 
  
So when bunnyhopping we have accelspeed =  addspeed;
+
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.
  
Increase of speed in one frame is
+
Lets see what maximum speed gain may give  inclined part of graphic.
dv_frame = addspeed * cos(gamma) = (30 - v * cos(gamma)) * cos(gamma).
 
  
Graphic of dv_frame(cos(gamma)) is parabola
+
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
  
        (Need picture)
+
The nearer cos(gamma) to 0 the bigger speed gain.
Upper (best) point is when соs(gamma_best) = 15 / v;
 
  
Best possible increase in one frame is
+
Break point cos(gamma_k) < 0, if 30 < a * T * V_max,
dv_frame_best =  (30 - v * 15 / v) * 15 / v = 225 / v.
+
that is V_max > 30 / (a * T) = 230.8  if 77 fps  and 214 and 72 fps physics.
  
pm_frametime = 0.013, if 77fps phisics is active
+
It means that maximum acceleration is when cos(gamma_best) == 0.
and pm_frametime = 0.014, if 72fps phisics (TF2003 standard, old TDM standard).
 
  
Ultimately speed increase is described by following differential equation:
+
(The only exception is hwguy with 77fps phisics.
        dv/dt = 225/(v * pm_frametime)
+
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.
  
 +
)
  
Acceleration with 77fps phisics is about 7% bigger than with 72fps.
+
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).
  
v(t) ~ sqrt(t - t0).
 
  
QW has fundimental restriction: no entity can have speed bigger than 2000.
+
dv/dt = 30^2/(2*v*T).
  
Theoretically it can be reached within 111 seconds with 77fps phisics.
+
Acceleration with 77 fps physics is bigger than with 72fps for 7.7%.
  
Player must keep best direction of wishdir.
+
In one frame velocity vector rotates for delta_fi = arctg(30/v),
He rotates to make it.
+
that is angle speed  omega = (1/T)*arctg(30/v).
 +
If v>>30 omega = 30 / (vT).
  
Player can look up or down while bunnyhopping: it does not matter for physics.
+
It means the bigger speed the slower you need to rotate.
  
Correct angle speed is
+
Theoretically you can reach speed 200 in 58 seconds with 77fps physics.
omega = addspeed * sin(gamma) / v = (15 / v) * sqrt(1 - (15 / v)^2).
 
  
So the greater is speed the less is best angle speed.
+
Player must keep correct direction of wishdir.
 +
He can do it by rotating and pressing keys correctly.
  
Comments and corrections are welcome.
+
Moving on ground is described in next part: [http://wiki.quakeworld.nu/QW_physics_ground]

Latest revision as of 17:37, 21 August 2010

Previous part [1]

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

Wishdir.png

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

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


Dependency of addspeed from cos(gamma):


Addspeed air fixed.png


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: [2]