пятница, 12 января 2018 г.

Не прошло и года, как я написал следующий пост.

    Ситуация такая получилась - комп у меня стационарный, а я сам почти всё прошедшее время в прямом смысле слова дома не был, вот на Новый год только домой приехал. А в телефоне я запустить Блендер не могу. Чистый же Питон сам по себе как-то не интересен, короче не получилось и не знаю как оно дальше будет продолжаться, вполне может статься, что опять год меня не будет. Хотелось бы летом дома побыть, но не уверен, что получится. Посмотрим.



    Но к делу, поскольку я понятия не имею, через какое время покину в очередной раз родную хату, то хоть сколько-нибудь сложный проект мне нет и смысла начинать, как обычно, впрочем. Да и пальцы от клавиатуры уже отвыкли. Поэтому мелочевка. Приспичило мне сделать более реалистичное поведение ракеты, которые в реальности не летают строго в точку упреждения, всегда есть "колебания вместе с линией партии", да и нет точки упреждения в методе пропорционального сближения. Например тут хорошо видно, что после переключения на собственную ГСН ракеты немножко "болтаются":


 Это происходит уже на нисходящей ветви траектории, почти в самом конце. Метод наведения дает ошибку даже в случае не маневрирующей цели, да и на ракету всякие силы действуют. Ракета может банально слишком сильно повернуть, в конце концов. Однако надо хоть немного рассказать о выбранном мной методе наведения и как вообще ракеты наводятся. Сразу оговорюсь, что речь идет о ракетах с полуактивными головками самонаведения (ГСН), с командным наведением и с активными ГСН это несколько другая епархия. Поясняю, командные потому так и называются, что носитель этих ракет определяет положение в пространстве ракеты и цели и отправляет ракете команды, куда рулить. Дешево и сердито, и можно использовать мощный и дорогой радар, да не один, но на больших расстояниях неточно. Также этот способ часто используется для вывода ракеты в район цели, пока ГСН не захватит цель и/или в ожидании освобождения канала подсвета цели. Подсвет цели применяется в полуактивных ГСН, лазерных или радиолокационных, станция наведения облучает цель, на ракете стоит датчик, который детектирует источник отраженного излучения и угол направления на него. В принципе, автопилот ракеты может удерживать ракету направленной строго на цель, и ракета даже попадет, но дело в том что такая траектория будет очень неэффективной, кстати этот метод так и называется - метод прямого наведения. Надо каким-то образом высчитывать точку упреждения, и самый простой способ - измерить угловую скорость объекта и доворачивать ракетой на значение этого угла умноженное на коэффициент пропорциональности. Это так называемый пропорциональный метод наведения, который я и попытался повторить, более и менее. Активные же ГСН систему подсвета цели несут с собой, так что их действительно "пустил-забыл".
    Объясняю как реализовал.
    Сперва- наперво получил глобальный вектор направления ракета цель и сравнил со хранящимся в проперти ракеты старым значением. Как сравнил - получил углы между старыми и новыми проекциями на две плоскости 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)


Управление - нажать и держать пробел, ракеты полетят на цель. Одна ракета (зеленая) реализует метод прямого наведения, вторая - пропорционального. Можно видеть как отличаются траектории. Есть еще одна сцена, посмотреть на вектора, там управление стрелочками, но и коэффициент пропорциональности зверски большой.