вторник, 13 декабря 2016 г.

Цветомузыка СПО.

СПО - сокращение от "Системы Предупреждения об облучении". Ныне эти системы весьма распространены, в том числе и среди автолюбителей, называясь "антирадаром" (чтобы заранее узнать, где сидит злой гаишник, готовый выписать штраф за превышение скорости)...
На самолетах военных же СПО предназначена для идентификации угрозы со стороны вражеских машин, использующих радары. И именно радары - именно на них реагирует СПО. Впрочем, также успешно СПО реагирует на облучение радаров ЗРК, если известна их частота 9в первые дни войны Судного Дня израильтянам здорово досталось от "Кубов",  частоты работы которых, в отличие от ЗРК С-75 и С-125, израильтянам известны не были и СПО их самолетов на работу станций ЗРК "Куб" не реагировали).
Так что СПО не спасет от внезапного выстрела из ПЗРК или неожиданно пущенной в хвост ракеты с ТГСН, которую враг запустил, используя теплопеленгатор. Но вот внезапного пуска ракеты с радийной головкой самонаведения не выйдет в принципе, если СПО зафиксировала работу радара. Причем радар выдает себя на гораздо большем удалении, нежели может охватить - отраженные импульсы с увеличением дистанции теряют силу,  не доходя до приемника, а вот излученные импульсы вполне способны СПО "потревожить" на дистанции, с которой противник просто не сможет принять отреженный сигнал.
все это - небольшое лирико-техническое отступление. В игре СПО только одна - и находится она у самолета игрока, точнее, на оверлейной сцене кабины. Ее единственное назначение - сообщить игроку об угрозе со стороны противника. Причем во второй версии СПО угрозы селектирует по степени опасности. тут играет свою роль не только дистанция до противника, но и его готовность открыть огонь или уже выпустившего ракету.
Ниже приведен скрин работающей СПО-10 "Сирена-3" в кабине истребителя МиГ-23МФ.
 Панель СПО - в белом прямоугольнике.


 Устройство включает в себя по четыре жельые и красные лампы, расположенных по периферии круглой панели и одну большую красную лампу посередине на изображении самолета. На скрине она потушена. Горят одна жельая лампа (правый передний квадрант - угроза спереди справа) и четыре красные лампы - показываюшие расстояние до источника угрозы - в пределах 20-30 км.
Мне неизвестно точно в деталях, как работает СПО-10, поэтому в соответствии работы красных лампочек я не уверен - тут я исходил из индикации работы СПО-15, на которой имеется ряд лампочек, отвечающих за отображение  дистанции до угрозы. Да и индикация СПО-15 тоже куда как более продвинута, о ней я напишу потом, когда до нее доберусь.
Пришлось повозиться со звуками, потому что СПО выдает не только световые, но и звукаовые сигналы земмером, меняющим тон и частоту звучания в соответствии с обстановкой.
А теперь немного кода.Сначала я дописал небольшую функцию для передачи в кабину данных об угрозах.

def SPODATA(own, target):
 
    indexOwn = str(id(own))                                        #Индекс перехватчика
    #indexTarget = str(id(target))                                  #Индекс цели
    distance = own.getDistanceTo(target)/1000                #Дистанция от источника угрозы
    LockOn = own['LockOn']                                   #Режим работы сенсора - облучение, захват, подсветка
    typeSensor = own['localDict']['sensList'][own['typeSensor']]   #Тип сенсора
    targetWectOwn = target.getVectTo(own)[2]                       #Ориентация цели относительно перехватчика
    #ownVectTarget = own.getVectTo(target)[2]                        #Обратная ориентация
    heigtUpDown = own.worldPosition[2] - target.worldPosition[2]   #Показатель превышения-принижения перехватчика перед целью
    PR = own['PR']
    AVTO = own['avto']
   
    #Список харакетирисимкм угрозыдля работы СПО оверлейной сцены
    SPODATA = [indexOwn, AVTO, PR, LockOn, distance, typeSensor, targetWectOwn, heigtUpDown]
   
    #Глобальный словарь
   
    bge.logic.globalDict['SPODATA'].append(SPODATA)

Думаю, в комментариях к коду понятно, ради чего все это нужно. Через определенные промежутки времени идет обнуление данных - многомерный список "пустеет", чтобы не засорять память. А "на том конце провода" идет селекция угроз из списка и работает индикация.  Звкеи работают в другом модуле, его я приводить не буду, поскольку ЕМНИП, я уже выкладывал тут его код. Саму функцию выбора звука я чуть доработал, но принцип все тот же - выбирается актуатор по НАЗВАНИЮ, задаваемый проперти audioProp.
Ну, в этой функции и задана работа ламп индикации по принципу "видно- не видно". СПО-10 система относительно простая, даже примитивная, гораздо сложнее ее СПО-15, правда, там индикация более подробная.
Итак, код работы СПО-10.

#SPODATA = [indexOwn, AVTO, PR, LockOn, distance, typeSensor, targetWectOwn, heigtUpDown]

def spo10():   
    cont = bge.logic.getCurrentController()
    scene = bge.logic.getCurrentScene()
    own = cont.owner
   
    #Это списки по степени угрозы
    listAVTO = []
    listPR = []
    listLockOn = []
    listNotThreat = []
   
    SelectThreatList = bge.logic.globalDict['SPODATA']
   
    #Список ламп СПО-10
    quad1 = scene.objects['SPOquad1']
    quad2 = scene.objects['SPOquad2']
    quad3 = scene.objects['SPOquad3']
    quad4 = scene.objects['SPOquad4']
    SPOalarm = scene.objects['SPOalarm']
    SPOdist5km = scene.objects['SPOdist5km']
    SPOdist10km = scene.objects['SPOdist10km']
    SPOdist15km = scene.objects['SPOdist15km']
    SPOdist20km = scene.objects['SPOdist20km']
   
    Cockpit = scene.objects['Cockpit']
   
    lampQuadrant = [quad1,quad2,quad3,quad4]
    lampDistance = [SPOdist5km,SPOdist10km,SPOdist15km,SPOdist20km]
   
    SPODATA = bge.logic.globalDict['SPODATA']
   
    #Если есть что  обрабатывать
    if len(SPODATA) > 0:
        for threat in SPODATA:
           
            #Если просто облучают
            if threat[1] == 0:
                listNotThreat.append(threat)
           
            #Если взяли на сопровождение
            elif threat[1] == 1:
                listNotAVTO.append(threat)
               
                #Если смаолет игрока захвачен и противник готов применить оружие
                if threat[2] == 1:
                    listPR.append(threat)
               
                #Если противник уже выпустил ракету и подсвечивает ее
                if threat[3] == 1:
                    listLockOn.append(threat)
                   
    #Теперь селектируем приоритетную угрозу в списке SelectThreatList                  
    #Идет сортировка по степени угрозы, выбирается сначала самая опасная
    if len(listLockOn) > 0:
        SelectThreatList = sorted(listLockOn, key = lambda obj:obj[4])
    else: 
        if len(listPR) > 0:
            SelectThreatList = sorted(listPR, key = lambda obj:obj[4])
        else: 
            if len(listAVTO) > 0:
                SelectThreatList = sorted(listAVTO, key = lambda obj:obj[4])
            else: 
                if len(listNotThreat) > 0:
                    SelectThreatList = sorted(listNotThreat, key = lambda obj:obj[4])
                else: 
                    SelectThreatList = []  
   
    #Если угрозы отсутствую, гасим все лампы на панели СПО       
    if len(SelectThreatList) == 0:
        for lampQuadrants in lampQuadrant:
            lampQuadrants.visible = 0
        for lampDistances in lampDistance:
            lampDistances.visible = 0      
    else:
        #А иначе, начинаем обработку обстановки
       
        #Лампа ракетной атаки противника
        if SelectThreatList[0][3] == 1:
            SPOalarm.visible - 1
        else:
            SPOalarm.visible = 0
       
        #Лмапы дистанции до угрозы   
        if SelectThreatList[0][4] > 30:
            lampDistance[0].visible = 0
            lampDistance[1].visible = 0
            lampDistance[2].visible = 0
            lampDistance[3].visible = 0
       
        elif 20 < SelectThreatList[0][4] < 30:
            lampDistance[0].visible = 1
            lampDistance[1].visible = 1
            lampDistance[2].visible = 1
            lampDistance[3].visible = 1
           
        elif 10 < SelectThreatList[0][4] < 15:
            lampDistance[0].visible = 1
            lampDistance[1].visible = 1
            lampDistance[2].visible = 1
            lampDistance[3].visible = 0
           
        elif 5 < SelectThreatList[0][4] < 10:
            lampDistance[0].visible = 1
            lampDistance[1].visible = 1
            lampDistance[2].visible = 0
            lampDistance[3].visible = 0
           
        elif SelectThreatList[0][4] < 5:
            lampDistance[0].visible = 1
            lampDistance[1].visible = 0
            lampDistance[2].visible = 0
            lampDistance[3].visible = 0
           
        #Лампы квадрантов
       
        #Слева спереди
        if SelectThreatList[0][6][0] < 0 and SelectThreatList[0][6][0] > 0:              
            lampQuadrant[0].visible = 0
            lampQuadrant[1].visible = 1
            lampQuadrant[2].visible = 0
            lampQuadrant[3].visible = 0
      
        #Справа спереди
        elif SelectThreatList[0][6][0] > 0 and SelectThreatList[0][6][0] > 0:              
            lampQuadrant[0].visible = 1
            lampQuadrant[1].visible = 0
            lampQuadrant[2].visible = 0
            lampQuadrant[3].visible = 0
          
       
        #Справа сзади
        elif SelectThreatList[0][6][0] > 0 and SelectThreatList[0][6][0] < 0:              
            lampQuadrant[0].visible = 0
            lampQuadrant[1].visible = 0
            lampQuadrant[2].visible = 1
            lampQuadrant[3].visible = 0
           
        #Слева сзади
        elif SelectThreatList[0][6][0] < 0 and SelectThreatList[0][6][0] < 0:              
            lampQuadrant[0].visible = 0
            lampQuadrant[1].visible = 0
            lampQuadrant[2].visible = 0
            lampQuadrant[3].visible = 1

        #Звуковая сигнализация
        if len(SelectThreatList) == 0:
            Cockpit['audioProp'] = 'NULL'
            Cockpit['volume'] = 0.0
            Cockpit['pitchSound'] = 0.0
        else:
            if SelectThreatList[0][3] == 1:
                Cockpit['audioProp'] = 'InfoLaunch'
                Cockpit['volume'] = 1.0
                Cockpit['pitchSound'] = 2.0
            else:
                if SelectThreatList[0][2] == 1:
                    Cockpit['audioProp'] = 'InfoLock'
                    Cockpit['volume'] = 1.0
                    Cockpit['pitchSound'] = 3.0
                else:
                    if SelectThreatList[0][1] == 1:
                        Cockpit['audioProp'] = 'InfoLock'
                        Cockpit['volume'] = 1.0
                        Cockpit['pitchSound'] = 1.0
                    else:
                        Cockpit['audioProp'] = 'InfoLock'
                        Cockpit['volume'] = 1.0
                        Cockpit['pitchSound'] = 0.0

Это, скорее, черновой вариант. Тут можно еще подработать код. Главный принцип 0 из общей мешанины вложенных списков выделяются списки по категориям угрозы. И эти списки сортируются по дальности до источника угрозы - приоритет отдается ближайшему. И вот тут-то выбрана последняя "матрешка" - выбранный элемент большого списка - это тоже списочек, только маленький, а внем расписано направление на угрозу, дистанция, степень опасности и так далее. Типа Кощеевой иглы, можно и так сказать (игла в яйце, яйцо - в утке, утка в зайце, заяц - в шоке). Также в этой функции выдается команда на использование звука, его частоту и громкость.
Таким образом, еще один важный этап позади. впереди - обмен информацией между ботами -  кто кого "ведет" и по кому бьет, а также отработка боевого маневрирования и стрельбы. Если это удастся сделать, то основная часть работы будет позади. Все остальное - уже детали и код-заготовка для таких деталей уже будет в наличии.

Комментариев нет:

Отправить комментарий