ВНИМАНИЕ! Наша конференция посвящена космической тематике и компьютерным играм. Политические вопросы и происходящие в мире события в данный момент на нашем сайте не обсуждаются!
|
» Расчет точки упреждения | страница 2 |
|
|
|
Канал Игры Мечты: «Расчет точки упреждения» |
|
|
akm 470 EGP
Рейтинг канала: 1(3) Репутация: 173 Сообщения: 1638 Откуда: Паразит Прайм Зарегистрирован: 23.10.2002 |
|
синусы, кватернионы, дифференциальные уравнения.... главное хвост! ой, т.е. задачу можно решить в лоб численными методами, причем с минимальной нагрузкой движка расчетами. Я такую задачу успешно решил даже на тормознутом скрипт-движке Х2, вот код:
Код: |
001 $step.duration = 2 // в секундах
002 $num.of.steps = 9 // (num.steps x duration) определяет временной интервал, в теч. которого будет усредняться вектор скорости цели
003
010 $pmax = 3
011 $Interception.point = array alloc: size=$pmax
012 $Tgt.positions = array alloc: size=$num.of.steps
013 $n = 0
014 $positions.saved = $n
015
016 // -----------------
017 // Здесь синхронизация с глобальным таймером до 1сек
018 // т.е. выполнение тут останавливается до момента перехода таймера ч-з целую секунду
019 // -----------------
020 $cur.time = значение глоб. таймера
021
022 $cur.Tgt.pos = $target -> get position as array
023 $Tgt.positions[$n] = $cur.Tgt.pos
024 $estim.dist = get distance between [THIS] and $target
026
027 while (надо стрелять)
028
029 $t = ( 10 * $estim.dist ) / $our.speed // time is in 0.1 sec
033 inc $n
034 if ($n == $num.of.steps) $n = 0
035
036 if not ($positions.saved == $num.of.steps)
037 inc $positions.saved
038 $delta = $positions.saved * $step.duration * 10
029 else
040 [THIS] -> set local variable: name='Max.Precition.Reached' value=[TRUE]
041 end
042
043 $time2sync = $cur.time + $step.duration
044 // -----------------
045 // Здесь синхронизация с глобальным таймером до $time2sync
046 // т.е. выполнение тут останавливается до момента перехода таймера через $time2sync
047 // -----------------
048 $cur.time = значение глоб. таймера
049
050 skip if (надо стрелять)
051 break
052 skip if $target -> exists
053 break
054 $cur.Tgt.pos = $target -> get position as array
055 $our.pos = [THIS] -> get position as array
056 $prev.pos = $n - $positions.saved
057 if ($prev.pos < 0) $prev.pos = $prev.pos + $num.of.steps
058
059 $prev.Tgt.pos = $Tgt.positions[$prev.pos]
060
061 $p = $pmax
062 while $p
063 dec $p =
064 $x0 = $prev.Tgt.pos[$p]
065 $x = $cur.Tgt.pos[$p]
066 $x = ( ( $x - $x0 ) * $t ) / $delta + $x
067 $Interception.point[$p] = $x
068 end
069
070 $estim.dist = [THIS] -> get distance to: position array=$Interception.point
071 $y = $Interception.point[1]
072 $z = $Interception.point[2]
073 $nav.mark -> set position: x=$x y=$y z=$z
074 $Tgt.positions[$n] = $cur.Tgt.pos
075 end
|
и уже после десятка итераций мы имеем очень точное направление на цель $target. Более того, каждый последующий залп, когда нам нужно уточнить направление на цель (в данном примере каждые 2 сек), повторять эти 10 итераций не требуется! Достаточно одной - и у нас опять точная координата цели!
Собственно, искомое направление на цель - это $nav.mark -> set position: x=$x y=$y z=$z,
а точнее это даже будет точка "столкновения" в пространстве, если цель не изменит вектор скорости.
Исходные параметры - это:
$our.speed - модуль скорости снаряда (или модуль скорости корабля + скорости снаряда, если они суммируются - зависит от физики)
$cur.Tgt.pos = $target -> get position as array - тек.координаты цели
$our.pos = [THIS] -> get position as array - тек.координаты нашего корабля.
Вместо задержек для синхронизации, лучше запускать эти части процедуры по прерыванию от таймера (просто такого функционала в Х2 нет), причем в фоновом режиме, а сам корабль попросту должен всегда стрелять в $nav.mark, а уточнение этого маркера будет непрерывно в бэкграунде.
Учитывая, что CPU все равно тригонометрию и даже корни рассчитывает численными методами, то оптимальнее данного кода придумать попросту невозможно тут все операции - это +, -, * ...
Кстати, все переменные используются исключительно 16-бит integer
Добавил 12.08.2006:
Если оставить только математику, то получится так:
Код: |
Distance = Получить расстояние между THIS и Target
for (i=0; i < 10; i++) {
Xo, Yo, Zo = Получить предыдущие координаты Target
X, Y, Z = Получить текущие координаты Target
k = (Distance / BulletSpeed) / Delta
X = (X - Xo)*k + X
Y = (Y - Yo)*k + Y
Z = (Z - Zo)*k + Z
Distance = Получить расстояние между THIS и точкой (X,Y,Z)
}
|
где THIS - атакующий корабль, ИИ которго и производит наведение
Target - атакуемая цель
BulletSpeed - модуль абсолютной скорости движения снаряда в пространстве
Delta - интервал времени, прошедший с момента, когда цель была в точке (Xo,Yo,Zo)
После 10 - 15 итераций данного алгоритма точка (X,Y,Z) и будет искомой точкой наведения (а также попадания).
Чем больше интервал Delta замера изменения позиции цели, тем лучше усреднение, но хуже предсказание ее динамичных маневров. Для стрельбы Delta лучше делать 1-2 сек, но если ньютоновская физика - то можно и больше. А можно и вовсе не вычислять вектор скорости цели на основе наблюдения этой цели атакующим, а просто его "подсмотреть" заранее, обратившись к внутренним переменным цели
А еще данный алгоритм можно использовать и для расчета точки перехвата цели (кстати именно для этого я скрипт и писал), все что нужно - это вместо BulletSpeed использовать текущую скорость движения атакующего, и Delta сделать секунд 20.
А в своем скрипте выше я размазывал 9 итераций на 18 секунд, производя лишь 1 итерацию каждые 2 сек и записывал при этом текущие координаты Target в массив (9 строк) так, чтобы при каждой последующей итерации я мог из этого массива получить наиболее старую позицию Target, т.е. спустя 2 итерации это была бы позиция 4 сек давности, а 9 и более итераций - 18 сек давности.
|
|
|
|
|
|
Канал Игры Мечты: «Расчет точки упреждения» |
|
К списку каналов | Наверх страницы |
Цитата не в тему: Если ты не видел кораблей противника, это еще не значит, что их не было.
|
» Расчет точки упреждения | страница 2 |
|