Последние рекорды серверов
Pro Nub

Расчёт дистанции

Опубликовано Kpoluk 13 Мая 2023 в 12:13
Как мы уже знаем, с точки зрения взаимодействия с картой моделька игрока представляет собой бокс (box), то есть параллелепипед, в основании которого лежит квадрат со стороной 32 юнита. Высота параллелепипеда равна 72 юнитам в стоячем положении и 36 юнитам в сидячем. Для преодоления блока номиналом в 240 юнитов центру бокса достаточно пролететь 208 юнитов, а оставшиеся 32 мы получим за счёт размеров бокса:


Всё это верно до тех пор, пока мы имеем дело с блоками, края которых выровнены вдоль главных базисных осей карты. Но что если расположить 240 блок под углом 45°? Тогда перемещение бокса в виде сверху будет выглядеть примерно так:


Дело в том, что когда мы поворачиваем нашу мышь, бокс модельки при этом не поворачивается. В среде разработчиков игр такой бокс называется AABB - axis-aligned bounding box. Из названия понятно, что оси бокса всегда сонаправлены с базисными осями карты. Попробуем посчитать минимальное расстояние, которое необходимо преодолеть центру модельки, чтобы перелететь наш повёрнутый 240 блок:

240 - sqrt(2) * 32 = 194.745

Чтобы понять, насколько это сложный прыжок, достаточно прибавить к этому расстоянию 32, и тогда получим 226.745, то есть на самом деле повёрнутый 240 блок не сложнее, чем блок 227. В своё время эта особенность движка была названа Flibo Bug по имени финского джампера Flibo, обратившего на неё внимание. У нас на серверах и в сборке LAN сервера имеется плагин, позволяющий не просто измерить дистанцию между двумя точками, но и оценить сложность прыжка с помощью параметра Estimated LJ, подробнее об этом читайте в специальной статье.

Следующее, что нужно вспомнить, это телепорт из статьи про физику EdgeBug и JumpBug, выполняемый функцией PM_CategorizePosition. Когда от бокса до земли остаётся меньше двух юнитов, бокс принудительно телепортирует на землю. Этот телепорт работает гораздо чаще, чем может показаться. Когда мы прыгаем на ровной поверхности, то телепорт в конце прыжка происходит и при lj с приседанием в конце, и при lj без приседания, и после double duck, а нередко и после bhop (зависит от высоты прыжка, то есть от FOG и fuser2). Именно поэтому во всех таких случаях длительность прыжка составляет целое количество фреймов. Однако если прыжок делается на блоке, то телепорт может и не сработать. В статье про физику LongJump мы говорили о том, что обычный lj длится ровно 73 фрейма, однако DeathClaw пролетел ещё и часть 74-го фрейма. Произошло это из-за того, что при подлёте к блоку в конце 73-го фрейма DeathClaw всё ещё находился над промежутком между блоками, так что от бокса до земли было всё ещё больше, чем 2 юнита:


В конце 73-го фрейма нижний край бокса находится в точке A, и если бы блока не было, то спустя фрейм он оказался бы в точке B. Однако благодаря функции PM_FlyMove движок находит точку C, в которой бокс сталкивается с блоком и меняет направление движения, оказываясь в итоге в точке D.

Поставим себя на место демочекера или его программы, которой необходимо посчитать дистанцию прыжка в имеющейся демке. Зная длительность 74-го фрейма dt и скорость (Vx_A, Vy_A, Vz_A) в точке A, мы можем получить координаты (x_B, y_B, z_B) точки B:

x_B = x_A + Vx_A * dt
y_B = y_A + Vy_A * dt
z_B = z_A + Vz_A * dt

Высота точки C совпадает с высотой точки D, а значит мы можем найти отношение fraction = AC / AB, а из него и координаты точки C:

fraction = (z_A - z_D) / (z_A - z_B)
x_C = x_A + (x_B - x_A) * fraction
y_C = y_A + (y_B - y_A) * fraction
z_C = z_A + (z_B - z_A) * fraction

Вот и всё, теперь достаточно найти расстояние от точки S, в которой был сделан прыжок, до точки C:

distance = sqrt((x_C - x_S) * (x_C - x_S) + (y_C - y_S) * (y_C - y_S))

Ну а теперь посмотрим, как это делает наш плагин LJ статистики. Первым делом он повторяет trace движка на 2 юнита вниз из последнего положения в воздухе. Если trace натыкается на землю, то это значит, что перед приземлением сработал телепорт, и в качестве координат конечной точки можно брать x_A и y_A. Если же trace землю не задел, то плагин производит те же вычисления, что и программа демочекера. Отличие разве что в том, что плагин вынужден считать дистанцию не только на блоках, но и при приземлении на произвольную поверхность, а значит в общем случае мы не можем пользоваться высотой точки D. Поэтому для получения величины fraction плагин делает trace из A в B.

Но на этом сложности для плагина не заканчиваются. Возьмём для примера любой bhop-lj блок с kz_longjumps3. Если на сервере не включен mpbhop, то после касания bhop блока игрок начинает опускаться вместе с ним вниз вплоть до момента прыжка. Чем больше FOG бхопа, то есть чем дольше игрок на блоке, тем ниже он опустится. Именно поэтому прохождение карт без mpbhop оказывается сложнее, причём чем больше скорость опускания блока, тем больше трудностей это вызовет у игрока. Из-за такого опускания вертикальная координата игрока в момент прыжка оказывается ниже, чем в конце прыжка. Чтобы прыжок засчитался как успешный, плагин запоминает как начальное положение игрока в конце последнего фрейма перед касанием bhop блока. В этот момент движок уже поместил игрока на блок, однако опускаться блок ещё не начал.

На деле сложностей конечно ещё больше, ведь надо понимать из какого именно фрейма брать те или иные данные, уметь посчитать дистанцию в случае неудачного прыжка и отличать прыжок с приседанием от прыжка без приседания. Но мы суть расчётов уже уловили, так что оставим детали для разработчиков.