Прежде чем разбираться непосредственно со слайдом, мы рассмотрим две перекликающиеся с ним техники –
WallRun и
WallSlide.
WallRun
В статье про физику стрейфов мы уже обсуждали, что если во время бега периодически зажимать клавишу стрейфа на 15-30 фреймов, то скорость будет колебаться в диапазоне 249-262 юнита/с. Движение будет не совсем по прямой, но в среднем всё же быстрее, чем обычный бег, потому технику и назвали
FastRun.
Однако это не единственный способ передвигаться по земле быстрее, не прибегая к помощи duck'ов и bhop'а. Если бежать вдоль вертикальной стены, зажав
W и повернувшись немного в её сторону, то можно обнаружить, что скорость оказывается больше 250 юнитов/с. Эта техника называется
WallRun. По сути здесь происходит то же самое, что и при наборе прейстрейфа в lj. Разница лишь в том, что каждый фрейм скорость
Vnew
, полученная сложением текущей скорости
V
и прибавки
dV
, проецируется на плоскость стены благодаря функции
PM_ClipVelocity, с которой мы уже сталкивались в статье про физику EdgeBug и JumpBug:
Здесь стена находится справа, а вектор
dV
направлен туда же, куда мы смотрим, так как зажата только клавиша
W. В отличие от разгона без стены, нам не нужно всё время поворачивать мышь, поддерживая определённый угол с вектором скорости, так как он всё время направлен вдоль стены. Если вспомнить трёхмерный график для разгона на земле, то мы окажемся на краю той самой ямы, начинающейся после 250 юнитов/с. Попробуем теперь увеличивать угол
u
между
dV
и скоростью
V
, то есть всё больше поворачиваться в сторону стены. Тогда на графике мы будем как бы ползти по краю ямы, перемещаясь в облась большей скорости и большего угла
u
. Благодаря стене мы не сваливаемся в яму, а успешно достигаем скорости 277 юнитов/с при
u
около 27°:
К сожалению, дальнейшее увеличение
u
заставит скатиться в область меньших скоростей, однако достижение максимального престрейфа столь малыми усилиями действительно впечатляет.
Конечно, того же результата можно добиться не столько с помощью
W. Например, одновременно зажатые
W и
D дадут то же направление
dV
, если смотреть на 45° левее, чем просто с
W.
WallSlide
Эта техника также известна как
kkz jump по нику джампера
koukouz, активно использовавшего её в своих мировых рекордах. Тем не менее, её применяли и до этого. От WallRun'а отличие техники состоит в том, что движение вдоль стены происходит не на земле, а в воздухе, соответственно мы должны зажимать не
W, а
D (по-прежнему считаем, что стена находится справа). При этом благодаря наличию стены скорость точно так же каждый фрейм проецируется на её плоскость, а значит нам не нужно активно двигать мышь, как мы это делали при стрейфах в воздухе. Достаточно лишь поддерживать значение угла
u
в диапазоне, дающем прирост скорости. В статье про физику LongJump мы узнали, что для стрейфов в воздухе прирост скорости происходит при
u > arccos(30 / V)
и
u < arccos(-12.5 / V)
c максимумом в
u = arccos(5 / V)
. В случае же WallSlide мы максимизируем не скорость
Vnew
, а её проекцию на плоскость стены
Vx = Vnew * cos(x)
, где за
x
мы обозначили угол между
Vnew
и
V
:
Прирост
Vx
начнётся также при
u > arccos(30 / V)
, однако прекратится он уже при
u = 90°
, что хорошо видно из рисунка. При
u
от
arccos(5 / V)
до 90° прирост
Vx
всё ещё есть, но падает. Значит, оптимальный
u
, максимизирующий
Vx
, находится где-то между
arccos(30 / V)
и
arccos(5 / V)
. Для его нахождения вновь воспользуемся теоремой косинусов, однако на этот раз запишем её относительно угла
x
:
dV^2 = V^2 + Vnew^2 - 2 * V * Vnew * cos(x)
Подставим сюда результаты из статьи про физику LongJump:
dV = 30 - V * cos(u)
и
Vnew^2 = V^2 * sin(u)^2 + 900
:
900 - 60 * V * cos(u) + V^2 * cos(u)^2 = V^2 + V^2 * sin(u)^2 + 900 - 2 * V * Vnew * cos(x)
Vx = Vnew * cos(x) = -V * cos(u)^2 + 30 * cos(u) + 1
Если сделать замену
z = cos(u)
, то окажется, что мы имеем дело с функцией
Vx(z) = -V * z^2 + 30 * z + 1
, которая имеет максимум в точке
z = 15 / V
, откуда оптимальный
u = arccos(15 / V)
.
Как и для стрейфов в воздухе, давайте теперь получим конкретные значения
u
для набора скоростей
V
:
В принципе, раз мы не используем переключение стрейфов, то мы могли бы провести все рассуждения не для угла
u
между
dV
и
V
, а взять угол между направлением взгляда и плоскостью стены, который для WallSlide находится как
90 - u
. Например, при скорости
V = 250
юнитов/с максимальный набор скорости происходит тогда, когда мы отвёрнуты от стены на
90 - 86.56 = 3.44°
. Если же отвернуться больше, чем на
90 - 83.11 = 6.89°
, то скорость меняться не будет. Углы получаются настолько небольшими, что стороннему наблюдателю может показаться, будто игрок во время прыжка просто смотрит вдоль стены. Но мы то с вами теперь знаем, что происходит на самом деле.
WallSlide не только служит альтернативой LongJump, но и порой является единственно возможным способом сделать прыжок. Такая ситуация может сложиться в очень узком длинном проёме, где просто нет места для извилистой траектории lj. Для примера возьмём 2 прыжка
throttle из его демки на
prochallenge2_mix (скачать демку можно
здесь). Дело происходит на последней climb секции, таймер throttle показывает 19:14, и он прыгает блок в 230 юнитов, зажатый между двумя стенами. Ширина модельки 32 юнита, а между стенами всего 36 юнитов, так что lj там делать крайне проблематично. Поэтому throttle использует правую стену, чтобы сделать сначала WallRun с
W и
D, а затем WallSlide c
D.
GIF 2.23MB
Обратите внимание, что перед прыжком он заранее повернул мышь вправо, чтобы в воздухе сразу попасть в диапазон
u
, дающий прирост скорости при WallSlide. За это он, конечно, поплатился небольшими потерями скорости в конце WallRun. В полёте же throttle не стал рисковать и не двигал мышь, поддерживая постоянный угол
u
.
Буквально спустя 10 секунд throttle делает ещё один прыжок, на порядок более сложный. Расположен он прямо над блоком 230, то есть ширина проёма та же. Однако разгон с помощью WallRun здесь уже не сделать, приходится разбегаться и выпрыгивать из-за угла, после чего в воздухе прижиматься к правой стене:
GIF 1.80MB
Как видим, в полёте throttle сначала по инерции коснулся левой стены, получив небольшой серый участок на графике слева (в эти фреймы красный вектор скорости не менялся ни по величине, ни по направлению). Затем, ещё не коснувшись правой стены, он заранее повернул мышь влево, получив ещё один серый участок. И уже только после касания пошёл стабильный набор скорости с помощью WallSlide.
Другим хорошим примером послужит Stand-Up CountJump в узком коридоре на карте
qcg_to_chichin. Её автор
Qicg записал для нас отдельно только этот прыжок, скачать его демку можно
здесь.
GIF 3.68MB
Ширина коридора составляет всего лишь 34 юнита. Qicg тоже использует правую стенку, разгоняясь на
W и
D, потом делает double duck c приседанием, отпускает duck перед самым приземлением, проводит на земле 6 фреймов, делает прыжок и выполняет WallSlide с зажатой клавишей
D. Такое большое количество
FOG (фреймов на земле) не случайно, оно позволяет значительно уменьшить jumpoff, то есть прыгнуть ближе к краю маленького блока. При этом с обычным Stand-Up CountJump он бы потерял на земле много скорости, однако здесь Qicg предпочёл повернуть мышь в сторону стены уже после double duck'а, так что в течение 6 фреймов на земле он фактически продолжал делать WallRun, набирая скорость. С большим FOG jumpoff будет ещё меньше, правда тогда уже сложновато будет называть это Stand-Up CountJump.
В качестве ещё одного примера рекомендую к просмотру демку
fykseN на
sn_beachcliff (скачать демку можно
здесь). На карте довольно много близко расположенных блоков вдоль скал, на которых WallSlide применяется и в одиночных прыжках, и при bhop'е.
Slide
В статье про физику EdgeBug и JumpBug из функции
PM_CategorizePosition мы узнали, что наклонная поверхность превращается в слайд, когда угол наклона
a
становится больше
acrcos(0.7) = 45.573°
. Скольжение по слайду с точки зрения движка является движением в воздухе, причём в отличие от WallSlide для нас очень важным становится действие гравитации, которая по умолчанию каждый фрейм вычитает из вертикальной скорости 8 юнитов/с (вспомните функции
PM_AddCorrectGravity и
PM_FixupGravityVelocity из статьи про физику bhop). Мы будем представлять это как прибавление вектора
dVz
, направленного вертикально вниз и имеющего длину 8. Результирующий вектор скорости будет получаться как сумма текущей скорости
V
, вертикальной прибавки от гравитации
dVz
и горизонтальной прибавки
dV
от функции
PM_AirAccelerate. Что примечательно, величина
dV
зависит только от горизонтальной текущей скорости, так что
dVz
(которая в коде прибавляется раньше
dV
) на неё никак не влияет. После сложения результат проецируется на плоскость слайда функцией
PM_ClipVelocity. Уже здесь мы можем сделать важный вывод о том, что для слайда не имеет никакого значения вверх вы смотрите или вниз, изменение скорости определяется только поворотом в горизонтальной плоскости, то есть вправо-влево.
Движение по вертикали
Начнём с простого случая – подойдём к слайду (не слишком крутому) и начнём подниматься вверх, зажав
W (смотрим при этом строго в сторону слайда, чтобы не было дополнительного скольжения вбок):
Поначалу скорость будет небольшой, поэтому прибавка
dV
максимальна и равна 25. Если проекция
dV
на плоскость слайда больше, чем проекция
dVz
, то результирующая скорость увеличится. Фактически, это сразу даёт нам условие, при котором в принципе возможен подъём:
dVz * sin(a) < dV * cos(a)
8 * sin(a) < 25 * cos(a)
a < arctg(25 / 8) = 72.255°
Если
a >= 72.255°
, то мы будем иметь дело с так называемым
Steep Slide, скатывание с которого неизбежно. На обычном же слайде наша скорость будет расти, и вскоре
dV
будет вычисляться уже как
30 - V * cos(a)
и пойдёт на спад. Как только
dV
окажется равным
dVz * sin(a)
, изменение скорости прекратится, и мы будем равномерно ползти вверх по слайду. Мы могли начать по-другому – разбежаться и запрынуть на слайд, зажав
W, тогда сначала прироста скорости не было бы вообще, а затем он бы появился и достиг величины
dVz * sin(a)
, и мы точно так же вышли бы на постоянную скорость.
А можно ли подниматься по слайду сидя? В статье про физику CountJump мы выяснили, что в даке переменные
pmove->cmd.forwardmove
и
pmove->cmd.sidemove
умножаются на 0.333, поэтому в
PM_AirAccelerate accelspeed = 10 * 0.01 * (250 * 0.333) * 1 = 8.325
, то есть максимальная прибавка
dV = 8.325
. Значит, слайд в даке возможен при
a < arctg(8.325 / 8) = 46.141°
. А поскольку слайд начинается с
a > 45.573°
, то маппер должен попасть в диапазон меньше градуса, так что встретить такие слайды удаётся не часто. Впрочем, иногда необходимый наклон получается даже не на самом слайде, а на его стыке с другим слайдом.
Для примера посмотрим на характерные размеры Slide блоков нескольких карт:
Здесь стоит отметить, что на карте
b2j_slide_longjumps, являющейся логическим продолжением
slide_gs_longjumps, размеры блоков чуть отличаются – высота стартовой платформы не 256, а 257 юнитов, откуда угол наклона слайда
a = 48.925°
. Аналогичная ситуация на
qcg_longslides, которую по номиналам блоков можно считать продолжением
slide_svn_longslides – там размер слайда по горизонтали не 128, а 129 юнитов, соответственно угол наклона
a = 45.659°
.
Также заметьте, что на
kz-endo_slide_svn_duckslides слайд находится на высоте 64 юнита над землёй. Однако мы ведь уже знаем, что максимальная высота, на которую можно запрыгнуть с места, равна 63 юнитам. Странно, правда? Эту загадку нам предстоит решить в следующей статье, а пока двинемся дальше.
Движение по горизонтали
Теперь перейдём к другому частному случаю. Пусть мы движемся вдоль слайда, зажав
D
и имея строго горизонтальную скорость, лежащую в плоскости слайда:
На рисунке скорость
V
и прибавка
dV
лежат в горизонтальной плоскости, а прибавка
dVz
направлена вертикально вниз. Попробуем понять, насколько вообще реально поддерживать такое положение, когда движение вдоль слайда вверх или вниз отсутствует. Другими словами, после сложения
V
,
dV
и
dVz
и проецирования результата на плоскость слайда мы снова должны получить строго горизонтальную скорость. Звучит затруднительно, однако если разбить
dV
на две части (вдоль скорости
V
и перпендикулярно ей), то всё становится намного прозрачнее. Составляющая вдоль
V
будет давать приращение к горизонтальной скорости, а перпендикулярная должна уравновесить
dVz
:
dVz * sin(a) = dV * sin(u) * cos(a)
В диапазоне углов
u
от
acrcos(5 / V)
до
90°
(то есть
cos(u)
от
0
до
5 / V
) прибавка
dV = 25
, и условие принимает вид
8 * tg(a) = 25 * sin(u)
Посчитав
u
при всевозможных
а
, мы обнаружим, что условие
V < 5 / cos(u)
будет ограничивать скорость в районе 5-6 юнитов/с. Однако поскольку при
u < 90°
скорость
V
постоянно растёт, поддерживать такое состояние невозможно.
Значит,
u
будет лежать в диапазоне от
acrcos(30 / V)
до
acrcos(5 / V)
, где прибавка
dV = 30 - V * cos(u)
. Подставляя эту прибавку в условие равновесия, получаем
8 * tg(a) = (30 - V * cos(u)) * sin(u)
Пытаться решить это уравнение относительно
u
мы не будем, вместо этого заметим лишь, что с ростом скорости
V
угол
u
нужно будет понемногу увеличивать (то есть поворачиваться в сторону слайда).
Поворачиваемся к слайду
Если при горизонтальном движении по слайду мы начнём поворачивать мышь в сторону слайда (угол отворота от горизонтального направления вдоль слайда обозначим как
y
), то вектор скорости начнёт поворачиваться в ту же сторону, оставаясь при этом в плоскости слайда:
Величина прибавки
dV
по-прежнему зависит от угла
u
, который отсчитывается от горизонтальной составляющей скорости (фиолетовый вектор на рисунке), смотрящей куда-то внутрь слайда. То есть если мы захотим поддерживать
dV
ненулевой, то в последующие фреймы нам придётся продолжать поворачиваться в сторону слайда, что очень напоминает логику стрейфов в воздухе.
Чтобы понять, что происходит со скоростью
V
, мы разложим её на две составляющие в плоскости слайда (тёмно-красные векторы на рисунке). Разложив также прибавку
dV
в горизонтальной плоскости, мы таким образом сразу же видим, что одна часть
dV
будет тормозить горизонтальное движение вдоль слайда, а вторая, как и раньше, будет противостоять гравитационной прибавке
dVz
. Пока угол отворота
y
не окажется слишком большим, мы будем одновременно тормозить вдоль горизонтального направления слайда и ускоряться по слайду вверх.
Для примера возьмём демку
BuTaMuH на карте
b2j_slide_longjumps, где он берёт slide блок в 241 юнит (скачать можно
здесь). Проследим за изменением горизонтальной скорости и угла
u
от момента прыжка до приземления:
GIF 3.84MB
Хорошо видно, как красный вектор горизонтальной скорости делает небольшой скачок в момент касания слайда – происходит проецирование всей скорости на плоскость слайда. После касания BuTaMuH продолжает вести мышь в сторону слайда, тем самым увеличивая горизонтальную скорость и в то же время тормозя скатывание по слайду. Благодаря этому в нижней точке скорость достигает значения 749.3 юнита/с. При подъёме горизонтальная скорость неуклонно падает, а вертикальная быстро растёт, что можно наблюдать на следующем графике:
Здесь показан прирост вертикальной скорости начиная с нижней точки траектории до последнего фрейма на слайде. Угол поворота в сторону слайда менялся при этом от
y = 0°
до
y = 50°
. Если взять максимальную прибавку
dV = 25
, то при
y = 0°
прирост вертикальной скорости составит
dV * cos(y) * cos(a) * sin(a) = 25 * cos(0) * cos(48.925°) * sin(48.925°) = 7.84
юнита/с, а при
y = 50°
получим 4.53 юнита/с. В случае же с BuTaMuH уже на анимации было видно, что угол
u
сначала отклонялся от
arccos(5 / V)
в меньшую сторону, что привело к уменьшению
dV
и небольшой яме в начале графика прироста. Затем угол
u
стал больше
arccos(5 / V)
, благодаря чему BuTaMuH вышел на максимальный прирост в вертильной скорости, однако в то же время он стал больше терять скорость в горизонтальном направлении слайда. Перед сходом со слайда BuTaMuH заранее начал отворачивать мышь, так что прибавка
dV
резко упала, и гравитация стала перевешивать. В последний фрейм на слайде горизонтальная скорость составляла 83.3 юнита/с, а вертикальная 387 юнитов/с.
Замечание: значения скорости в демке сохраняются с погрешностью 0.125 юнита/с, поэтому на графике прироста, построенном по разности таких значений, погрешность величин составляет 0.25 юнита/с. Именно поэтому прирост на графике достигает значения 8.0 при максимуме 7.84 юнита/с.
Отворачиваемся от слайда
В этой статье мы уже познакомились со steep slide, так что теперь предлагаю взглянуть на то, как
.script берёт последний блок на карте
slide_svn_steepslides_h (скачать демку можно
здесь):
GIF 3.43MB
После разбега и касания слайда, происходит уже знакомая нам процедура – .script поворачивается направо в сторону слайда, теряя скорость и набирая высоту. Но вот после прохождения верхней точки происходит любопытная вещь – по мере скольжения вдоль слайда он всё больше отворачивается от него. Подобную технику он вынужден применить потому, что после прохождения верхней точки траектории он начинает соскальзывать вниз (как мы помним, на steep slide гравитация всегда побеждает), причём чем дальше, тем быстрее. Возрастающая вертикальная скорость проецируется на плоскость слайда и превращается в горизонтальную, в результате чего суммарный вектор горизонтальной скорости начинает уходить в сторону от слайда. А поскольку .script хочет иметь прирост скорости, он для поддержания угла
u
в необходимом диапазоне вынужден уводить мышь влево вслед за вектором скорости.
Заключение
Когда мы пытались оценить максимальные возможности человека на lj, то нам уже пришлось несладко, со слайдом же провернуть подобное практически невозможно. Мало того, что речь постоянно идёт об одновременном изменении горизонтальной и вертикальной скоростей, даже при рассмотрении конкретного прыжка, как мы это только что делали, результат будет сильно зависеть от начальной и конечной высот на слайде, а также от того, как игрок обойдётся с набранной скоростью уже после слайда. В произвольном же случае варьируются и размеры, и наклон слайда, и конечная цель – где-то нужно подлететь как можно выше, где-то набрать горизонтальную скорость, а на блоках типа
b2j_slide_longjumps требуется что-то среднее. Неслучайно в kreedz можно встретить карты, практически полностью посвящённые слайду. Несмотря на то, что мы рассматриваем слайд как одну из техник, он вполне может выступать самостоятельным направлением, причём его границы возможного остаются достаточно размытыми.
Тут можно вспомнить, как мы обсуждали существование специальных серверов с настройкой
sv_airaccelerate, изменённой с 10 на 100. В случае слайда это небольшое на первый взгляд изменение привело к формированию целых сообществ, посвящённых surf (такое название получил slide с
sv_airaccelerate 100). Связано это с тем, что во-первых максимальная прибавка
dV
равна в таком случае не 25, а 30, что влияет как на набор горизонтальной, так и вертикальной скоростей. Чем дольше мы скользим на surf блоке, тем больше проявляется разница, благодаря чему на surf быстро достигаются огромные скорости. Во-вторых, диапазон углов
u
, дающий прирост горизонтальной скорости, оказывается шире, что добавляет манёвренности при перелётах между surf блоками.
На этом пока всё, однако тема слайда ещё всплывёт в наших последующих изысканиях.