В двух предыдущих постах я писал про взаимодействие снарядов и юнитов. Точнее, воздействие поражающих факторов на сами юниты. Было это все чисто умозрительно и пока не было воплощено на практике, так и оставалось у меня в голове.
Скрипт работы снаряда, точнее, его БЧ (боевой части) был собран не сразу. Точнее, не скрипт, а функция в скрипте CONTROL_Weapon. А когда она была написана, то пришлось поломать голову, почему оно не работает (ну как всегда - там опечатка, там не то имя указал). А главной причиной была нихкая точность - снаряды рвались уж очень далеко от зенитки. Я использовал миссию теста МиГ-23БН для проверки работы НАР С-8 по зенитке GDF-001 Oerlicon. Выяснилось, что прицельная сетка на самолете не соответствует дальности полета НАР. Пришлось лезть в файл кабины и корректировать ее положение. Теперь, видимо, ту же процедуру надо провести и в остальных машинах. Ничего не поделаешь - до НАР и пушек я просто до сих пор еще не добирался - руки просто не доходили.
Но в конце концов скрипт заработал полностью в том виде, какой он сейчас есть. Необходимо дописать проверку лучом от эпицентра взрыва до юнита на наличие препятствия (укрытия) на пути ударной волны и осколков. Приведу текст функции для БЧ типа "осколочно-фугасная":
def OskolFugas(own):
for units in ArbitrGame.UNITS[1]:
#Проверяем наличие атрибута повреждений у объекта - ударной волне и осколкам все равно, что разрушать
if hasattr(units, "crash") == True:
#В зависимости от расстояния подрыва рассчитывается величина поражающего фактора
if own.radiusExplode*1.5 < own.getDistanceTo(units) < own.radiusExplode*3:
own.LEVELS_CRASH = 0.4*own.levelsCrash*own.radiusExplode/own.getDistanceTo(units)
elif own.radiusExplode < own.getDistanceTo(units) < own.radiusExplode*1.5:
own.LEVELS_CRASH = 0.8*own.levelsCrash*own.radiusExplode/own.getDistanceTo(units)
elif own.getDistanceTo(units) < own.radiusExplode:
own.LEVELS_CRASH = own.levelsCrash
#Вычисление нанесенного урона
if own.LEVELS_CRASH > units.levelDefens:
#При условии, что защита "пробита", смотрим на уровень повреждений юнита и вносим коррективы
if own.LEVELS_CRASH/units.levelDefens < units.crash:
units.crash -= own.LEVELS_CRASH/units.levelDefens
else:
units.crash = 0.0
print(units, units.crash, own.getDistanceTo(units), own.LEVELS_CRASH)
Последнюю строчку можног не принимать во внимание, я ее потом закомментирую или вообще уберу. В ней я отсматривал работу функции. В принципе, все остальные функции типа "проникающе-фугасной", "Фугасной" и прочей БЧ будут работать так же. Разница будет заключаться лишь в градации расстояния для ослабления действия снаряда.
А вот ненаписанные пока функции для кумулятивных БЧ и бронебойно-подкалиберных снарядов будут вести себя по-другому. Там не нужен цикл перебора юнитов сцены - цель одна-единственная и вступают в действие такие факторы, как толщина брони, угол встречи с броней, наличие динамической защиты и ее тип... То же самое, кстиати, относится к пулям стрелкового оружия - они действуют примерно по тому же принципу - скорость, калибр, плюс дальность выстрела. Мда, придется еще как-то по бронепробиваемости в зависимости от дальности , с которой был сделан выстрел, что-то придумывать...
И в конце об артиллерии. Здесь я приведу скрипт работы артиллерийского орудия. На данный момент на нем работает "Эрликон", но там еще надо смотреть по его точности - в скрипт введен разброс снарядов и ошибки прицеливания. Весьма вероятно, что с этим я переборщил...
import bge
import json
import sys
import random
cont = bge.logic.getCurrentController()
own = cont.owner
scene = bge.logic.getCurrentScene()
ArbitrGame = scene.objects["ArbitrGame"]
#Импортируем модуль юнита
#unit_module = __import__(own.unitModule)
t = 0.0
xS = 0.0
yS = 0.0
zS = 0.0
S = 0.0
newPos = [xS, yS, zS]
import CONTROL_Operations
import CONTROL_Sensor
import mathutils
scene = bge.logic.getCurrentScene()
def UnitArtillery():
cont = bge.logic.getCurrentController()
own = cont.owner
################################################################
#Просчет уровней детализации
if own.maxVisibleDist < own.getDistanceTo(scene.active_camera):
own.levelsDetails = 2
elif own.maxVisibleDist/10 < own.getDistanceTo(scene.active_camera) < own.maxVisibleDist:
own.levelsDetails = 1
elif own.maxVisibleDist/10 > own.getDistanceTo(scene.active_camera):
own.levelsDetails = 0
#print(own.getDistanceTo(scene.active_camera))
#Работа с детализацией
if own.Temp_levelsDetails != own.levelsDetails:
CONTROL_Operations.levelsDetailArtillery(own)
own.Temp_levelsDetails = own.levelsDetails
if own.crash > 0.1:
if own.typeMissions != "":
if own.statusBattery == "Commander":
own.timerTargetChanged += 1
if own.timerTargetChanged == 600:
targetChangedOwn(own)
own.timerTargetChanged = 0
if own.targetID != "":
Ballistica(own)
#Блокировка возможности стрельбы при отсутствии бокомплекта
if own.BK == 0:
own.shoot = 0
own.targetID = ""
own.PR = 0
#Разрешение на открытие огня
if own.PR == 1:
own.shoot = 1
else:
own.shoot = 0
#Стрельба
if own.shoot == 1:
shooting(own)
#Остановка стрельбы
if own.Temp_shoot != own.shoot:
if own.Temp_shoot == 1:
own.Temp_shoot = own.shoot
#Функция выбора ближайшей цели. Используется для зениток и стрельбы прямой наводкой
#по конкретной цели, для стрельбы с закрытых позиций по площадям и квадратам
#используются координаты
def targetChangedOwn(own):
if own.typeMissions == "AntiAircraft":
own.targetType = 0
sceneObjList = ArbitrGame.UNITS[0][own.targetType][own.target]
tempSortedList = []
if len(sceneObjList) > 0:
tempsortedList = sorted(sceneObjList, key = lambda obj:own.getDistanceTo(obj))
#print(tempsortedList)
own.targetID = str(id(tempsortedList[0]))
else:
own.PR = 0
own.targetID = ""
#Расчет точки упреждения
def Ballistica(own):
try:
target = scene.objects.from_id(int(own.targetID))
#Тип прицеливания - отслеживание самой цели
if own.typeCoordTarget == "AimingTarget":
newPos = target.worldPosition
#Тип прицеливание с упреждением
if own.typeCoordTarget == "VisibleTarget":
# Рассчитываем время полета снаряда.
t = own.getDistanceTo(target) / own.speedBullet
# Рассчитываем путь перемещения объекта за это время.
S = target.worldLinearVelocity * t
xS = target.worldPosition[0] + S[0] + random.randrange(-own.razbros,own.razbros)
yS = target.worldPosition[1] + S[1] + random.randrange(-own.razbros,own.razbros)
zS = target.worldPosition[2] + S[2] + abs((-10*t*t)/2) + random.randrange(-own.razbros,own.razbros)
newPos = [xS, yS, zS]
#print(target)
Turret(own, newPos)
except:
own.PR = 0
own.targetID != ""
#Управление наведением в горизонтальной плоскости
def Turret(own, newPos):
#print(own.PR)
Turret = own.childrenRecursive[own.unitName + "Turret_"]
#Данные по ориентации
orientY = Turret.getVectTo(newPos)[2][1]
orientX = Turret.getVectTo(newPos)[2][0]
#Скорость наведения
kZ = own.speedMaxGor
correct = 1.0
znak = 0
if orientX > 0:
znak = -1
elif orientX < 0:
znak = 1
if orientY > 0.9:
correct = 1 - orientY
else:
correct = 1.0
Turret.applyRotation([0.0,0.0,kZ*correct*znak], True)
Canon = own.childrenRecursive[own.unitName + "Canon_"]
orientZ = Canon.getVectTo(newPos)[2][2]
kX = own.speedMaxVert
correctCanon = 1.0
znakCanon = 0
if orientY > 0.7:
if orientZ > 0:
znakCanon = 1
elif orientZ < 0:
znakCanon = -1
if abs(orientZ) < 0.2:
correctCanon = abs(orientZ)
else:
correctCanon = 1.0
Canon.applyRotation([kX*correctCanon*znakCanon,0.0,0.0], True)
if abs(orientZ) < 0.1 and orientY > 0.9 and own.getDistanceTo(newPos) < own.distMax:
#print(own.getDistanceTo(newPos))
if own.Temp_cassetteBK < own.cassetteBK:
own.PR = 1
else:
own.PR = 0
else:
own.PR = 0
#Перезарядка - магазин, кассета, обойма или снаряд
if own.Temp_cassetteBK == own.cassetteBK:
own.PR = 0
if own.Temp_cassetteBK > 0:
if own.Temp_timerCassetteChanged < own.timerCassetteChanged:
own.Temp_timerCassetteChanged += 1
elif own.Temp_timerCassetteChanged == own.timerCassetteChanged:
own.Temp_timerCassetteChanged = 0
own.Temp_cassetteBK = 0
def shooting(own):
#Стрельба из пушек, пулеметов и многоствольных систем
if own.typeShoot == "Zalp":
for FLAME in own.fireGun:
addBullet(own, FLAME)
#Стрельба из РСЗО, РБУ и прочих реактивных(ракетных) систем
elif own.typeShoot == "Paket":
FLAME = own.fireGun[own.BK-1]
addBullet(own, FLAME)
own.BK -= 1
own.Temp_cassetteBK += 1
#Функция добавления снаряда и прочего - звука, вспышки...
def addBullet(own, FLAME):
Canon = own.childrenRecursive[own.unitName + "Canon_"]
#Вспышка - лампа
vspyshka = scene.addObject('LampUniversal', Canon, own.gunPausa+1)
vspyshka.setParent(Canon, False, False)
vspyshka.localPosition = FLAME
#Вспышка - меш
vspyshkaMesh = scene.addObject('AudioGun', Canon, own.gunPausa+5)
vspyshkaMesh.setParent(Canon, False, False)
vspyshkaMesh["audioProp"] = own.audioGun
vspyshkaMesh.replaceMesh("FireUniversal", True, False)
vspyshkaMesh.localPosition = FLAME
razmer = own.scaleGun
vspyshkaMesh.worldScale = [razmer, razmer, razmer]
vspyshkaMesh.visible = 1
#Снаряд цепляется к самому юниту и происходит мутация
#Проверяется наличие атрибута вроде калибрСнаряд = 23мм
#и объект мутирует в своем классе
dynObj = scene.addObject('UniversalBullet',vspyshka , 300)
dynObj.worldScale = [1.0,1.0,1.0]
if "calibr" not in dynObj:
dynObj["calibr"] = own.gunBullet
dynObj.localLinearVelocity = [random.randrange(-own.randomSpeed,own.randomSpeed),
random.randrange(-own.randomSpeed,own.randomSpeed)+own.speedBullet,
random.randrange(-own.randomSpeed,own.randomSpeed)]
Пост, конечно, длинноватый получился, да и сами скрипты сыроваты, хотя и работают. Но как "история развития", может, кому-то и будет интересно. А то и полезно. В завершение приведу скрин работы "Эрликона". Пушка смотрит в сторну цели , вот только пока она еще безобидна. Надеюсь, ненадолго. Освещение, конечно еще то... Все никак не начну ковыряться в скриптах упитиса, чтобы понять, как писать шейдер... Ну, не все ж сразу...
Скрипт работы снаряда, точнее, его БЧ (боевой части) был собран не сразу. Точнее, не скрипт, а функция в скрипте CONTROL_Weapon. А когда она была написана, то пришлось поломать голову, почему оно не работает (ну как всегда - там опечатка, там не то имя указал). А главной причиной была нихкая точность - снаряды рвались уж очень далеко от зенитки. Я использовал миссию теста МиГ-23БН для проверки работы НАР С-8 по зенитке GDF-001 Oerlicon. Выяснилось, что прицельная сетка на самолете не соответствует дальности полета НАР. Пришлось лезть в файл кабины и корректировать ее положение. Теперь, видимо, ту же процедуру надо провести и в остальных машинах. Ничего не поделаешь - до НАР и пушек я просто до сих пор еще не добирался - руки просто не доходили.
Но в конце концов скрипт заработал полностью в том виде, какой он сейчас есть. Необходимо дописать проверку лучом от эпицентра взрыва до юнита на наличие препятствия (укрытия) на пути ударной волны и осколков. Приведу текст функции для БЧ типа "осколочно-фугасная":
def OskolFugas(own):
for units in ArbitrGame.UNITS[1]:
#Проверяем наличие атрибута повреждений у объекта - ударной волне и осколкам все равно, что разрушать
if hasattr(units, "crash") == True:
#В зависимости от расстояния подрыва рассчитывается величина поражающего фактора
if own.radiusExplode*1.5 < own.getDistanceTo(units) < own.radiusExplode*3:
own.LEVELS_CRASH = 0.4*own.levelsCrash*own.radiusExplode/own.getDistanceTo(units)
elif own.radiusExplode < own.getDistanceTo(units) < own.radiusExplode*1.5:
own.LEVELS_CRASH = 0.8*own.levelsCrash*own.radiusExplode/own.getDistanceTo(units)
elif own.getDistanceTo(units) < own.radiusExplode:
own.LEVELS_CRASH = own.levelsCrash
#Вычисление нанесенного урона
if own.LEVELS_CRASH > units.levelDefens:
#При условии, что защита "пробита", смотрим на уровень повреждений юнита и вносим коррективы
if own.LEVELS_CRASH/units.levelDefens < units.crash:
units.crash -= own.LEVELS_CRASH/units.levelDefens
else:
units.crash = 0.0
print(units, units.crash, own.getDistanceTo(units), own.LEVELS_CRASH)
Последнюю строчку можног не принимать во внимание, я ее потом закомментирую или вообще уберу. В ней я отсматривал работу функции. В принципе, все остальные функции типа "проникающе-фугасной", "Фугасной" и прочей БЧ будут работать так же. Разница будет заключаться лишь в градации расстояния для ослабления действия снаряда.
А вот ненаписанные пока функции для кумулятивных БЧ и бронебойно-подкалиберных снарядов будут вести себя по-другому. Там не нужен цикл перебора юнитов сцены - цель одна-единственная и вступают в действие такие факторы, как толщина брони, угол встречи с броней, наличие динамической защиты и ее тип... То же самое, кстиати, относится к пулям стрелкового оружия - они действуют примерно по тому же принципу - скорость, калибр, плюс дальность выстрела. Мда, придется еще как-то по бронепробиваемости в зависимости от дальности , с которой был сделан выстрел, что-то придумывать...
И в конце об артиллерии. Здесь я приведу скрипт работы артиллерийского орудия. На данный момент на нем работает "Эрликон", но там еще надо смотреть по его точности - в скрипт введен разброс снарядов и ошибки прицеливания. Весьма вероятно, что с этим я переборщил...
import bge
import json
import sys
import random
cont = bge.logic.getCurrentController()
own = cont.owner
scene = bge.logic.getCurrentScene()
ArbitrGame = scene.objects["ArbitrGame"]
#Импортируем модуль юнита
#unit_module = __import__(own.unitModule)
t = 0.0
xS = 0.0
yS = 0.0
zS = 0.0
S = 0.0
newPos = [xS, yS, zS]
import CONTROL_Operations
import CONTROL_Sensor
import mathutils
scene = bge.logic.getCurrentScene()
def UnitArtillery():
cont = bge.logic.getCurrentController()
own = cont.owner
################################################################
#Просчет уровней детализации
if own.maxVisibleDist < own.getDistanceTo(scene.active_camera):
own.levelsDetails = 2
elif own.maxVisibleDist/10 < own.getDistanceTo(scene.active_camera) < own.maxVisibleDist:
own.levelsDetails = 1
elif own.maxVisibleDist/10 > own.getDistanceTo(scene.active_camera):
own.levelsDetails = 0
#print(own.getDistanceTo(scene.active_camera))
#Работа с детализацией
if own.Temp_levelsDetails != own.levelsDetails:
CONTROL_Operations.levelsDetailArtillery(own)
own.Temp_levelsDetails = own.levelsDetails
if own.crash > 0.1:
if own.typeMissions != "":
if own.statusBattery == "Commander":
own.timerTargetChanged += 1
if own.timerTargetChanged == 600:
targetChangedOwn(own)
own.timerTargetChanged = 0
if own.targetID != "":
Ballistica(own)
#Блокировка возможности стрельбы при отсутствии бокомплекта
if own.BK == 0:
own.shoot = 0
own.targetID = ""
own.PR = 0
#Разрешение на открытие огня
if own.PR == 1:
own.shoot = 1
else:
own.shoot = 0
#Стрельба
if own.shoot == 1:
shooting(own)
#Остановка стрельбы
if own.Temp_shoot != own.shoot:
if own.Temp_shoot == 1:
own.Temp_shoot = own.shoot
#Функция выбора ближайшей цели. Используется для зениток и стрельбы прямой наводкой
#по конкретной цели, для стрельбы с закрытых позиций по площадям и квадратам
#используются координаты
def targetChangedOwn(own):
if own.typeMissions == "AntiAircraft":
own.targetType = 0
sceneObjList = ArbitrGame.UNITS[0][own.targetType][own.target]
tempSortedList = []
if len(sceneObjList) > 0:
tempsortedList = sorted(sceneObjList, key = lambda obj:own.getDistanceTo(obj))
#print(tempsortedList)
own.targetID = str(id(tempsortedList[0]))
else:
own.PR = 0
own.targetID = ""
#Расчет точки упреждения
def Ballistica(own):
try:
target = scene.objects.from_id(int(own.targetID))
#Тип прицеливания - отслеживание самой цели
if own.typeCoordTarget == "AimingTarget":
newPos = target.worldPosition
#Тип прицеливание с упреждением
if own.typeCoordTarget == "VisibleTarget":
# Рассчитываем время полета снаряда.
t = own.getDistanceTo(target) / own.speedBullet
# Рассчитываем путь перемещения объекта за это время.
S = target.worldLinearVelocity * t
xS = target.worldPosition[0] + S[0] + random.randrange(-own.razbros,own.razbros)
yS = target.worldPosition[1] + S[1] + random.randrange(-own.razbros,own.razbros)
zS = target.worldPosition[2] + S[2] + abs((-10*t*t)/2) + random.randrange(-own.razbros,own.razbros)
newPos = [xS, yS, zS]
#print(target)
Turret(own, newPos)
except:
own.PR = 0
own.targetID != ""
#Управление наведением в горизонтальной плоскости
def Turret(own, newPos):
#print(own.PR)
Turret = own.childrenRecursive[own.unitName + "Turret_"]
#Данные по ориентации
orientY = Turret.getVectTo(newPos)[2][1]
orientX = Turret.getVectTo(newPos)[2][0]
#Скорость наведения
kZ = own.speedMaxGor
correct = 1.0
znak = 0
if orientX > 0:
znak = -1
elif orientX < 0:
znak = 1
if orientY > 0.9:
correct = 1 - orientY
else:
correct = 1.0
Turret.applyRotation([0.0,0.0,kZ*correct*znak], True)
Canon = own.childrenRecursive[own.unitName + "Canon_"]
orientZ = Canon.getVectTo(newPos)[2][2]
kX = own.speedMaxVert
correctCanon = 1.0
znakCanon = 0
if orientY > 0.7:
if orientZ > 0:
znakCanon = 1
elif orientZ < 0:
znakCanon = -1
if abs(orientZ) < 0.2:
correctCanon = abs(orientZ)
else:
correctCanon = 1.0
Canon.applyRotation([kX*correctCanon*znakCanon,0.0,0.0], True)
if abs(orientZ) < 0.1 and orientY > 0.9 and own.getDistanceTo(newPos) < own.distMax:
#print(own.getDistanceTo(newPos))
if own.Temp_cassetteBK < own.cassetteBK:
own.PR = 1
else:
own.PR = 0
else:
own.PR = 0
#Перезарядка - магазин, кассета, обойма или снаряд
if own.Temp_cassetteBK == own.cassetteBK:
own.PR = 0
if own.Temp_cassetteBK > 0:
if own.Temp_timerCassetteChanged < own.timerCassetteChanged:
own.Temp_timerCassetteChanged += 1
elif own.Temp_timerCassetteChanged == own.timerCassetteChanged:
own.Temp_timerCassetteChanged = 0
own.Temp_cassetteBK = 0
def shooting(own):
#Стрельба из пушек, пулеметов и многоствольных систем
if own.typeShoot == "Zalp":
for FLAME in own.fireGun:
addBullet(own, FLAME)
#Стрельба из РСЗО, РБУ и прочих реактивных(ракетных) систем
elif own.typeShoot == "Paket":
FLAME = own.fireGun[own.BK-1]
addBullet(own, FLAME)
own.BK -= 1
own.Temp_cassetteBK += 1
#Функция добавления снаряда и прочего - звука, вспышки...
def addBullet(own, FLAME):
Canon = own.childrenRecursive[own.unitName + "Canon_"]
#Вспышка - лампа
vspyshka = scene.addObject('LampUniversal', Canon, own.gunPausa+1)
vspyshka.setParent(Canon, False, False)
vspyshka.localPosition = FLAME
#Вспышка - меш
vspyshkaMesh = scene.addObject('AudioGun', Canon, own.gunPausa+5)
vspyshkaMesh.setParent(Canon, False, False)
vspyshkaMesh["audioProp"] = own.audioGun
vspyshkaMesh.replaceMesh("FireUniversal", True, False)
vspyshkaMesh.localPosition = FLAME
razmer = own.scaleGun
vspyshkaMesh.worldScale = [razmer, razmer, razmer]
vspyshkaMesh.visible = 1
#Снаряд цепляется к самому юниту и происходит мутация
#Проверяется наличие атрибута вроде калибрСнаряд = 23мм
#и объект мутирует в своем классе
dynObj = scene.addObject('UniversalBullet',vspyshka , 300)
dynObj.worldScale = [1.0,1.0,1.0]
if "calibr" not in dynObj:
dynObj["calibr"] = own.gunBullet
dynObj.localLinearVelocity = [random.randrange(-own.randomSpeed,own.randomSpeed),
random.randrange(-own.randomSpeed,own.randomSpeed)+own.speedBullet,
random.randrange(-own.randomSpeed,own.randomSpeed)]
Пост, конечно, длинноватый получился, да и сами скрипты сыроваты, хотя и работают. Но как "история развития", может, кому-то и будет интересно. А то и полезно. В завершение приведу скрин работы "Эрликона". Пушка смотрит в сторну цели , вот только пока она еще безобидна. Надеюсь, ненадолго. Освещение, конечно еще то... Все никак не начну ковыряться в скриптах упитиса, чтобы понять, как писать шейдер... Ну, не все ж сразу...
Комментариев нет:
Отправить комментарий