Копия. Оригинал: https://www.liveinternet.ru/users/flogger-k/post432889601/
Итак, задача. Провести перестроение пары ведущий-ведомый в БГЕ из строя "правый пеленг" в "левый пеленг". Задача решалась в БГЕ, объекты имели тип физики "но коллижн", то есть физика отсутствовала. Ведомый при получении команды немного "приотставал", разворачивался по отношению к ведущему под углом, после чего занимал свое место с противоположной стороны и, догнав "командира" уравнивал с ним скорость. Активно использовался метод getVectTo. В итоге, после опробования различных вариантов кода, получилось следующее:import bge
scene = bge.logic.getCurrentScene()
def Wingman():
V_own = 0.0
V_wingman = 0.0
R_own_x = 0.0
R_wingman_x = 0.0
R_own_y = 0.0
R_wingman_y = 0.0
R_own_z = 0.0
R_wingman_z = 0.0
Wingman = scene.objects["MiG21Wingman"]
cont = bge.logic.getCurrentController()
own = cont.owner
if own["prop"] == 0:
V_own = 0.3
V_wingman = 0.3
#Перестройка в пеленг
elif own["prop"] == 1:
V_own = 0.3
V_wingman = 0.3
if own.getVectTo(Wingman)[2][0] > 0:
V_own += 0.05
V_wingman -= 0.05
if abs(Wingman.getVectTo(own)[2][0]) < 0.5 and own.getVectTo(Wingman)[2][0] > 0:
R_wingman_z += 0.01
elif abs(Wingman.getVectTo(own)[2][0]) > 0.5 and own.getVectTo(Wingman)[2][0] < 0:
R_wingman_z -= 0.01
else:
V_own = 0.3
V_wingman = 0.3
if Wingman.getVectTo(own)[2][0] + own.getVectTo(Wingman)[2][0] > 0:
R_wingman_z -= 0.01
else:
R_wingman_z += 0.01
if abs(Wingman.getVectTo(own)[2][0] + own.getVectTo(Wingman)[2][0]) > 0.01:
V_own -= 0.05
V_wingman += 0.05
else:
if Wingman.worldOrientation[2] != own.worldOrientation[2]:
V_own = 0.3
V_wingman = 0.3
Wingman.worldOrientation[2] = own.worldOrientation[2]
else:
if own.getDistanceTo(Wingman) > V_own*60:
V_own = 0.3
V_wingman += 0.1
else:
own["prop"] == 0
V_own = 0.3
V_wingman = 0.3
elif own["prop"] == 2:
V_own = 0.3
V_wingman = 0.3
if own.getVectTo(Wingman)[2][0] < 0:
V_own += 0.05
V_wingman -= 0.05
if abs(Wingman.getVectTo(own)[2][0] > 0.5) and own.getVectTo(Wingman)[2][0] > 0:
R_wingman_z += 0.01
elif abs(Wingman.getVectTo(own)[2][0] < 0.5) and own.getVectTo(Wingman)[2][0] < 0:
R_wingman_z -= 0.01
else:
V_own = 0.3
V_wingman = 0.3
if Wingman.getVectTo(own)[2][0] + own.getVectTo(Wingman)[2][0] < 0:
R_wingman_z += 0.01
else:
R_wingman_z -= 0.01
if abs(Wingman.getVectTo(own)[2][0] + own.getVectTo(Wingman)[2][0]) > 0.01:
V_own -= 0.05
V_wingman += 0.05
else:
if Wingman.worldOrientation[2] != own.worldOrientation[2]:
V_own = 0.3
V_wingman = 0.3
Wingman.worldOrientation[2] = own.worldOrientation[2]
else:
if own.getDistanceTo(Wingman) > V_own*60:
V_own = 0.3
V_wingman += 0.1
else:
own["prop"] == 0
V_own = 0.3
V_wingman = 0.3
own.applyMovement([0.0, V_own, 0.0], True)
Wingman.applyMovement([0.0, V_wingman, 0.0], True)
own.applyRotation([R_own_x, R_own_y, R_own_z], True)
Wingman.applyRotation([R_wingman_x, R_wingman_y, R_wingman_z], True)
Параллельно с написанием пробного скрипта перестроения пары самолетов пришлось составлять таблийу для значений векторов метода getVectTo[2] . Если попытаться представить это в трехмерном пространстве, то получается куб, в центра которого находится ведущий, а в углах, центрах граней и ребер - ведомый. Условно говоря, конечно. То есть ведомый может идти параллельно ведущему рядом с ним. Или с отставанием справа и сверху или с опережением слева по центру и так далее. В итоге табличку я сюда солью, может потом пригодиться (хотя бы и самому себе).
НА ОДНОМ УРОВНЕ
Спереди по центру [0.0, 1.0, 0.0]
Сзади по центру [0.0, -1.0, 0.0]
Слева спереди [-0.7071, 0.7071, 0.0]
Справа спереди [0.7071, 0.7071, 0.0]
Слева сзади [-0.7071, -0.7071, 0.0]
Справа сзади [0.7071, -0.7071, 0.0]
Справа по центру [1.0, 0.0, 0.0]
Слева по центру [-1.0, 0.0, 0.0]
ВЫШЕ
Выше по центру [0.0, 0.0, 1.0]
Спереди по центру [0.0, 0.7071, 0.7071]
Сзади по центру [0.0, -0.7071, 0.7071]
Слева спереди [-0.5774, 0.5774, 0.5774]
Справа спереди [0.5774, 0.5774, 0.5774]
Слева сзади [-0.5774, -0.5774, 0.5774]
Справа сзади [0.5774, -0.5774, 0.5774]
Справа по центру [0.7071, 0.0, 0.7071]
Слева по центру [-0.7071, 0.0, 0.7071]
НИЖЕ
Ниже по центру [0.0, 0.0, -1.0]
Спереди по центру [0.0, 0.7071, -0.7071]
Сзади по центру [0.0, -0.7071, -0.7071]
Слева спереди [-0.5774, 0.5774, -0.5774]
Справа спереди [0.5774, 0.5774, -0.5774]
Слева сзади [-0.5774, -0.5774, -0.5774]
Справа сзади [0.5774, -0.5774, -0.5774]
Справа по центру [0.7071, 0.0, -0.7071]
Слева по центру [-0.7071, 0.0, -0.7071]
Потом, когда все это было закончено, я попробовал сделать немного по-другому. А именно - сделать так, чтобы ведущий постоянно вычислял координаты ведомого относительно себя, любимого, чтобы подчиненный просто занимал эту область, не заморачиваясь с векторами. Тем более, что гораздо раньше у меня уже был отработан метод наведения ботов на цель с помощью крена, тангажа или рыска по отдельности или сразу всего одновременно. Никаких проблем с наведением ведомого на эту самую искомую точку быть не должно. Однако вот тут я застрял. Как поется в одной старой песне из кинофильма: "Уж я к ней и так и этак, со словами и без слов. Обломал немало веток, наломал немало дров". В итоге все же удалось решить проблему со строем "фронт" - когда ведомый и ведущий выстроены в одну линию параллельно друг другу и строем "колонна", когда ведомый держится строго позади ведущего. А вот со строем "пеленг" пока облом. Там нужно реализовать отставание ведомого от ведущего, либо его опережение. Ну, хоть что-то получилось, а с пеленгом я все равно как-нибудь разберусь. Код написан уже для объектов с физикой типа Dynamics.
port bge
import math
scene = bge.logic.getCurrentScene()
def Wingman():
cont = bge.logic.getCurrentController()
own = cont.owner
#Задание объекта-цели
target = scene.objects["wingman"]
target.worldOrientation = own.worldOrientation
#target.worldPosition = front(own, target)
target.worldPosition = peleng(own, target)
#target.worldPosition =colonna(own, target)
def colonna(own, target):
targetX = own.worldPosition[0] - 3*own.worldLinearVelocity[0]
targetY = own.worldPosition[1] - 3*own.worldLinearVelocity[1]
targetZ = own.worldPosition[2] - 3*own.worldLinearVelocity[2]
listCoord = [targetX, targetY, targetZ]
return listCoord
def front(own, target):
LeftRightX = 0
LeftRightY = 0
kY = own.worldLinearVelocity[0]/own.localLinearVelocity[1]
kX = own.worldLinearVelocity[1]/own.localLinearVelocity[1]
kZ = own.worldLinearVelocity[2]/own.localLinearVelocity[1]
PRAVOLEVO = 1
if kX > 0 and kY > 0:
LeftRightX = 1
LeftRightY = -1
elif kX < 0 and kY > 0:
LeftRightX = 1
LeftRightY = -1
elif kX > 0 and kY < 0:
LeftRightX = 1
LeftRightY = -1
elif kX < 0 and kY < 0:
LeftRightX = 1
LeftRightY = -1
ownX = own.worldPosition[0]
ownY = own.worldPosition[1]
ownZ = own.worldPosition[2]
DIST = 20.0
targetX = ownX + DIST*kX*LeftRightX*PRAVOLEVO
targetY = ownY + DIST*kY*LeftRightY*PRAVOLEVO
targetZ = ownZ + DIST*kZ
listCoord = [targetX, targetY, targetZ]
return listCoord
В функциях colonna и front идет как раз вычисление и выдача искомых координат ведомого. Комментариев в коде почти нет, потому как работа над этим делом еще не закончена. Получится ли из этого что-нибудь, пока неясно. Во всяком случае, в основном коде проекта включить их можно хоть сейчас, но хотелось бы добить строй "пеленг"...