Ситуация такая получилась - комп у меня стационарный, а я сам почти всё прошедшее время в прямом смысле слова дома не был, вот на Новый год только домой приехал. А в телефоне я запустить Блендер не могу. Чистый же Питон сам по себе как-то не интересен, короче не получилось и не знаю как оно дальше будет продолжаться, вполне может статься, что опять год меня не будет. Хотелось бы летом дома побыть, но не уверен, что получится. Посмотрим.
Но к делу, поскольку я понятия не имею, через какое время покину в очередной раз родную хату, то хоть сколько-нибудь сложный проект мне нет и смысла начинать, как обычно, впрочем. Да и пальцы от клавиатуры уже отвыкли. Поэтому мелочевка. Приспичило мне сделать более реалистичное поведение ракеты, которые в реальности не летают строго в точку упреждения, всегда есть "колебания вместе с линией партии", да и нет точки упреждения в методе пропорционального сближения. Например тут хорошо видно, что после переключения на собственную ГСН ракеты немножко "болтаются":
Это происходит уже на нисходящей ветви траектории, почти в самом конце. Метод наведения дает ошибку даже в случае не маневрирующей цели, да и на ракету всякие силы действуют. Ракета может банально слишком сильно повернуть, в конце концов. Однако надо хоть немного рассказать о выбранном мной методе наведения и как вообще ракеты наводятся. Сразу оговорюсь, что речь идет о ракетах с полуактивными головками самонаведения (ГСН), с командным наведением и с активными ГСН это несколько другая епархия. Поясняю, командные потому так и называются, что носитель этих ракет определяет положение в пространстве ракеты и цели и отправляет ракете команды, куда рулить. Дешево и сердито, и можно использовать мощный и дорогой радар, да не один, но на больших расстояниях неточно. Также этот способ часто используется для вывода ракеты в район цели, пока ГСН не захватит цель и/или в ожидании освобождения канала подсвета цели. Подсвет цели применяется в полуактивных ГСН, лазерных или радиолокационных, станция наведения облучает цель, на ракете стоит датчик, который детектирует источник отраженного излучения и угол направления на него. В принципе, автопилот ракеты может удерживать ракету направленной строго на цель, и ракета даже попадет, но дело в том что такая траектория будет очень неэффективной, кстати этот метод так и называется - метод прямого наведения. Надо каким-то образом высчитывать точку упреждения, и самый простой способ - измерить угловую скорость объекта и доворачивать ракетой на значение этого угла умноженное на коэффициент пропорциональности. Это так называемый пропорциональный метод наведения, который я и попытался повторить, более и менее. Активные же ГСН систему подсвета цели несут с собой, так что их действительно "пустил-забыл".
Объясняю как реализовал.
Сперва- наперво получил глобальный вектор направления ракета цель и сравнил со хранящимся в проперти ракеты старым значением. Как сравнил - получил углы между старыми и новыми проекциями на две плоскости X-Y и Y-Z, углы умножил на значения коэффициента пропорциональности. Построил по углам матрицы поворота. Затем повернул по этим матрицам вектор ракета-цель и выравнял ракету по этому повернутому вектору. Всё.
Собственно программная реализация:
import bge
import mathutils
import random
cont = bge.logic.getCurrentController()
# ракета
own = cont.owner
scene = bge.logic.getCurrentScene()
# цель
target = scene.objects['Target']
always = cont.sensors['Always']
if always.positive:
# извлекаем среди прочего глобальный вектор ракета-цель
dist, glbVect, locVect = own.getVectTo(target)
# в первый раз проперти нет, проверяем
if own.get('oldVect', None) != None:
oldVect = own['oldVect']
# проекция вектора ракета-цель на плоскость Y-Z в данный момент
currVectX = mathutils.Vector((glbVect[1], glbVect[2]))
# проекция вектора ракета-цель на плоскость Y-Z в прошлый вызов скрипта
oldVectX = mathutils.Vector((oldVect[1], oldVect[2]))
currVectX.normalize()
oldVectX.normalize()
# угол между векторами - проекциями
angleX = currVectX.angle_signed(oldVectX) * -1
# рандомный коэффициент упреждения
rX = random.randint(5, 10)
# умножаем угол вращения вектора ракета-цель на коэффициент упреждения
# плюс ограничиваем черезмерный поворот ракеты
if abs(angleX) * rX < 1.3:
angleX = angleX * rX
else:
angleX = 0.0
# создаем матрицу поворота в плоскости Y-Z
mat_rotX = mathutils.Matrix.Rotation(angleX, 4, 'X')
mat_rotX = mat_rotX.to_3x3()
# Аналогично для проекций на плоскость X-Y
currVectZ = mathutils.Vector((glbVect[0], glbVect[1]))
oldVectZ = mathutils.Vector((oldVect[0], oldVect[1]))
currVectZ.normalize()
oldVectZ.normalize()
angleZ = currVectZ.angle_signed(oldVectZ) * -1
rZ = random.randint(5, 10)
if abs(angleZ) * rZ < 1.3:
angleZ = angleZ * rZ
else:
angleZ = 0.0
mat_rotZ = mathutils.Matrix.Rotation(angleZ, 4, 'Z')
mat_rotZ = mat_rotZ.to_3x3()
# поворачиваем вектор ракета-цель на полученные матрицы и получаем
# вектор упреждения
V = glbVect * mat_rotX * mat_rotZ
V.normalize()
# выравниваем ракету по вектору упреждения ( не резко)
own.alignAxisToVect(V, 1, 0.8)
# сохраняем нынешнее значение вектора ракета-цель на потом
own['oldVect'] = glbVect
Ссылка:
proportional_aiming.blend.7z (120 kB)
Управление - нажать и держать пробел, ракеты полетят на цель. Одна ракета (зеленая) реализует метод прямого наведения, вторая - пропорционального. Можно видеть как отличаются траектории. Есть еще одна сцена, посмотреть на вектора, там управление стрелочками, но и коэффициент пропорциональности зверски большой.
Но к делу, поскольку я понятия не имею, через какое время покину в очередной раз родную хату, то хоть сколько-нибудь сложный проект мне нет и смысла начинать, как обычно, впрочем. Да и пальцы от клавиатуры уже отвыкли. Поэтому мелочевка. Приспичило мне сделать более реалистичное поведение ракеты, которые в реальности не летают строго в точку упреждения, всегда есть "колебания вместе с линией партии", да и нет точки упреждения в методе пропорционального сближения. Например тут хорошо видно, что после переключения на собственную ГСН ракеты немножко "болтаются":
Это происходит уже на нисходящей ветви траектории, почти в самом конце. Метод наведения дает ошибку даже в случае не маневрирующей цели, да и на ракету всякие силы действуют. Ракета может банально слишком сильно повернуть, в конце концов. Однако надо хоть немного рассказать о выбранном мной методе наведения и как вообще ракеты наводятся. Сразу оговорюсь, что речь идет о ракетах с полуактивными головками самонаведения (ГСН), с командным наведением и с активными ГСН это несколько другая епархия. Поясняю, командные потому так и называются, что носитель этих ракет определяет положение в пространстве ракеты и цели и отправляет ракете команды, куда рулить. Дешево и сердито, и можно использовать мощный и дорогой радар, да не один, но на больших расстояниях неточно. Также этот способ часто используется для вывода ракеты в район цели, пока ГСН не захватит цель и/или в ожидании освобождения канала подсвета цели. Подсвет цели применяется в полуактивных ГСН, лазерных или радиолокационных, станция наведения облучает цель, на ракете стоит датчик, который детектирует источник отраженного излучения и угол направления на него. В принципе, автопилот ракеты может удерживать ракету направленной строго на цель, и ракета даже попадет, но дело в том что такая траектория будет очень неэффективной, кстати этот метод так и называется - метод прямого наведения. Надо каким-то образом высчитывать точку упреждения, и самый простой способ - измерить угловую скорость объекта и доворачивать ракетой на значение этого угла умноженное на коэффициент пропорциональности. Это так называемый пропорциональный метод наведения, который я и попытался повторить, более и менее. Активные же ГСН систему подсвета цели несут с собой, так что их действительно "пустил-забыл".
Объясняю как реализовал.
Сперва- наперво получил глобальный вектор направления ракета цель и сравнил со хранящимся в проперти ракеты старым значением. Как сравнил - получил углы между старыми и новыми проекциями на две плоскости X-Y и Y-Z, углы умножил на значения коэффициента пропорциональности. Построил по углам матрицы поворота. Затем повернул по этим матрицам вектор ракета-цель и выравнял ракету по этому повернутому вектору. Всё.
Собственно программная реализация:
import bge
import mathutils
import random
cont = bge.logic.getCurrentController()
# ракета
own = cont.owner
scene = bge.logic.getCurrentScene()
# цель
target = scene.objects['Target']
always = cont.sensors['Always']
if always.positive:
# извлекаем среди прочего глобальный вектор ракета-цель
dist, glbVect, locVect = own.getVectTo(target)
# в первый раз проперти нет, проверяем
if own.get('oldVect', None) != None:
oldVect = own['oldVect']
# проекция вектора ракета-цель на плоскость Y-Z в данный момент
currVectX = mathutils.Vector((glbVect[1], glbVect[2]))
# проекция вектора ракета-цель на плоскость Y-Z в прошлый вызов скрипта
oldVectX = mathutils.Vector((oldVect[1], oldVect[2]))
currVectX.normalize()
oldVectX.normalize()
# угол между векторами - проекциями
angleX = currVectX.angle_signed(oldVectX) * -1
# рандомный коэффициент упреждения
rX = random.randint(5, 10)
# умножаем угол вращения вектора ракета-цель на коэффициент упреждения
# плюс ограничиваем черезмерный поворот ракеты
if abs(angleX) * rX < 1.3:
angleX = angleX * rX
else:
angleX = 0.0
# создаем матрицу поворота в плоскости Y-Z
mat_rotX = mathutils.Matrix.Rotation(angleX, 4, 'X')
mat_rotX = mat_rotX.to_3x3()
# Аналогично для проекций на плоскость X-Y
currVectZ = mathutils.Vector((glbVect[0], glbVect[1]))
oldVectZ = mathutils.Vector((oldVect[0], oldVect[1]))
currVectZ.normalize()
oldVectZ.normalize()
angleZ = currVectZ.angle_signed(oldVectZ) * -1
rZ = random.randint(5, 10)
if abs(angleZ) * rZ < 1.3:
angleZ = angleZ * rZ
else:
angleZ = 0.0
mat_rotZ = mathutils.Matrix.Rotation(angleZ, 4, 'Z')
mat_rotZ = mat_rotZ.to_3x3()
# поворачиваем вектор ракета-цель на полученные матрицы и получаем
# вектор упреждения
V = glbVect * mat_rotX * mat_rotZ
V.normalize()
# выравниваем ракету по вектору упреждения ( не резко)
own.alignAxisToVect(V, 1, 0.8)
# сохраняем нынешнее значение вектора ракета-цель на потом
own['oldVect'] = glbVect
Ссылка:
proportional_aiming.blend.7z (120 kB)
Управление - нажать и держать пробел, ракеты полетят на цель. Одна ракета (зеленая) реализует метод прямого наведения, вторая - пропорционального. Можно видеть как отличаются траектории. Есть еще одна сцена, посмотреть на вектора, там управление стрелочками, но и коэффициент пропорциональности зверски большой.
Комментариев нет:
Отправить комментарий