Делаю нативный AOE поиск юнитов в JASS

Все юниты на карте находятся в одной общей группе, карта небольшая
Юнитов ищу с помощью ForGroup по такой формуле: если (расстояние между координатами минус физический размер) меньше или равно AOE

Но я решил сделать эксперимент, брал юнита с дальней атакой, отбегал и давал приказ атаковать цель
Потом детектил ивент на атаку и измерял расстояние между координатами юнитов, в первом случае я атаковал слева и показало 830.031, во втором случае я уже атаковал справа и показало другие цифры 829.394
Повторил эксперимент ещё раз, атакуя с разных сторон и цифра получалась плюс-минус ~3 единицы, но не превышало максимальную возможную дальность атаки (физ. размер атакующего + радиус атаки атакующего + физ. размер цели)

И из за этого у меня возникли сомнения что получится сделать нативный AOE поиск, который работал бы точно как AOE из обычных абилок варкрафта

UPD:
GroupEnumUnitsInRange просто тупо по расстоянию между координатами ищет юнитов, это не то

Принятый ответ

C++ тоже показывает 832.0, на С почему-то не смог запустить.
UrsaBoss, вообще, используй нативки, они точнее будут нахождения дистанции "руками" в данном случае. Но не используй Pow(), эта функция очень неточная.
constant native IsUnitInRange       takes unit whichUnit, unit otherUnit, real distance returns boolean
constant native IsUnitInRangeXY     takes unit whichUnit, real x, real y, real distance returns boolean
constant native IsUnitInRangeLoc    takes unit whichUnit, location whichLocation, real distance returns boolean
`
ОЖИДАНИЕ РЕКЛАМЫ...
0
28
5 лет назад
0
А какая вообще дальность атаки?
0
18
5 лет назад
0
PT153:
А какая вообще дальность атаки?
у атакующего 600
физ. размер атакующего 32
физ. размер цели 200

Хочется узнать, использует ли движок такой же способ AOE поиска, который хочу сделать я
0
28
5 лет назад
Отредактирован PT153
0
-__-
А ландшафт плоский?

Я бы АОЕ поиск делал через GroupEnumUnitInRange.
0
18
5 лет назад
0
PT153:
А ландшафт плоский?
да
Я бы АОЕ поиск делал через GroupEnumUnitInRange.
там просто по координатам)

В AOE способностей игра вычитает физ. размер из расстояния между координатами и проверяет получилось или нет меньше требуемого AOE
Если смотреть на глаз, то именно так и выходит
0
26
5 лет назад
0
А такая точность критична, ведь погрешность маленькая?
Наверное, тут может быть связано с точкой начала атаки у юнита в РО.
0
18
5 лет назад
Отредактирован Hodor
0
меньше требуемого AOE
меньше или равно, чуть ошибся

8gabriel8:
А такая точность критична, ведь погрешность маленькая?
Наверное, тут может быть связано с точкой начала атаки у юнита в РО.
Т.е юнит может не остановиться именно на радиусе 832, а чуть дальше пройти до радиуса ~830?
0
26
5 лет назад
0
Не совсем это имел ввиду, так как не знал, двигается ли юнит или башней стоит, но это тоже вариант.
По идее попробуй триггерно расставить юнитов, цель в (0;0), а атакующего сначала в (832;0), потом в (-832;0). Через секунду после атаки показывай расстояние между ними, если будет таким же, как описал в вопросе, то поставь точку начала атаки атакующему на (0;0;0), если опять расстояние будет таким же, то попробуй цели модель сменить на какую-нибудь идеально ровную.
0
18
5 лет назад
Отредактирован Hodor
0
8gabriel8:
832.015 во всех случаях
слева, сверху, справа, снизу. И модель убирал и точку начала атаки

Убрал теорему Пифагора и посчитал просто по Y координатам и вышло ровно 832

Поставил 833 и показало 824.090

Я сделал вывод себе: теорема Пифагора немного неточная в варкрафте и юнит не всегда встает ровно в нужный радиус атаки (но при этом не превышает свой же доступный радиус атаки)

Короче, вот что нужно выяснить
Использует ли варкрафт на нативном уровне теорему так же как и в JASS?
Т.е в плане точности
К примеру игра получит расстояние 50, а в JASS будет 49.99999
Плохой пример, но думаю понятно
0
26
5 лет назад
0
Наверное, тут роль может играть ещё ось Z. Ты ведь чисто по X и Y рассматриваешь?
0
18
5 лет назад
0
8gabriel8:
Наверное, тут роль может играть ещё ось Z. Ты ведь чисто по X и Y рассматриваешь?
высота в варкрафте не влияет на расстояние)
проверял уже

Но я уже сказал) Мне грубо говоря пофиг что там с дальностью атаки у юнитов, главное что она не превышает своего максимума
В данный момент я сомневаюсь в точности вычислений из под JASS
Т.к посчитал через теорему, получил 832.015
Посчитал просто Y2 минус Y1 получил 832.000

А если точность вычислений теоремы в JASS такая же как и в движке, то всё очень хорошо и можно будет закрыть вопрос.
Осталось подождать того кто сможет сказать это с уверенностью)
0
26
5 лет назад
0
По идее варик точно не высчитывает точный радиус атаки для расстановки юнитов. Возможно, из-за длительности анимации walk, если она выше какого-то значения, то юнит должен её воспроизвести до конца, продолжая движение, возможно, из-за тяжести точных расчётов для отрядов юнитов на компьютерах того периода, возможно, потому что так реалистичнее получается, возможно, обновление исполнения приказов юнитов выполняется по какому-то небольшому периоду, а не точь-в-точь. Короче, лишь гадаю, так как не знаю причины.

Кстати, как именно ты считаешь через теорему?
0
18
5 лет назад
Отредактирован Hodor
0
8gabriel8:
Кстати, как именно ты считаешь через теорему?
так же как в ГУИ DistanceBetweenPoints
Беру из координат X2 Y2 вычитаю X1 Y1 и потом полученные dx dy по отдельности возвожу в квадрат и слагаю, в конце из полученного числа вычисляю корень
local real dx = GetUnitX(gg_unit_hdhw_0001) - GetUnitX(gg_unit_Hblm_0000)
local real dy = GetUnitY(gg_unit_hdhw_0001) - GetUnitY(gg_unit_Hblm_0000)
call BJDebugMsg(R2S(SquareRoot(dx * dx + dy * dy)))
т.е на самом деле в этой ситуации происходят два простых вычисления:
  1. 832 умножается на 832
  2. и потом из этого вычисляется корень
и корень равен 832.015
0
26
5 лет назад
0
Не очень верится, что при вычислении корня реальных переменных такая погрешность. Попробуй вывести на экран кроме корня все значения получаемых координат, то есть X1, Y1, X2, Y2 и сумму квадратов.
0
28
5 лет назад
Отредактирован PT153
0
корень равен 832.015
Так это нормально, возьми любой другой язык, поставь тип переменная на float и сделай такие же вычисления. Уверен, результат будет тот же.
UPD: проверил в JAVA и Python, там вроде выводит 832.0.

Выводи все 9 цифр после запятой. Или вот этой функцией.
function R2SX takes real r returns string
    return R2SW(r, 0, -1)
endfunction
0
26
5 лет назад
0
Конечно, слышал о небольшой погрешности в вычислениях таких чисел, но ты получил 824.090, когда считал от 833, а это погрешность почти в 9 целых!
Пока с планшета сижу, не могу проверить.
0
28
5 лет назад
Отредактирован PT153
0
но ты получил 824.090, когда считал от 833, а это погрешность почти в 9 целых!
Я думаю, что UrsaBoss опечатался и хотел написать 834.090.
0
26
5 лет назад
0
Всё равно значительно больше 0.015. Хотя ладно, надо было больше интересоваться вычислениями с плавающей точкой раньше, когда движок варика делали)
0
28
5 лет назад
Отредактирован PT153
0
C++ тоже показывает 832.0, на С почему-то не смог запустить.
UrsaBoss, вообще, используй нативки, они точнее будут нахождения дистанции "руками" в данном случае. Но не используй Pow(), эта функция очень неточная.
constant native IsUnitInRange       takes unit whichUnit, unit otherUnit, real distance returns boolean
constant native IsUnitInRangeXY     takes unit whichUnit, real x, real y, real distance returns boolean
constant native IsUnitInRangeLoc    takes unit whichUnit, location whichLocation, real distance returns boolean
Принятый ответ
0
18
5 лет назад
Отредактирован Hodor
0
PT153:
Я думаю, что UrsaBoss опечатался и хотел написать 834.090.
824.090
Это если поставить героя на расстоянии 833.000, то ему придется чуть чуть пройти, короче проехали.

Главное чтобы точность работы с float была такая же как в движке.

IsUnitInRange
Тут тоже считает по расстоянию между координатами)

До завтра подержу вопрос открытым, вдруг кто то ещё знаниями поделится)
Выводи все 9 цифр после запятой. Или вот этой функцией.
function R2SX takes real r returns string
    return R2SW(r, 0, -1)
endfunction
832.014832


UPD:
как я уже определил с помощью BJDebugMsg - вся неточность в SquareRoot, т.е я передаю туда 692224.000 (квадрат 832), а мне возвращает 832.014832

короче, додумался сделать такой тест точности теоремы в движке:
оба юнита стоят в одинаковых X координатах, а атакующий смещен вверх от цели ровно на 832.000
832.000 это максимальный радиус атаки (т.к физ. размер атакующего 32, физ. размер цели 200 и дальность атаки 600)
если я задам атакующему координаты выше 832.000, то атакующий автоматически сдвинется с места и его координаты при атаке уже будут примерно 824 (округляя), а если я задам 832 или ниже, то атакующий никуда не сдвинется
Т.е при событии атаки я вычисляю разницу между Y координатой обоих целей

Это понятно
Я задаю 832 по Y и начинаю измерять расстояние, если я использую SquareRoot((y2-y1)*(y2-y1)) - то получаю 832.014832
делая нехитрые вычисления я нахожу "дальность атаки", т.е 832.014832 минус 200 и минус 32 и получаю 600,014832
Т.е атакующий по мнению SquareRoot "бьет с расстояния 600,014832", а это уже выше 600

А вот если я задам Y координату 832.014 или даже 832.001, то во время начала атаки используя разницу в Y координатах - будет около 824
Т.е получается что с 832.001 расстояния невозможно начать атаку и юнит "идет до цели"
Я ставлю обратно 832 в Y и всё замечательно

Учитывая то что я говорил выше - получается что SquareRoot в движке игре полностью точный, а SquareRoot в JASS нет

Попробовал Pow(dy*dy, .5), там такая же неточность, но уже не выше допустимого значения, а ниже
831.998901

Абсолютный бред
Сделал вот так: SquareRoot(SquareRoot(dy*dy)*SquareRoot(dy*dy))
И всё равно выдало 832.014832
Повторюсь, dy == 832

Столько часов делал бд со всеми физ. размерами и дальностями атаки, а оно вот как
Может быть есть какие нибудь способы сделать чтобы всё было точно?
Не предлагайте округлять, 832 это просто тестовое число, в игре же могут быть абсолютно разные числа


UPD:
извиняюсь, IsUnitsInRange считает не по координатам, а по физ. размерам + дальность (я думал из за Range в GroupEnumUnitsInRange который считает по координатам), как раз то что надо и нагрузки меньше будет
короче, закрыл вопрос
0
16
5 лет назад
0
>> 600,014832 а это уже выше 600
это выше в нашем мире, где точность флоатов неограничена, а под капотом вполне нормальная дельта расхождения, не говоря уже о том, что само представление координат не идеальное
0
18
5 лет назад
0
DracoL1ch, но если я из JASS получаю 600.014832, а исходя из опыта - игра получает ровно 600.000000
Т.е я задаю юниту 832.000 по Y, даю приказ атаковать - он никуда не уходит и в момент атаки имеет эти координаты
Далее я задаю юниту уже 832.001 по Y, опять даю приказ атаковать и в момент атаки координаты уже около 824, имхо игра не позволила ему атаковать с 832.001, что говорит о точности вычислений в движке.
Как я знаю движок на C++ писался, поэтому тем более)

По идее уже пофиг на точность, буду юзать IsUnitInRange

В планах сделать поиск ближайшего юнита, там уже смогу юзнуть бд и думаю не будет важна точность
0
16
5 лет назад
0
понятия не имею, в чем там дело, лишь уточняю, что не обязательно движок сам стремится к абсолютной точности
0
18
5 лет назад
0
DracoL1ch, SquareRoot внутри движка отличается от того что в JASS?
Ну я имел в виду близзарды делали sqrt в JASS по своему или юзнули тот что доступен в ++?

Ну чтобы не было так что я посчитаю 600.123 расстояния, а движок 600 ровно
0
16
5 лет назад
0
ну ты ж понимаешь, что компилятор пережевал их реализацию в нечитаемую битовую магию?) Местами используется ассемблеровский sqrt, местами - самопальный
0
28
5 лет назад
0
UrsaBoss, а где задаются физический размер юнита? Просто мне нужно, чтобы игра не учитывала физразмер юнита в нативках, что ты кинул.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.