Why FPS Effects Jumping

From Trepidation
Jump to: navigation, search

Why FPS Effects Jumping

Originally a bug in Quake3 and later Star Trek Voyager Elite Force, Trepidation has chosen to recreate this bug for the physics of the game.


(1) The final velocity vectors are clamped to integers every time the player movement code is called. This gets called once per frame for fast clients, but never less than 20 times per second.

(2) This conversion is done by the equation (int)x, where "x" is a floating point value.

(3) The integer conversion done by the Q3 vm *IS NOT ANSI COMPLIENT*. ANSI C specifies that integer conversion is done by ignoring the fraction. The Q3 vm does it by rounding to the nearest integer.

This third point explains exactly why DLL's have slower speeds and jump heights than QVM's. In a QVM, the rounding is to nearest integer, so errors will tend to cancel out. In a DLL, rounding is always towards 0, so errors always reduce your speed and will always accumulate. The rounding error in a DLL always acts as extra friction. I expect you can get around this problem in DLL's by rewriting the "SnapVector" macro to emulate the QVM's rounding method.


Now, back to the jumps. In theory, the rounding errors should cancel out over the number of frames in a typical jump. This assumes that the fraction can be any value with equal probability. However, in practice, this is not the case. Each frame tends to be the same time as the previous one. The change in velocity is the acceleration times the frame time. Acceleration is due to gravity, and is therefore constant. Frame time is also nearly constant, so the change in velocity is also nearly constant in each frame. Since velocity always starts as an integer, and the change is always nearly the same, under a constant fps rounding has nearly the same error each frame. With a constant frame rate, Q3's rounding errors will tend to accumulate. For some frame rates, this will always round down; for others, it will always round up.


Based on this, the ideal frame rate for jumping distance is the highest one your computer can maintain that gets a fraction remainder near 0.5, but always greater than 0.5. Q3's gravity is 800, so you want the fractional part of 800/fps to be greater than 0.5. To protect against frame rate fluctuations, you'd also want nearby frame rates to have fractions greater than 0.5. Lastly, you want there to be as many frames as possible, so that the most possible positive error gets accumulated.


This chart gives (1) fps, (2) remainder of 800 / fps, (3) number of frames in 0.675 seconds, (4) maximum positive accumulated error in 0.675 seconds. The table was generated for all frame rates from 20 to 200 fps.

23 0.78  15   3.26
26 0.77  17   3.92
27 0.63  18   6.67
28 0.57  18   7.71
29 0.59  19   7.86
30 0.67  20   6.67
31 0.81  20   3.87
34 0.53  22  10.35
35 0.86  23   3.29
37 0.62  24   9.08
39 0.51  26  12.67
41 0.51  27  13.17
43 0.60  29  11.47
45 0.78  30   6.67
48 0.67  32  10.67
51 0.69  34  10.67
54 0.81  36   6.67
55 0.55  37  16.82
58 0.79  39   8.07
59 0.56  39  17.19
62 0.90  41   3.97
63 0.70  42  12.67
67 0.94  45   2.69
68 0.76  45  10.59
69 0.59  46  18.67
73 0.96  49   2.01
74 0.81  49   9.27
75 0.67  50  16.67
76 0.53  51  24.16
81 0.88  54   6.67
82 0.76  55  13.41
83 0.64  56  20.24
84 0.52  56  26.67
89 0.99  60   0.67
90 0.89  60   6.67
91 0.79  61  12.74
92 0.70  62  18.87
93 0.60  62  24.67
94 0.51  63  30.83
101 0.92  68   5.39
102 0.84  68  10.67
103 0.77  69  16.08
104 0.69  70  21.54
105 0.62  70  26.67
106 0.55  71  32.15
115 0.96  77   3.35
116 0.90  78   8.07
117 0.84  78  12.67
118 0.78  79  17.41
119 0.72  80  22.18
120 0.67  81  27.00
121 0.61  81  31.46
122 0.56  82  36.30
123 0.50  83  41.16
134 0.97  90   2.69
135 0.93  91   6.74
136 0.88  91  10.71
137 0.84  92  14.77
138 0.80  93  18.87
139 0.76  93  22.75
140 0.71  94  26.86
141 0.67  95  30.99
142 0.63  95  34.79
143 0.59  96  38.94
144 0.56  97  43.11
145 0.52  97  46.83
161 0.97 108   3.35
162 0.94 109   6.73
163 0.91 110  10.12
164 0.88 110  13.41
165 0.85 111  16.82
166 0.82 112  20.24
167 0.79 112  23.47
168 0.76 113  26.90
169 0.73 114  30.36
170 0.71 114  33.53
171 0.68 115  36.99
172 0.65 116  40.47
173 0.62 116  43.58
174 0.60 117  47.07
175 0.57 118  50.57
176 0.55 118  53.64
177 0.52 119  57.15


The C++ code to generate the above table is

code:

#include <stdio.H>
int main(int argc, char* argv[])
{
    for( int i=20; i<300; i++ )
    {
        double f = 800.0 / i;
        int ipart = (int)f;
        double fpart = f - ipart; 

        if( fpart > 0.5f )
        {
            printf( "%3d %.2f %3d %6.2f\n", i, fpart, (int)(i * .675), (1.0-fpart) * (int)(i*.675) );
        }
    }

    return 0;
}

Matching our conditions with the table, we predict that the best frame rates would be about 29, 41, 83, 92, 120, 140, and 170. Notice that these numbers are very near the values that people have found experimentally. This match between theory and experience lends credence to the model used.


When you jump, you are given 270 units / second of upward velocity, with a gravity of 800 units / second squared. Basic physics tells us that you should reach a maximum height of 45.5625 units after 0.3375 seconds. The height value shows the actual height of your jump. Frames is the number of frames the server used in reaching that height. Extra Vel is the approximate additional velocity you gained from rounding errors. Extra Hgt is the approximate additional height you gained from rounding errors.