SoprachevAK 59 Posted February 5, 2021 Появилась идея собрать статистику по "везентю" стрельбы. Веб сервер, мат статистика, сайт с отображением для меня легко и просто ибо умею. Встаёт вопрос о том как получить инфу от клиента, как то год назад уже писал модик, крайне неприятный опыт, так что проще всего спросить совета, а не рандомно тыкаться в исходник Собственно мне нужно: Хук в старт битвы Получение общей инфы (ник игрока, техника, пушка, её урон и продибие по типу снарядов, разброс с учётом перков и модулей) Хук в момент выстрела Координата маркера прицела Текущий разброс (надеюсь он в хук выстрела ещё не разбрасывается) Танк на который наведён прицел (буду брать хп шотных совков) Тип снаряда которым произведён выстрел Хук? в момент попадания снаряда в коллайдер (видел как то на форму такой коллбэк, но сейчас найти не получается) Координата куда снаряд попал Инфа о попадание если попал в танк (тип попадания (пробитие/рикошет/не пробил), урон) Буду очень признателен за помощь, потенциально модик интересный, обговорил с некоторыми стримерами и они готовы информационно поддержать, так что данные для анализа будут Quote Share this post Link to post Short link Share on other sites
StranikS_Scan 4,210 #497050 Posted February 6, 2021 (edited) Этой седой бороде уже 10 лет в обед. Кто только не пробовал собирать и анализировать эту инфу. На раковом были даже профильные темы, я в них сидел раньше. Скажу сразу - ничего там интересного нет. Обычное нормальное распределение. Степень его кривости будет коррелировать с репрезентативностью собранных данных и тем насколько процесс их собирания близок к Пуассоновскому потоку событий. Про моды - можно посмотреть здесь (описание тут) и здесь. Про "потенциально модик интересный" - эти моды никому не интересны (кроме гиков конечно) и в первую очередь не интересны стримерам и их комьюнити, ибо ни стримеры ни их зрители совершенно не забираться в том, что эти моды делают, что показывают, как этим пользоваться и зачем это все нужно. Edited February 6, 2021 by StranikS_Scan 3 Quote Share this post Link to post Short link Share on other sites
SoprachevAK 59 #497085 Posted February 6, 2021 5 hours ago, StranikS_Scan said: ибо ни стримеры ни их зрители совершенно не забираться в том, что эти моды делают, что показывают, как этим пользоваться и зачем это все нужно. Ну тут вопрос в том как эту информацию отображать, я хочу сделать визуальную инфографику, которая будет по списку боёв показывать точку попадания каждого выстрела относительно круга сведения, будет опция переключение на нормализованное отображение, когда круги сведения приводятся к одному размеру, будет отображаться суммарный круг, где на одной картинке будут все точки попаданий выбранных боёв, на ней будет 50% квантиль нормального распределения и 50% квантиль фактического, по их взаимному расположению можно будет однозначно определить везло или нет в выбранных боях У многих стримеров горит с того как не летят снаряды и им было бы интересно чем то оправдать своё горение, ровно так же, как многие стримеры юзают модик показывающий точки попадания по танку после боя, пару стримеров которых я спросил с аудиторией 100к-150к, подтвердили интерес За модики спасибо, из них суммарно я смогу взять координату пушки до выстрела и координату попадания как по ландшафу, так и по технике, однако под вопросом остаётся способ получения текущего разброса танка в момент перед выстрелом, тк далеко не все выстрелы производятся с полным сведением И если не сложно, ткни в мануал как запустить исходники твоих модов, через .wotmod работают, через орион и exec, import/reload scripts from file/folder выдаёт ошибки по типу ImportError: No module named hook, тесторый скрипт print(BigWorld.player().name) работает Quote Share this post Link to post Short link Share on other sites
StranikS_Scan 4,210 #497090 Posted February 6, 2021 8 минут назад, SoprachevAK сказал: Ну тут вопрос в том как эту информацию отображать, я хочу сделать визуальную инфографику, которая будет по списку боёв показывать точку попадания каждого выстрела относительно круга сведения, будет опция переключение на нормализованное отображение, когда круги сведения приводятся к одному размеру, будет отображаться суммарный круг, где на одной картинке будут все точки попаданий выбранных боёв, на ней будет 50% квантиль нормального распределения и 50% квантиль фактического Это теория. А на практике: - не круг сведения, а круг разброса, это разные круги - есть клиентский круг разброса и есть серверный, в динамике они не совпадают - событие выстрела и событие попадания разнесены по времени - распределение у разброса снарядов в текущей версии игры не совсем "нормальное", оно искусственное и до конца не изучено (патч 0.8.5, патч 0.9.6, патч 1.0.x) - точка попадания может оказаться за точкой прицеливания, а может оказать и перед точкой прицеливания, так как снаряд летит в игре по параболе в трехмерном пространстве, а круг разброса это плоскость монитора, как результат простое проецирование точки коллизии снаряда с танком или ландшафтом на плоскость монитора, это не есть точка разброса выстрела, потребуется трехмерная математика, с помощью которой сначала придется определить плоскость разброса снарядов в точке прицеливания, параллельную с плоскость монитора игрока, а уже затем, зная точку реального попадания, восстановить траекторию снаряда и только после этого найти в какой точке она пронизывает плоскость разброса снарядов... - после чего осмысливаем с какой погрешностью это все будет работать в динамике Отсюда приходим к простому выводу, что если стримеру нужно знать "везло ему или не везло", то есть в разы более простые и понятные пути как это посчитать. Например, взять число выстрелов за бой и число попаданий и выдать стримеру %. Это идеальный мод для ютуберов и их хомяков. Легко, просто, понятно. Сей мод будет не только информативен но даже и полезен, так как сподвигнет малолетних танкистов не стрелять в небо по кустам и просто так. 1 час назад, SoprachevAK сказал: через .wotmod работают Они же собраны под пакет. Только в составе пакета и будут работать. Запуск через Орион они не предполагают. Quote Share this post Link to post Short link Share on other sites
SoprachevAK 59 #497095 Posted February 6, 2021 1 hour ago, StranikS_Scan said: есть клиентский круг разброса и есть серверный, в динамике они не совпадают Ну в твоём моде с артой есть серверный тангенс разброса 1 hour ago, StranikS_Scan said: распределение у разброса снарядов в текущей версии игры не совсем "нормальное", оно искусственное и до конца не изучено (патч 0.8.5, патч 0.9.6, патч 1.0.x) Вместо нормального можно брать среднее по всем боям, думаю оно будет весьма точным 1 hour ago, StranikS_Scan said: точка попадания может оказаться за точкой прицеливания Это проблема, я согласен, однако я и планировал искать пересечение с плоскостью заданной нормалью от прицела до пушки, но как посчитать траекторию я не представляю, но тогда интересно как рисуются трассеры, ведь для их отрисовки надо в момент выстрела уже точно знать траекторию проходящую через плоскость разброса 1 hour ago, StranikS_Scan said: после чего осмысливаем с какой погрешностью это все будет работать в динамике Спорно, большинство выстрелов делается в стоячем положение с полным или почти полным сведением, что нивелирует рассинхронизацию, и остаётся научиться считать траекторию, либо засчитывать лишь те выстрелы, у которых F(скорость полёта снаряда, расстояние от прицела до попадания) < X, где функцию F и константу X взять с потолка 1 hour ago, StranikS_Scan said: взять число выстрелов за бой и число попаданий и выдать стримеру % Это вроде бы и так показывается в послебоевой статистике, однако из 20 выстрелов обидно иметь не 5 попаданий по танку, а 15 промахов когда улетело в край разброса, обидны выстрелы, которые могли бы попасть, если бы не рандом В заключение остаётся вопрос о вычисление траектории Quote Share this post Link to post Short link Share on other sites
StranikS_Scan 4,210 #497107 Posted February 7, 2021 8 часов назад, SoprachevAK сказал: В заключение остаётся вопрос о вычисление траектории Ну да, в остальном же все гладко ))))))) https://github.com/StranikS-Scan/WorldOfTanks-Decompiled/blob/b92d3a2b1678f04f1ea78aa78ab6e77e51b98844/source/res/scripts/common/projectile_trajectory.py Quote Share this post Link to post Short link Share on other sites
SoprachevAK 59 #497108 Posted February 7, 2021 (edited) 24 minutes ago, StranikS_Scan said: Ну да, в остальном же все гладко ))))))) https://github.com/StranikS-Scan/WorldOfTanks-Decompiled/blob/b92d3a2b1678f04f1ea78aa78ab6e77e51b98844/source/res/scripts/common/projectile_trajectory.py Ну если предположить, что ProjectileMover.add получает refVelocity достаточную для вычисления траектории, то да, остальное вроде бы гладко И судя по всему это то что надо Два выстрела с бт7 артиллерийского Edited February 7, 2021 by SoprachevAK Quote Share this post Link to post Short link Share on other sites
SoprachevAK 59 #497755 Posted February 18, 2021 (edited) @StranikS_Scan а почему скорость трассера меньше ттх скорости снаряда? Ты в своём моде делишь её на 0.8, что видимо было посчитано эмпирически, тк в движке я никаких упоминаний об этих магических константах я не нашел ps. Если интересно вот что получилось, пока в альфа версии https://soprachev.com/wot-shoot/ Edited February 18, 2021 by SoprachevAK Quote Share this post Link to post Short link Share on other sites
ktulho 5,790 #497757 Posted February 18, 2021 50 минут назад, SoprachevAK сказал: почему скорость трассера меньше ттх скорости снаряда? Ты в своём моде делишь её на 0.8, что видимо было посчитано эмпирически, тк в движке я никаких упоминаний об этих магических константах я не нашел Quote Share this post Link to post Short link Share on other sites
StranikS_Scan 4,210 #497758 Posted February 18, 2021 (edited) 2 часа назад, SoprachevAK сказал: что видимо было посчитано эмпирически Ага, ну прям))) Эмпирика - удел безработных чудиков. У меня нет времени на такое. Смотри чтение параметров из xml - тыц. Ну и ссылку на подробное объяснение выше дал Ктулху. 2 часа назад, SoprachevAK сказал: ps. Если интересно вот что получилось, пока в альфа версии https://soprachev.com/wot-shoot/ Нету подписей у кругов. Не понятно, что есть что. Ну и в таких случаях стоит где-то описание подробностей давать ибо иначе сразу возникают вопросы - насколько все это соотносится с физикой игры. Например та же вероятность попадания (квантиль) при каких условиях считается. Когда, например, erfc() или erf() применяете, то нужно учитывать, что в игре распределения не идеальные ,а с обрезкой. ВГ в распределениях разброса, урона, пробития, берет(брал) обрезку по трем сигмам..... Еще бы вероятность попадания в круг показывалось бы. Да и кругов этих много... может какие-то круги с полупрозрачной заливкой сделать. А вообще, если вы такое умеете делать, как этот сайт сейчас, то мои советы вам нафиг не нужны ))))) Edited February 18, 2021 by StranikS_Scan Quote Share this post Link to post Short link Share on other sites
SoprachevAK 59 #505976 Posted July 23, 2021 (edited) On 2/18/2021 at 2:02 PM, StranikS_Scan said: Ага, ну прям))) Эмпирика - удел безработных чудиков. У меня нет времени на такое. Смотри чтение параметров из xml - тыц. Ну и ссылку на подробное объяснение выше дал Ктулху. Нету подписей у кругов. Не понятно, что есть что. Ну и в таких случаях стоит где-то описание подробностей давать ибо иначе сразу возникают вопросы - насколько все это соотносится с физикой игры. Например та же вероятность попадания (квантиль) при каких условиях считается. Когда, например, erfc() или erf() применяете, то нужно учитывать, что в игре распределения не идеальные ,а с обрезкой. ВГ в распределениях разброса, урона, пробития, берет(брал) обрезку по трем сигмам..... Еще бы вероятность попадания в круг показывалось бы. Да и кругов этих много... может какие-то круги с полупрозрачной заливкой сделать. А вообще, если вы такое умеете делать, как этот сайт сейчас, то мои советы вам нафиг не нужны ))))) А я да, сама актуальность) О подписях к кругам много кто говорил, но я постоянно ленюсь добавить их красиво, некрасиво добавлять нет смысла, тк понять какой круг за что отвечает можно потыкав галочки в настройках Квантиль считаю не теоретическую, а практическую по текущей выборке. Например выбрано 100 попаданий, сортирую их по расстоянию до центра относительно разброса на момент выстрела, и беру радиус от выстрела с индексом желаемой квантили. Для 60% квантили будет R = shots.sort()[count * 0.6], что означает: 60% выстрелов попали в радиус <= R при нормализации разброса на момент выстрела. Круги не помню как раньше, а сейчас по умолчанию включен 1 — базовый разброс на момент старта боя. Для группового выбора выстрелов отображается ещё круг выбранной квантили. Ну и советы с критикой всегда важны. Сейчас вот появилось время/желание и запилил аналитический раздел, можешь глянуть мб будет интересно. Взглянув на график распределения снарядов от класса техники возникает предположение, что я неправильно считаю арту https://wotstat.soprachev.com/analytics/60fa42ff8149f07093332402 Собственно внимание вопрос, как к человеку, куда лучше знакомому с игровыми механиками, как расположен конус разброса у САУ? Кажется что не так, как у обычных танков, и если да, то ещё от какого расстояния у них зависит фактический размер круга разброса? Сейчас я нахожу точку пересечения траектории трассера с плоскостью заданной нормалью от маркера до пушки в момент выстрела. Для арты это не работает. Edited July 23, 2021 by SoprachevAK Quote Share this post Link to post Short link Share on other sites
MoD 32 #506200 Posted July 27, 2021 (edited) On 7/23/2021 at 7:26 AM, SoprachevAK said: Собственно внимание вопрос, как к человеку, куда лучше знакомому с игровыми механиками, как расположен конус разброса у САУ? Кажется что не так, как у обычных танков, и если да, то ещё от какого расстояния у них зависит фактический размер круга разброса? Ходят слухи, что у арты круг разброса == кругу сведения On 7/23/2021 at 7:26 AM, SoprachevAK said: Сейчас я нахожу точку пересечения траектории трассера с плоскостью заданной нормалью от маркера до пушки в момент выстрела. Для арты это не работает. Не знаю как точно ты считаешь, можешь попробовать апроксимировать сразу после первого сегмента трассера - так у тебя будет почти идеальный круг, соответственно - это тебе даёт плоскость, на которой 2 точки - центр круга и пересечение трассера с этим кругом. Т.е. ты можешь посчитать оклонение ЗЫ Если охота - пободайся с распредением урона на добивании. Бери ХП танка по которому есть выстрел, который теоретически мог его уничтожить, выкидывай фугасы из расчётов и смотри на распределение урона. Там интересно - если урон снаряда ниже текущего ХП танка - почти никогда не будет фрага. Edited July 27, 2021 by MoD Quote Share this post Link to post Short link Share on other sites
SoprachevAK 59 #506202 Posted July 27, 2021 38 minutes ago, MoD said: Ходят слухи, что у арты круг разброса == кругу сведения Тыкался тут тыкался и уже сам начал сомневаться, новая версия покажет, возможно реально 1 в 1 как у обычных танков, а не работало из-за другого бага 39 minutes ago, MoD said: ЗЫ Если охота - пободайся с распредением урона на добивании. Бери ХП танка по которому есть выстрел, который теоретически мог его уничтожить, выкидывай фугасы из расчётов и смотри на распределение урона. Там интересно - если урон снаряда ниже текущего ХП танка - почти никогда не будет фрага. Конечно это было бы интересно, однако я не нашел как связать нанесённый урон с выстрелом, что в данной концепции хотелось бы. Типа список выстрелов и рядом с каждым результат выстрела. def showTracer(self, attackerID, shotID, isRicochet, effectsIndex, refStartPoint, velocity, gravity, maxShotDist, *a, **k) def showDamageFromShot(self, attackerID, points, effectsIndex, damageFactor, *a, **k) showTracer я юзаю для записи выстрела, showDamageFromShot можно было бы использовать для подсчёта дамага, но к сожалению у неё нет shotID и я не нашел как связать по другому. Так что отложу на неопределённое время, если будет большой интерес к модику, обновлю и допишу Quote Share this post Link to post Short link Share on other sites
spoter 1,402 #506211 Posted July 28, 2021 7 часов назад, SoprachevAK сказал: Тыкался тут тыкался и уже сам начал сомневаться, новая версия покажет, возможно реально 1 в 1 как у обычных танков, а не работало из-за другого бага Конечно это было бы интересно, однако я не нашел как связать нанесённый урон с выстрелом, что в данной концепции хотелось бы. Типа список выстрелов и рядом с каждым результат выстрела. def showTracer(self, attackerID, shotID, isRicochet, effectsIndex, refStartPoint, velocity, gravity, maxShotDist, *a, **k) def showDamageFromShot(self, attackerID, points, effectsIndex, damageFactor, *a, **k) showTracer я юзаю для записи выстрела, showDamageFromShot можно было бы использовать для подсчёта дамага, но к сожалению у неё нет shotID и я не нашел как связать по другому. Так что отложу на неопределённое время, если будет большой интерес к модику, обновлю и допишу при каждом showTracer от себя запоминай его в словарь. при каждом showDamageFromShot от себя, бери последнее значение в словаре и присваивай результат выстрела. 1 Quote Share this post Link to post Short link Share on other sites
StranikS_Scan 4,210 #506213 Posted July 28, 2021 (edited) 9 часов назад, SoprachevAK сказал: Типа список выстрелов и рядом с каждым результат выстрела. https://github.com/StranikS-Scan/StranikS_Scan-mods/tree/master/.experiments/SPGDispersion - это если ты в треньке один стреляешь для сбора статистки попаданий и изучения разброса, то сойдет и такой мод. Если в бою/реплеи нужно отследить чьи-то трассеры/попадания, то используем shooterID в new_showTracer и используем attackerID в new_showDamageFromShot и в new_showDamageFromExplosion 9 часов назад, SoprachevAK сказал: Тыкался тут тыкался и уже сам начал сомневаться, новая версия покажет, возможно реально 1 в 1 как у обычных танков, а не работало из-за другого бага У арты вроде все тоже самое, кроме того, что круг разброса - круг когда сверху смотришь. А если по вектору попадания снаряда смотреть при подлете к цели, то эллипс будет. Edited July 28, 2021 by StranikS_Scan Quote Share this post Link to post Short link Share on other sites
MoD 32 #506216 Posted July 28, 2021 По поводу конуса, если всё правильно - тебе надо от последнего сегмента трассера получать угол между нормалью в точке прицеливания и трассером, это тебе даст часть данных для вычисления эксцентриситета, второе что тебе надо это угол привершине конуса, который можно получить зная расстояние и макс величину раброса (или там уже тангенс есть для разброса), а длинна конуса - это длинна параболы, которая от точки выстрела до точки прицеливания. Тут прекрасное видео от 3b1b Quote Share this post Link to post Short link Share on other sites
StranikS_Scan 4,210 #506218 Posted July 28, 2021 (edited) Еще можно покурить вот этот Нашел древнюю тему по арте - http://forum.worldoftanks.ru/index.php?/topic/92927-эксперимент-с-разбросом-снарядов-у-арты-№2-прод/ Вот оттуда я знаю про эллипс. Можно почитать, что там. Edited July 28, 2021 by StranikS_Scan 1 Quote Share this post Link to post Short link Share on other sites
SoprachevAK 59 #506239 Posted July 28, 2021 @MoD @StranikS_Scan, за материалы спасибо, однако я ооочень сомневаюсь, что ленивые программисты в 2012 году писали для артиллерии новую уникальную механику, причём весьма сложную с точки зрения математики. Я на выходных тестировал, и у меня появилось предположение, что берётся координата маркера, на ней строится плоскость перпендикулярная вектору от САУ до маркера, на этой плоскости строится круг разброса и в нём рандомится точка, через которую пойдёт траектория снаряда (пока что ровно так же как и у обычных танков), а уже потом, в арт прицеле, этот круг проецируется на рельеф продолжая траекторию трассера. Если так, то это даже не конус получается, это получается банан (не знаю как по науке называется конус с параболической осью) Если так, то на сервере вообще не надо считать ничего, там просто дискретно летит трассер по простой траектории пока не пересечётся с препятствием, причём арта ничем не отличается от других танков в этом случае 9 hours ago, spoter said: при каждом showTracer от себя запоминай его в словарь. при каждом showDamageFromShot от себя, бери последнее значение в словаре и присваивай результат выстрела. в таком случае полностью игнорируются пулемётные танки, хотя они у меня и так не работают, потому что корректно считывать разброс для них я не смог И надо ещё проверить когда именно вызывается функция, и не считаются ли всякие тараны, пожары или расходники DamageFromShot'ом, потому что я тут недавно узнал, что дымы в спецрежимах являются трассером, который принадлежит игроку который их запустил Вообще да, решение простое и скорее всего действенное, о словаре я чёт не подумал) Quote Share this post Link to post Short link Share on other sites
MoD 32 #506277 Posted July 29, 2021 Не, у тебя не банан. У тебя конус и сечение его. У тебя есть точка прицеливания, нормаль в точке прицеливания и вектор последнего сегмента трассера - угол между ними. Это тебе задаёт плоскость П У тебя есть тангенс угла, это как раз угол при вершине конуса. ты размещаешь центр основания конуса в точке прицеливания, высота консуа - расстояние до цели (длинна дуги параболы), потом типа "продляешь консу вниз", и находишь эллипс, который образовывается при пересечении конса и плоскости П. Это тебе даст эллипс. Дальше у тебя есть точка попадания снаряда и эллипс -> можно найти насколько сильно оно уехало в сторону Но это ещё усложняется тем фактом, что эллипс у тебя может вырождаться в параболу и точка попадания - онато на рельефе, и она не факт что совпадёт с эллипсом. Это по сути с определённой точностью можно только вычислить.... Тут https://math.stackexchange.com/questions/2638515/how-to-convert-points-in-a-circle-to-points-in-an-ellipse описано как потом точку принадлежащую эллипсу пересчитать для круга Quote Share this post Link to post Short link Share on other sites
StranikS_Scan 4,210 #506321 Posted July 30, 2021 (edited) Немного про механику игры, исходя из клиентского кода Разброс в механике игры задается сервером как тангенс половинного угла разброса орудия dispersionAngle. Эту цифру сервер обсчитывает с тиком 0,1 сек и шлет клиенту игры. Вычисляет её он как функцию от динамических характеристик танка, путем применения дополнительных коэффициентов к базовому тангенсу разброса орудия, прописанному в файлах ТТХ для дистанции 100 метров. Все эти коэффициенты и формулу можно посмотреть в коде игры, они дублируют расчеты на сервере чтобы сглаживать движение объектов в клиенте игры. Расчеты в клиенте вынесены в отдельную функцию getOwnVehicleShotDispersionAngle. Ниже её код, а вот тут его разбор в числах, правда он мог немного устареть. def getOwnVehicleShotDispersionAngle(self, turretRotationSpeed, withShot=0): descr = self.__getDetailedVehicleDescriptor() aimingStartTime, aimingStartFactor, multFactor, gunShotDispersionFactorsTurretRotation, chassisShotDispersionFactorsMovement, chassisShotDispersionFactorsRotation, aimingTime = self.__aimingInfo vehicleSpeed, vehicleRSpeed = self.getOwnVehicleSpeeds(True) vehicleMovementFactor = vehicleSpeed * chassisShotDispersionFactorsMovement vehicleMovementFactor *= vehicleMovementFactor vehicleRotationFactor = vehicleRSpeed * chassisShotDispersionFactorsRotation vehicleRotationFactor *= vehicleRotationFactor turretRotationFactor = turretRotationSpeed * gunShotDispersionFactorsTurretRotation turretRotationFactor *= turretRotationFactor if withShot == 0: shotFactor = 0.0 elif withShot == 1: shotFactor = descr.gun.shotDispersionFactors['afterShot'] else: shotFactor = descr.gun.shotDispersionFactors['afterShotInBurst'] shotFactor *= shotFactor idealFactor = vehicleMovementFactor + vehicleRotationFactor + turretRotationFactor + shotFactor additiveFactor = self.__getAdditiveShotDispersionFactor(descr) idealFactor *= additiveFactor ** 2 idealFactor = multFactor * math.sqrt(1.0 + idealFactor) currTime = BigWorld.time() aimingFactor = aimingStartFactor * math.exp((aimingStartTime - currTime) / aimingTime) isGunReloading = self.guiSessionProvider.shared.ammo.isGunReloading() if aimingFactor < idealFactor: aimingFactor = idealFactor self.__aimingInfo[0] = currTime self.__aimingInfo[1] = aimingFactor if abs(idealFactor - multFactor) < 0.001: if not self.__isAimingEnded and not isGunReloading: self.soundNotifications.play('sight_convergence') self.__isAimingEnded = True elif idealFactor / multFactor > 1.1: self.__isAimingEnded = False elif aimingFactor / multFactor > 1.1: self.__isAimingEnded = False return [descr.gun.shotDispersionAngle * aimingFactor, descr.gun.shotDispersionAngle * idealFactor] В механике игры снаряды летят по параболе, параметры которой зависят от дистанции от танка игрока до точки прицеливания. Сервер в игре вычисляет дистанции по прямой, либо от опорной точки модели танка, либо от точки вылета снаряда. При этом снаряд на всех моделях вылетает из точки крепления пушки, она же опорная точка орудия (трассер кстати рисуется из другой точки, из конца орудия - элемент модели _GunFire). Первое юзается в механике маскировки и в засвета, второе в баллистике и прицеливании. Опорная точка пушки вычисляется, например так: startPoint = player.getOwnVehiclePosition() startPoint += player.vehicleTypeDescriptor.hull.turretPositions[0] + player.vehicleTypeDescriptor.turret.gunPosition Дистанция прицеливания вычисляется в той точке, в которую указывает маркер игрока, т.е. в точке пересечения луча из маркера, ортогонального плоскости монитора, с поверхностью игрового мира. В клиенте есть код на её вычисление, поэтому самому считать не надо, а можно брать готовое значение из: markerPos = player.gunRotator.markerInfo[0] Отсюда получается, что дистанция от танка игрока до точки прицеливания в механике стрельбы это всегда: markerDist = startPoint.distTo(markerPos) Тогда радиус круга разброса в точке прицеливания для любого танка это: dispersionRadius = player.gunRotator.dispersionAngle * markerDist В клиенте игры это все есть в коде, который отвечает за отрисовку сведения. Для этого используются следующие функции: 1. Внеклассовая функция расчета баллистических параметров в точке прицеливания getCappedShotTargetInfos def getCappedShotTargetInfos(shotPos, shotVec, gravity, shotDescr, vehicleID, minBounds, maxBounds, collisionStrategy): endPos, direction, collData, usedMaxDistance = BigWorld.wg_getCappedShotTargetInfos(BigWorld.player().spaceID, shotPos, shotVec, gravity, shotDescr.maxDistance, vehicleID, minBounds, maxBounds, collisionStrategy) if collData != 0: collData = EntityCollisionData(*collData) else: collData = None return (endPos, direction, collData, usedMaxDistance) Она обсчитывает траекторию нативно, но как именно она считает можно глянуть под спойлером. В списке выходных параметров direction это вектор попадания снаряда с учетом баллистической траектории. Модуль projectile_trajectory.py содержит неиспользуемые сегодня, но все еще актуальные, функции расчета траектории, это BigWorld.wg_computeProjectileTrajectory и пайтон аналог её, когда-то давно использовавшийся: def computeProjectileTrajectory(beginPoint, velocity, gravity, time, epsilon): checkPoints = [] endPoint = beginPoint + velocity.scale(time) + gravity.scale(time * time * 0.5) stack = [(velocity, beginPoint, endPoint)] while len(stack) > 0: lastIdx = len(stack) - 1 v1, p1, p2 = stack[lastIdx] del stack[lastIdx] delta = p2 - p1 xzNormal = Math.Vector3(-delta.z, 0.0, delta.x) normal = xzNormal * delta if abs(normal.y) < epsilon: checkPoints.append(p2) continue normal.normalise() extremeTime = normal.dot(v1) / (-gravity.y * normal.y) extremePoint = v1.scale(extremeTime) + gravity.scale(extremeTime * extremeTime * 0.5) dist = abs(normal.dot(extremePoint)) if dist > epsilon: extremeVelocity = v1 + gravity.scale(extremeTime) stack.append((extremeVelocity, p1 + extremePoint, p2)) stack.append((v1, p1, p1 + extremePoint)) checkPoints.append(p2) return checkPoints 2. Классовая функция расчета баллистических параметров и разброса в точке прицеливания __getGunMarkerPosition, использующая функцию из п.1 def __getGunMarkerPosition(self, shotPos, shotVec, dispersionAngles): shotDescr = self._avatar.getVehicleDescriptor().shot gravity = Math.Vector3(0.0, -shotDescr.gravity, 0.0) testVehicleID = self.getAttachedVehicleID() collisionStrategy = AimingSystems.CollisionStrategy.COLLIDE_DYNAMIC_AND_STATIC minBounds, maxBounds = BigWorld.player().arena.getSpaceBB() endPos, direction, collData, usedMaxDistance = AimingSystems.getCappedShotTargetInfos(shotPos, shotVec, gravity, shotDescr, testVehicleID, minBounds, maxBounds, collisionStrategy) distance = shotDescr.maxDistance if usedMaxDistance else (endPos - shotPos).length markerDiameter = 2.0 * distance * dispersionAngles[0] idealMarkerDiameter = 2.0 * distance * dispersionAngles[1] replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.isClientReady: markerDiameter, endPos, direction = replayCtrl.getGunMarkerParams(endPos, direction) return (endPos, direction, markerDiameter, idealMarkerDiameter, collData) Как видим, диаметр круга разброса в точке прицеливания это удвоенное текущее значение тангенса половинного угла разброса орудия танка 2*dispersionAngles[0] помноженное на дистанцию distance = .... (endPos - shotPos).length между опорной точкой орудия shotPos и точкой прицеливания endPos. 3. Далее находим, где используется __getGunMarkerPosition. В функции обновления сведения прицела __updateGunMarker, которая вызывается пока игрок в бою с периодичностью 0,1 сек, что составляет тик сервера: def __updateGunMarker(self, forceRelaxTime=None): if self._avatar.getVehicleAttached() is None: return else: shotPos, shotVec = self.getCurShotPosition() markerPos, markerDir, markerSize, idealMarkerSize, collData = self.__getGunMarkerPosition(shotPos, shotVec, self.__dispersionAngles) replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isRecording and not replayCtrl.isServerAim: replayCtrl.setGunMarkerParams(markerSize, markerPos, markerDir) if not self.__targetLastShotPoint: self.__lastShotPoint = markerPos replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.isUpdateGunOnTimeWarp: self._avatar.inputHandler.updateGunMarker(markerPos, markerDir, (markerSize, idealMarkerSize), 0.001, collData) else: relaxTime = self.__ROTATION_TICK_LENGTH if forceRelaxTime is None else forceRelaxTime self._avatar.inputHandler.updateGunMarker(markerPos, markerDir, (markerSize, idealMarkerSize), relaxTime, collData) self.__markerInfo = (markerPos, markerDir, markerSize) if self._avatar.inCharge: self._updateMultiGunCollisionData() return А еще в дублирующей её setShotPosition, которая обеспечивает автовозвышение орудия танка и обновление, упомянутого выше публичного буфера player.gunRotator.markerInfo. 4. Теперь нужно лезть в дебри модулей, отвечающих за управление прицелом и отрисовку сведения через флэшку, именно туда ведет вызов _avatar.inputHandler.updateGunMarker из кода выше. Если опустить подробности то, передача данных идет через объект DataProvider, который по сути является прокладкой для передачи данных в код флэшки прицела. Здесь же стоит отметить, что версии провайдера разные для прицела арты и для остальных прицелов танков. Для прицела арты создается он так: def _makeSPGProvider(): dataProvider = GUI.WGSPGGunMarkerDataProvider(aih_constants.SPG_GUN_MARKER_ELEMENTS_COUNT, aih_constants.SPG_GUN_MARKER_ELEMENTS_RATE) dataProvider.positionMatrixProvider = Math.MatrixAnimation() dataProvider.maxTime = 5.0 dataProvider.serverTickLength = constants.SERVER_TICK_LENGTH dataProvider.sizeScaleRate = aih_constants.SPG_GUN_MARKER_SCALE_RATE dataProvider.sizeConstraint = (aih_constants.SPG_GUN_MARKER_MIN_SIZE, aih_constants.SPG_GUN_MARKER_MAX_SIZE) dataProvider.setRelaxTime(constants.SERVER_TICK_LENGTH) return dataProvider А для всех остальных вот так def _makeDefaultProvider(): dataProvider = GUI.WGGunMarkerDataProvider() dataProvider.positionMatrixProvider = Math.MatrixAnimation() dataProvider.setStartSize(_setupGunMarkerSizeLimits(dataProvider)[0]) return dataProvider Что означают доп.константы у прицела арты, думаю не сложно догадаться, их значения кстати вот такие: GUN_MARKER_MIN_SIZE = 32.0 SPG_GUN_MARKER_ELEMENTS_COUNT = 37 SPG_GUN_MARKER_ELEMENTS_RATE = 10 SPG_GUN_MARKER_MIN_SIZE = 50.0 SPG_GUN_MARKER_MAX_SIZE = 100.0 SPG_GUN_MARKER_SCALE_RATE = 10.0 Обращаем внимание на последний параметр, у сведения арты есть дополнительный коэф. масштаба SPG_GUN_MARKER_SCALE_RATE. Передача данных в провайдер прицела арты выглядит вот так: def update(self, markerType, position, direction, size, relaxTime, collData): super(_SPGGunMarkerController, self).update(markerType, position, direction, size, relaxTime, collData) positionMatrix = Math.Matrix() positionMatrix.setTranslate(position) self._updateMatrixProvider(positionMatrix, relaxTime) self._size = size[0] ################################################# self._update() def _update(self): pos3d, vel3d, gravity3d = self._getCurrentShotInfo() replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.isClientReady: self.__updateRelaxTime() self._updateDispersionData() self._dataProvider.update(pos3d, vel3d, gravity3d, self._size) def _getCurrentShotInfo(self): gunMat = AimingSystems.getPlayerGunMat(self._gunRotator.turretYaw, self._gunRotator.gunPitch) position = gunMat.translation velocity = gunMat.applyVector(Math.Vector3(0, 0, self._shotSpeed)) return (position, velocity, Math.Vector3(0, -self._shotGravity, 0)) ######################### def _updateDispersionData(self): dispersionAngle = self._gunRotator.dispersionAngle ######################### isServerAim = self._gunMarkerType == _MARKER_TYPE.SERVER replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.isClientReady: d, s = replayCtrl.getSPGGunMarkerParams() if d != -1.0 and s != -1.0: dispersionAngle = d elif replayCtrl.isRecording: if replayCtrl.isServerAim and isServerAim: replayCtrl.setSPGGunMarkerParams(dispersionAngle, 0.0) elif not isServerAim: replayCtrl.setSPGGunMarkerParams(dispersionAngle, 0.0) self._dataProvider.setupConicDispersion(dispersionAngle) В то время как для остальных танков вот так: def update(self, markerType, pos, direction, sizeVector, relaxTime, collData): super(_DefaultGunMarkerController, self).update(markerType, pos, direction, sizeVector, relaxTime, collData) positionMatrix = Math.Matrix() positionMatrix.setTranslate(pos) self._updateMatrixProvider(positionMatrix, relaxTime) size = sizeVector[0] idealSize = sizeVector[1] replayCtrl = BattleReplay.g_replayCtrl if replayCtrl.isPlaying and replayCtrl.isClientReady: s = replayCtrl.getArcadeGunMarkerSize() if s != -1.0: size = s elif replayCtrl.isRecording: if replayCtrl.isServerAim and self._gunMarkerType == _MARKER_TYPE.SERVER: replayCtrl.setArcadeGunMarkerSize(size) elif self._gunMarkerType == _MARKER_TYPE.CLIENT: replayCtrl.setArcadeGunMarkerSize(size) positionMatrixForScale = self.__checkAndRecalculateIfPositionInExtremeProjection(positionMatrix) worldMatrix = _makeWorldMatrix(positionMatrixForScale) currentSize = _calcScale(worldMatrix, size) * self.__screenRatio idealSize = _calcScale(worldMatrix, idealSize) * self.__screenRatio self.__sizeFilter.update(currentSize, idealSize) self.__curSize = self.__sizeFilter.getSize() if self.__replSwitchTime > 0.0: self.__replSwitchTime -= relaxTime self._dataProvider.updateSize(self.__curSize, 0.0) else: self._dataProvider.updateSize(self.__curSize, relaxTime) Рассмотрим сначала второй код. Для аркадного и снайперского прицелов размер сведения в пикселях вычисляется непосредственно в функции update() и затем отдается провайдеру. Для этого берется диаметр мгновенного значения круга разброса в текущей точке прицеливания size = sizeVector[0], высчитывается его масштаб для экрана игрока через функцию _calcScale и этот масштаб умножается на половину ширины экрана в пикселях self.__screenRatio. Последняя величина находится вот так self.__screenRatio = GUI.screenResolution()[0] * 0.5. Чтобы сведение в игре не было очень маленьким или очень большим, а оно будет таковыми, имеется фильтр self.__sizeFilter, который ограничивает минимально и максимально возможное значение круга сведения. Лимиты, которые задаются в него, вычисляются вот так: def _setupGunMarkerSizeLimits(dataProvider, scale=None): if scale is None: settingsCore = dependency.instance(ISettingsCore) scale = settingsCore.interfaceScale.get() limits = (aih_constants.GUN_MARKER_MIN_SIZE * scale, min(GUI.screenResolution())) dataProvider.sizeConstraint = limits return limits Переходим к арт-прицелу. У арты расчеты в пикселях в функции update() не выполняются, вместо этого данные о точке выстрела, векторах начальной скорости и гравитации и текущем диаметре круга разброса в точке прицеливания - pos3d, vel3d, gravity3d и self._size - передаются прямо в провайдер. А также в него передается текущее значение тангенса угла разброса орудия dispersionAngle. Что со всем этим делает провайдер WGSPGGunMarkerDataProvider сказать трудно, т.к. он нативный. Если глянуть список доступных атрибутов и функций у WGSPGGunMarkerDataProvider, то там можно увидеть: *** enableSmoothFiltering *** getPointsInside *** maxTime *** positionMatrixProvider *** relaxTime *** reset *** serverTickLength *** setRelaxTime *** setStartSize *** setupConicDispersion *** setupFlatRadialDispersion *** sizeConstraint *** sizeScaleRate *** update *** updateSize Функция setupFlatRadialDispersion тоже встречается в коде клиента игры. Это код, который отвечает за отрисовку новой игровой фичи - подсветки на игровом поле места, куда стреляет или будет стрелять арта. Код класса можно глянуть тут. В качестве аргумента в функцию передается игровая константа areaRadius. Edited August 20, 2021 by StranikS_Scan 5 Quote Share this post Link to post Short link Share on other sites