QW physics air ru

From QWiki
Revision as of 13:26, 18 January 2010 by *>Sss

Физика QW: движение в воздухе, распрыг.

При помощи команд

  +forward
  +back
  +moveleft
  +moveright
  +moveup
  +movedown
  +speed

игрок задаёт значения forwardmove, sidemove, upmove.


Они определяются переменными cl_sidespeed, cl_forwardspeed, cl_backspeed, cl_upspeed

Также команда +speed увеличивает их в 2 раза.

Если активны 2 противоположные команды (например, +forward и +back), то учитывается только та, что была активирована раньше.


Значения forwardmove, sidemove, upmove передаются на сервер,

а также используется в клиенте для предсказания движения.

Код обработки движений игроков на сервере и на клиенте должен быть одинаковым.

У меня cl_forwardspeed 400 (ezquake default), а также при старте клиента выполняется строка +mlook;wait;+speed;wait;

Поэтому при нажатии +forward

forwardmove = 2 * 400 = 800.


Движение рассчитывается в функции PM_PlayerMove.


???? В ezquake при игре под mvdsv + ktx сервером forwardmove = 800 почему-то превращаются в 508 в PM_PlayerMove. ???

Рассмотрим движение игрока в воздухе. Вычисляется т.н. вектор желаемой скорости. В данном случае горизонтален и складывается только из 2-х компонент:

 горизонтального вектора длины forwardmove, направленного вдоль направления взгляда по горизонтали,

и вектора длины sidemove, направленного вбок. upmove не учитывается.

В вертикальном направлении играет роль только гравитация. Она учитывается отдельно.

Далее, если длина получившегося вектора превышает ограничение сервера, то его уменьшают до соответствующей длины. Это число равно 320 для обычного TDM и меняется от 230 до 450 в зависимости от класса игрока в TF.

Далее используются единичный вектор желаемого направления и значение желаемой скорости: мы попали в функцию PM_PlayerAccelerate().

Здесь значение желаемой скорости сразу ограничивается числом 30: wishspd = min(wishspd, 30);

Находим проекцию текущей скорости на желаемое направление: currentspeed = DotProduct (pmove.velocity, wishdir);

Вычисляем разницу между желаемой скоростью и проекцией теущей скорости. Если получается отрицательное число, то скорость не меняется. addspeed = wishspd - currentspeed; if (addspeed <= 0) return;


Далее вычисляется величина accelspeed = accel * wishspeed * pm_frametime =

            10 *320 * 0.014 = 44.8.

(wishspeed - это не wishspd)

После выбирается минимальная из addspeed и accelspeed accelspeed = min(accelspeed, addspeed);

Добавляем к вектору скорости вектор с полученной длиной и направлением wishdir VectorMA(pmove.velocity, accelspeed, wishdir, pmove.velocity);


Простейшие частные случаи. Если игрок в воздухе и не нажимает на кнопки, то скорость (горизонтальная) сохраняется.

Если у игрока нулевая скорость, то выполнив +forward, он приобретёт сразу скорость 30, направленную горизонтально вперёд.

Теперь рассмотрим распрыг. Скорость сразу будем считать большей, чем ограничение сервера (320 в TDM), т.к. её можно достигнуть ещё на земле. Разумеется, считаем, что игрок не устанавливал значения cl_sidespeed, cl_forwardspeed, cl_backspeed слишком маленькими.

Замечательным фактом является то, что в сущности, не важно, куда смотрит игрок, зато важно, куда направлен его wishdir.


Пусть угол между горизонтальной скоростью v и wishdir равен gamma.

wishspd = min(wishspd, 30) = 30 при заданных выше условиях.

addspeed = wishspd - currentspeed = 30 - v * cos(gamma)

конечное значение accelspeed >=0. Нам надо увеличивать скорость, поэтому нужно обеспечивать

cos(gamma) > 0 addspeed = 30 - v * cos(gamma) > 0

При распрыге величина accel * wishspeed * pm_frametime нам не важна,

т.к. мы не выходим на режим, где она актуальна.

Действительно, 44.8 > 30 - v * cos(gamma), если cos(gamma) > -14.8/v, т.е. если мы тормозим.

Итак, при распрыге accelspeed = addspeed;


Приращение скорости по модулю за один фрейм равно dv_frame = addspeed * cos(gamma) = (30 - v * cos(gamma)) * cos(gamma).

График зависимости от cos(gamma) - перевёрнутая парабола.

Верхняя точка при соs(gamma_best) = 15 / v;

dv_frame_best = = (30 - v * 15 / v) * 15 / v = 225 / v.

pm_frametime = 0.013, если работает 77fps физика и pm_frametime = 0.014, если работает 72fps физика (TF2003 standard, old TDM standard).

В предельном случае скорость растёт по закону dv/dt = 225/(v * pm_frametime)

Ускорение с 77fps физикой примерно на 7% больше, чем с 72fps.

v(t) ~ sqrt(t - t0). Подтверждено экспериментально, что игрок может преодолеть скорость sv_maxvelocity (2000)

Теоретически её можно достичь распрыгом за приблизительно 111 секунд с 77fps физикой.

Игрок должен обеспечивать правильное направление wishdir. Это обеспечивается поворотом.

Правильная угловая скорость поворота omega = addspeed * sin(gamma) / v = (15 / v) * sqrt(1 - (15 / v)^2).

С ростом скорости надо всё медленнее поворачиваться.

Комментарии и поправки приветствуются.