Показаны сообщения с ярлыком Blender 3D. Показать все сообщения
Показаны сообщения с ярлыком Blender 3D. Показать все сообщения

суббота, 14 декабря 2019 г.

Дорогу осилит ползущий...

Долгое время не писал. Особо не о ч ем было. Как-тог подзабросил дела - очередное лечение с его порцией уколов в глаза, виски и прочие места, чтение накопившихся книг, ползанья по Сети в поисках учебников, чтение оных же, поиск информации и примеров. Да и лень-матушка, куда ж без нее...
На днях выправил ситуацию с неправильной индикацией выбранного оружия на подвесках самолета игрока. Как оказалось, задача была не такой страшной, как виделось. Для этого понадобилось ввести в стартовый json летательного аппарата еще одну переменную, раскомментировать строку в одном скрипте, добавить пару строк в другом. В итоге теперь информация с названием и оружия и его БК послушно высвечивается при перебре оружия и гаснет при выключении системы управления вооружением. Вот так:
Цель - F-16C ВВС США, удаление 24 км, тип оружия - УРСД Р-23Р, БК-2, режим - РЛС с дальностью обнаружения - 60 км.

понедельник, 18 декабря 2017 г.

Дао скриптов. Перманентный погром, как оптимизация.

"Лев Революции", товарищ Троцкий (ставший потом Иудушкой после изменения политичекой еонъюктуры) как-то провозгласил: "Есть у революции начало и нет у революции конца". Это изречение вполне применимо к моему проекту, хотя, если честно, мне гораздо больше нпавится другое его изречение: "И пусть наши враги знают - на всякую принципиальность с их стороны мы ответим абсолютной беспринципностью!" Но что есть - то есть.
В прошлом посте я писал, по поводу "дробления" огромных кусков кода на удобочитаемые скрипты относительно небольшого объема. Что ж, схема обретает свои очертания. Итак, сначала мы используем священное заклинание import sys. А потом перечисляем требующиеся нам пути к папкам с новыми скриптами.
import bge

import sys
for pathFolder in ["Scene_Scripts","UnitAir_Scripts", "UnitGround_Scripts", "Weapon_Scripts"]:
    sys.path.append(bge.logic.expandPath("//Scripts/" + pathFolder))

Всего-то три строчки привели прямо-таки к тектоническим сдвигам... Постепенно стали исчезать скрипты из пускового бленда, а оставшиеся стали "съехиваться" в размерах, порой всего-то то десятка-другого строчек. А огромные куски кода стали распадаться на мелкие скрипты и скриптики, узкоспециализированные, не интересующиеся жизнью соседей и занимающихся исключительно своим делом.
Сама схема теперь выглядит примерно так. Смотрим по уровням.

1. Первый уровень, видимый в пусковом бленде и там же находящийся. Я его обозвал скрипт-нод. Например CONTROL_UnitAir. Он отвечает за поведение летательного аппарата, безразлично от того, летит ли он или стоит на аэродроме, изображая мишень. Теперь от огромного скрипта остались только пара десятков строчек. Непрервыно в этом скрипте работает лишь система детализации. При условии, что ЛА летит, из папки со скриптами вызывается скрипт UnitAir_engine.

def UnitAir():
    cont = bge.logic.getCurrentController()
    own = cont.owner
   
    if own.controlUnit != "Statist":
        UnitAir_engine.engine(own)
       
    #Работа уровня детализации идет ВСЕГДА
    UnitAir_LODes.LODes(own)

2. Уровень два. Включает два скрипта. Первый - уровни детализации - смена объектов потомков или замена их мешей в зависмости от расстояния. Все то же, о чем раньше писал, просто вынесено в отдельный скрипт. И второй скрипт - описание поведения ЛА. А вот здесь кроется еще одна ниточка, ведущая на третий уровень. Это приводит к тому, что в начале скрипта взываются модкли анимации, модели сенсоров, модкли ИИ или модуль управления игроком. так сказать, "смерть кощея": "Игла в яйце, яйцо в утке, утка в зайце, заяц в шоке". Ну, или в сундуке, который висит на огромном дубе за тридевять земель...

3. Уровень три. так сказать, уровень нюансов. Здесь скриптов гораздо больше и лни помельче. Это, к примеру, описание работы сенсоров самолета (РЛС, теплопеленгатор и тд), описание анимации подвижных деталей (рули высоты, элероны и тд), описание поведения самолета при штопоре, модель разрушения и так далее. В свою очередь, некоторые из этих скриптов ведут все дальге и вниз. На четвертый уровень, если надо.

Вообще главное в этом деле, - точно прописать в вызываемых модулях в "шапке" перед функциями импортирование нужных именно на этом этапе модулей. А поскольку на самом первом этапе мы уже перечислили, какие папки нам нужны, можно обойтись без прописания строчек типа бгеЭспандПатч(чего-то-там). Для профессиональных программистов ничего нового в этом нет, но я-то всего лишь самоучка и пишу эти строчки для таких же, как и я. Ну или позабавить более продвинутых своими героическими штурмами открытх дверей, которых надо просто потянуть на себя, а не пытаться вышибать с налету.

Тем временем, похоже идет к концу разрешение проблемы с анимацией всех без исклюяения подвижных объектов, за исключением шасси. Мне ранее удалось сделать универсальную функцию работы рулей направления, перекладки крыла, открытия фонаря, выпуска-уборки закрылков и предкрылков.. Вроде я об этом писал, потом напишу еще для элеронов, интерцепторов и рулей высоты. Проблема крылась в том, что у многих машин оно отклоняются на больший или меньший угол в зависмости от скорости или стреловидности.  Кажется, теперь понятно, как этого добиться, не сильно напрягая мозг большим количеством строчек кода. Но пока данное "изобретение" нуждается в проверке и об этом напишу в другой раз.
На данный момент неторопливо и осторожно я "растаскиваю" скрипты, не делая слишком резких движений, чтобы не обвалить работающую конструкцию. Надеюсь, в пусковом бленде останется совсем мало скриптов, а все остальное будет лежать в папках, и вытаскиваться не все подряд, а только то, что нужно в данный момент.

понедельник, 2 октября 2017 г.

Размышления о наземных объектах-2. Как бы все это разрушить...

Как обычно, после перерыва в использовании блога по причине израсходованого трафика, узнаешь много нового... Так, сегодня freenome отказался пускать меня в мой же блог. Это было для меня в первый раз, но не первый раз в Сети. быстро пробежавшись по сети, нашел упоминания о подобном саботаже, причем не только freenome, но и других хостингов. Ну раз так, то вникать я в причины блокировки не стал. Это достаточно хроническое явление для бесплатных доменов и у меня нет времени и сил, чтобы вникать в тонкости взаимоотношений сайтоы, блогов и хостингов. спросил у dron-а, что с этим делать и утвердился в мысле, что надо просто убрать использование домена из настроек. Надеюсь, получилось и эти строчки могут прочитать все остальные.
Несколько дней я пытался нащупать хоть какую-то схему воздействия на игровые объекты. Задача состояла в том, что разные типы боевых частей по-разному воздействуют на объекты. В конце концов, пришел к выводу, что объект должен обладать неким атрибутом, назовем его "уровнем боевой устойчивости". Или crashDefens, как-то так. Сей уровень характеризуется неким порогом, ниже которого поразить объект оружием с низким ТТХ невозможно. Например, как-то натолкнулся на вопрос:"Может ли ЗУ-23-2 остановить танк?". Ответ воевавшего в Чечне танкиста был таков: "Может. Если экипаж танка ее заметит и остановится. Для прицеливания..."
Вывод:
В оружейные ТТХ надо вводить уровень  "преодоления защиты", эффективности, что ли, так скажем.
И тут начинается самое нитересное.  Нужен какойто эталон, от которого можно отталкиваться.  И в качестве эталона была выбрана бомба ФАБ-100. Известно, что ее радиус поражения (сплошной) составляет 12 метров. Вообще в самих бомбах где-то половина веса - это металл, остальное - взрывчатка. Ну что ж, берем 50 кг за 0.1 . Извращение, конечно, ну ладно, в конце концв изготовлять эталон веса или длины мне не надо. Примем за основу. С бомбами далее оказалось проще - 28 метров для ФАБ-250 и 40 - для полутонных бомб. исходя из этого я и правил показатель...
предполагаю, что внутри этого радиуса сплошного поражения наземные юниты уничтожаются, если, это, конечно, не бункер с уровне защиты 0.5. Тому же "Абрамсу" будет фиолетово, что упало ему на башню - ФАБ-100, 250 или ОФАБ-250. А вот потом...
На расстоянии двойного радиуса поражения эффективность оружия падаеь  вдвое,  еще дальше - вчетверо. Но, если рядом с "Абрамсом" в момент взрыва стоял еще один танк и БМП в зоне падения ущерба, то порог воздействия на танк преодолен не будет, а вот БМП может и выйти из строя после попадания осколков и удара взрывной волны.
Понимаю, сии измышления неплохо бы подкрепить кодом, но был занят - срочно вписывал в json бомб и УРВВ  данные об их могуществе и типе БЧ.
Прикол заключается в том, что БЧ ракет "воздух-воздух" на три четверти состоят из поражающих элементов и только четверть забирает взрывчатка. В общем-то опять натягивание совы на глобус получается, но вменяемой и систематизированной информации по этому вопросу нет. нет, найти массу БЧ ракет не проблема, но далеко не всегда указывается вес ВВ. Ну ладно, решил так сделать.
Объем работ оказался приличный. А впереди еще ракеты "воздух-земля"...
Попутно выяснил еще ое-каие вещи. Например, что ракета Р-27ЭМ заточена под перехват КР "томагавк" или ПКР "Гарпун". А вот ракета Р-27ЭП специализируется на выбивании постановщиков помех. Это дело надо учесть. Еще ракетами типа Р-77, Р-73, Р-77 и AIM-9X можно организовать персональное ПРО, отстреливая пущенные по тебе ракеты.
Также попалась серия интересных статей на Афтершоке по авианосцам и крылатым ракетам. Выяснилось, что многие, так называемые эксперты не знают некоторых элементарных вещей. Например, среди поклонников западной военной мощи бытует мнение, что ПКР российских кораблей посшибают ракетами и пушками "Хорнеты", причем за считанные минуты, а потом наши корабли будут расстреляны, как в тире. Ну-ну... Другие, наоборот, впадают в крайность и яростно отмахиваются от необходимости иметь свои авианосцы для обеспечения ПВО кораблей. Но тут есть свои нюансы...
Недавно на Дальнем востоке прошли учения по отражению удара КР с моря силами ВВС и ПВО. Причем с боевыми стрельбами. и хотя цели были поражены, выяснилась одна настораживающая деталь. МиГ-31 дал залп двумя ракетами по ПКР "Гранит", шедшей по маршруту и попал. Цель была изрешечена, но невозмутимо продолжала себе лететь. Последовал второй залп. Только после этого ПКР удалось свалить. все дело в том, что у "Гранитов2 есть бронирование, защишающее важные узлы и сбить ее не так то просто. На одну ракету ушло 4 Р-33 - весь БК одного МиГ-31. "Хорнеты" могут стрелять AIM-120, БЧ которых сдабее больше чем в два раза. Итого, ладно, с натяжкой будем считать - 6 АМРААМ на один "Гранит". Но в залпе 20 ПКР. И кроме них, кое-что еще помельче. По поводу пушек - даже не смешно - отстрел "Гранитов2 на полигоне из 20-мм пушки не дал НИЧЕГО.  Поразить эту ПКР может лишь 30-мм пушка, да и то с рядом условий.
Придется ставить уровень боевой устойчивости еще и на оружие... Добавлю, что для надежного уничтожения ПКР нужен ЗРК, но обнаружить подлетающую над волнами ПКР он может не так далеко, есть еще время реакции, что приводит к тому, что ЗУР стартует, когда расстояние до корабля для ПКР уже меньше километра (а иногда сильно меньше). И есть еще мертвые зоны, и есть бортовая РЭБ самой ракеты и есть увеличенная точность попадания в уязвимые места.
Короче, морской бой, если я до него доберусь, обещает быть очень интересной задачкой.
Ладно, вернемся к нашим баранам, то бишь наземным объектам. Действие фугасных и осколочно-фугасных бомб и снарядов я описал выше. Все зависти от расстояния до окружающих объектов.
Но есть подкалиберные снаряды и кумулятивные снаряды. Вот для них радиус поражения нулевой. Они втыкаются в броню конкретного танка, БМП или БТР, "не отвлекаясь" на окружающее. Если при взрыве фугаса надо циклом перебирать все объекты-юниты по расстоянию, то в этом случае просто идет проверка условий по единственной цели - в которую снаряд попал. Тут уже вступает в строй условие наличия-отсутствия  динамической защиты и угла встречи с броней, если таковая есть и имеются данные по ее толщине.
На b3d.ua есть WIP от  exooman-a, который занимается танками, в отличие от меня. Он тоже всячески рассчитывает подобные мелочи, у него тоже есть ДЗ, толщина и угол брони и много чего...
Надо добивать ракеты класса "воздух-земля", дописывая для них json, в основном с оружием будет закончено, но остаются еще зажигательные баки, кассеты, контейнеры с суббоеприпасами и тому подобная мелось. И такие извращения, как "радость танкиста" - кассеты с самоприцеливающимися боевыми элементами, опускающимися на парашютах и прошибающими крыши танков и прочей техники кумулятивной струей.
А еще шейдеры и карта высот, которую я еще не успел поновой закачать у denis8424 (движение по карте высот без физики). Разные интересные мысли крутятся, однако... Вроде полногог отказа от физики, кроме снарядов и бомб. В ракетах же отказался и ничего, все нормально...

пятница, 8 сентября 2017 г.

Бюрократия. Ревизионизм. Реанимация. Тестирование. Су-25. И снова про blf - избавление от кракозябр.

Следующим после МиГ-27К к реанимации был назначен Су-25. Работа выдалась вполне рутинной. Сначала. А вот потом вдруг всплыла нерешенная еще в пераой версии проблема - кабина Су-25, которую я перенес во вторую версию, была меньше требуемых размеров. Произошло это из-за ошибки в моделировании Су-25 в первой версии. Тогда я вывернулся с оверлейной сценой и благополусно забыл об этом. во второй версии из-за ряда новых нюансов подобная халява не прокатила и пришлось кабину "увеличивать". А вместе с ней и остальные детали - индикаторы, стрелочки и тд. Также пришлось подгонять названия деталей под единый стандарт и править текст скрипта работы приборов. Попутно выяснил, что можно UV-скроллинг задавать из единого центра, называя имена объектов в скрипте - все равно мешей у них в списке всего один. по-видимому, придется все кабины зачистить от лишней логики работы курвиметров и вообще потихоньку оптимизировать скрипты, перечислив газвания стрелочек в "шапках" модулей. Ну, ладно, не в первый раз оптимизирую.
Пришлось повозиться с json для Су-25. Постоянно выплывала ошибка в строке с данными сенсора. В конце концов мое терпение лопнуло и я ее заменил на строчку из другого json, подкорректировав цифры. Ошибка пропала. Что это было я так и не понял.
Установил в кабине прицел АСП-17, про который я писал уже в своем блоге здесь, но пока толком не тестировал.
Большую работу пришлось проделать с меню. Серией различных ухищрений мне удалось достичь того, что теперь текст может более-менее точно располагаться на кнопке, а не только рядом с ней, он может быть русским или английским, иметь определенный цвет и прозрасность. К сожаленпию, смена текстур в 2.78 была таки сломана, да и видеотекстура теперь работает странно... Так что смена заставок в меню была сделана через замену мешей, зато раотает железно.
Наконец, с подсказки dron-а, были ликвидированы жуткие кракозябры вместо русского текста. Понятно, что во всем была виновата кодировка. преодолевается это так:

 with open(bge.logic.expandPath('//Menu/StartMenu.json'), 'r', encoding = 'utf-8') as directMenu:
        JSONmenu = json.load(directMenu)

В данном случае encoding = 'utf-8' - это убийца кракозябр. Русский текст после этого нормально воспринимается и читается в БГЕ и можно его пропечатать на экране хоть в текстовом объекте, хоть в blf. Кстати о последнем. Я уже писал о выведении текста на экран. У меня работают текстовые метки целей (наконец-то получилось отсечь цели позади активной камеры),  но надо было обязательно сделать меню справку о клавишах и командах. Приводить весь текст json, пожалуй, не буду, он длинный и однообразный. Приведу строчку с разъяснением структуры, хотя, там скорее всего и так будет более-менее поянтно.

"str1":{"az":35,"buki":45,"vediR":1.0,"vediG":1.0,"vediB":1.0,"vediA":1.0,"strX":0.01,"strY":0.975,
        "textRus":"Команды","textEng":"Option"},
"str2":{"az":35,"buki":45,"vediR":1.0,"vediG":1.0,"vediB":1.0,"vediA":1.0,"strX":0.01,"strY":0.95,
        "textRus":"+ - увеличение тяги двигателя","textEng":"+ - Engine power plus"}

Хотя нет, не все. Тут еще дело упирается в мой специфический юмор. Недолго думя, я обозвал переменные сами видите как. az и buki - это размер текста. vedi с заглавными буквами - это цвет и прозрасность текста - RGBA, strX-Y- координаты начала строчки на экране. Далее понятно - русский и английский текст. Дело в том, что я постепенно наращивал число ключей в словаре json, не зная толком, что понадобится в работе - в итоге вот так и получилось. Хотя можно и упростить.
Как бы то ни было, меню стало более вменяемым и происходит его сборка-пересборка при смене разделов. у меня не было ни малейшего желания громоздить кучу сцен ради меню, надеюсь, удастся итоговую сцену тоже не делать, а возвращаться в сцену с меню.
И да, наконец удалось ввести в сцену террайна наземную цель - бункер, взаимодействие которого при попадании оружия еще надо как-то отработать - обрушение, разлет обломков там...
Пока меню имеет пять миссий - для МиГ-23МФ и МиГ-29  это перехват Ф-16 и Ф-15 соответственно. Для Су-25, МиГ-23БН и МиГ-27К  я противников из воздуха убрал, но оставил в качестве цели бункер. Надо попробовать ввести МЗА и СЗРК. В первой версии МЗА "Эрликон" был, надо перетаскивать. Плюс "Стрела-1" и БРДМ-2, но их текстурить надо. Когда-то я сделал модель БМП-1. Ее надо избавить от высокополигональных катков и гусениц, посмотреть, что можно упростить и туда же, тем более, она была затекстурена...
В общем, продолжим...
Ниже скрины - нельзя же совсем ез картинок - Су-25 и его кабина. Подвешены по две пары блоков С-8 и бомб ФАБ-250, плюс пара ракет Р-60М.


вторник, 2 мая 2017 г.

Теория классовой борьбы-2. Метод мавра.

В прошлом посте я делился новообретенными знаниями о создании класса и изощрялся в раздаче данных в этом самом классе. И все бы хорошо - все работало, самолет летал, пускались ракеты, работал кокпит... Словом все было замечательно. Однако тут  при добавлении оппонентов вышла неувязочка. Сначала я к своему удивлению, обнаружил упорное нежелание модели МиГ-23МФ добавлять высокодетализированные меши. Погтом вдруг обнаружилось, что кабины нет и управления, кстати, тоже нет. И при всем этом консоль упорно выдавало отсутствие какой-либо ошибки. Еще раз вспомнив бессметрное изречение O.din13: "Боендер не тупит - тупят люди", я приступил к исследованию сего бага. В конце концов, пришлось признать, что дал маху. И весьма ощутимого. Ошибка была в том, что в БГЕ создается ОДИН класс на ВСЕ юниты типа "летательный аппарат". Но при этом его данные меняются в масштабах ВСЕЙ сцены, а не одного конкретного объекта. В итоге вместо пары МиГ-23МФ и пары Ф-16 мы получаем 4 самолета одного типа - чья сточка с данными будет прочитана последней. И это был Ф-16. Но вот добавление "основы" юнита у меня идет независимо от значения в классе, в итоге получаем Ф-16 с нормально работающей моделью и Миг-23 с ЛОД-основой, но тоже вроде как Ф-16! Прикол, ничего не скажешь...
Пришлось некоторое время поломать голову. В итоге, следуя дао дятла и с остервнением пробившись сквозь дебри своего же кода, получил работающую модель. Надо заметить, что у меня идет подключение и использование скриптов-модулей в некоем "коммутаторе". Чтобы совсем уж не ломать существующую структуру с неясным исходом, я применил старый испытанный прием - "против лома нет  приема".

Класс у меня стал простым и суровым:
import bge

class air(bge.types.KX_GameObject):
   
    def __init__(self, old_owner):
       
        self.nameIndex = str(id(self))
        self.WINGS = -1
        self.Temp_WINGS = -1
        self.FLAPS = 0
        self.Temp_FLAPS = 0
        self.SLATS = 0
        self.Temp_SLATS = 0
        self.CANOPY = 0
        self.Temp_CANOPY = 0
        self.AIRBRAKE = 0
        self.Temp_AIRBRAKE = 0
        self.CHASSY = 0
        self.Temp_CHASSY = 0
        self.ROLL = 0
        self.Temp_ROLL = 0
        self.YAW = 0
        self.Temp_YAW = 0
        self.PITCH = 0
        self.Temp_PITCH = 0
        self.ROLLwings = 0
        self.Temp_ROLLwings = 0
        self.avto = 0
        self.Temp_avto = 0
        self.PR = 0
        self.Temp_PR = 0
        self.LockOn = 0
        self.enemy = 0
        self.weapon = -1
        self.Temp_weapon = -1
        self.crash = 1.0
        self.Temp_crash = 1.0
        self.correctSpeedAngleOfAttack = 0.0
        self.levelsDetails = 3
        self.Temp_levelsDetails = 3
        self.angleOfAttack = 0.0
        self.ownType = 0
        self.sensEyesscanTimer = 300
        self.rotatX = 0.0
        self.rotatY = 0.0
        self.rotatZ = 0.0
        self.rollSelf = 0
        self.pitchSelf = 0
        self.yawSelf = 0
        self.antiForce = 0.0
        self.massFuel = 0.0
        self.massChild = 0.0
        self.massFuelTank = 0.0
        self.ownAntiForce = 0.0001
        self.lovushki = 0
        self.correctRotat = 1.0
        self.correctSpeed = 1.0
        self.slideRotat = 0.0
        self.speedTemp = 0.0
        self.typeShtopor = "NULL"
        self.Temp_BK = 0
        self.BK = 0
        self.typeSensor = 0
        self.targetType = 0
        self.timerImpulse = 0
        self.sonicBoom = 0
        self.idTarget = []
        self.PuskSbros = 0
        self.Temp_PuskSbros = 0
        self.indexRadarDist = 0
        self.timerShoot = 0
        self.classWeapon = ""
        self.nameWeapon = ""
        self.Temp_typeSensor = 0
        self.localTargetList = []
        self.threatWeapon = []
        self.sbrosInterval = 0
        self.ochered = 0
        self.Temp_ochred = 0
        self.dictWeapon = {}
       
        self.controlUnit = ""
        self.keyDict = ""
        self.bortNumber = 0
        self.target = -1
       
        self.typeMissions = ""
        self.Marshrut = []
        self.ownGroup = ""
        self.targetGroup = []
        self.escortGroup = []
        self.statusDict = {}
        self.ownBase = ""
        self.levelsSkill = 100
               
        self.THREAT = {"UnitAir":{'RL':[],'TP':[],'LD':[],'RD':[],'TV':[],'MG':[],'SN':[],'EL':[]},
                       "UnitGround":{'RL':[],'TP':[],'LD':[],'RD':[],'TV':[],'MG':[],'SN':[],'EL':[]},
                       "tnreatWeapon":[]}
       
        self.unitName = ""
        self.unitNation = ""
        self.unitModule = ""
        self.speedMax = 0.0
        self.heightMax = 0
        self.speedVert = 0
        self.startSpeed = 1.1
        self.limitRoll = 1.1
        self.limitPitch = 1.1
        self.alarmAngleOfAttack = 0.0
        self.globalRotatPitch = 0.005
        self.speedStall = 0.0
        self.angX = 0.0
        self.angY = 0.0
        self.angZ = 0.0
        self.rotatDyn = 0.0
        self.dvigDyn = 1
        self.MaxPower = 0.0
        self.maxFuelSpeed = 0.0
        self.massFuelOwn = 0.0
        self.massOwn = 0.0
        self.antiECM = 0.0
        self.stealth = 0.7
        self.maxVisibleDist = 0
        self.ownECM = 0.0
        self.lovushki = 0
        self.Temp_lovushki = 0
        self.sensorList = ["Eyes"]
        self.WINGS = -1
        self.Temp_WINGS = -1
        self.dvig = 0
        self.dvigRight = 0
        self.dvigLeft = 0
        self.Temp_dvig = 0
        self.Temp_dvigRight = 0
        self.Temp_dvigLeft = 0
        
        self.etalonDvig = 0
        self.typeManeur = ""
        self.bot = 0           
             
      
def mutate(cont):
    air(cont.owner)

В нем происходит появление всех атрибутов с исходными значениями. Сообсветственно, все юниты при рождении - братья-близнецы. Потом они получают свои качества...
Повозившись с открытиями-закрытиями json, я махнул рукой и стал при появлении юнитов цеплять к ним 2репер", хотя его можно назвать и "ярлыком" (на княжение, стало быть, угу). В этом ярлыке командой типа yarlyk["startDict"]= {} я создавал стартовый словарь и ссыпал туда из json-ов данные. Не абы как, чтобы потом можно было разобраться. В итоге юнит уже имел потомка при появлении, а впотомке было записано все, что нужно. Мне пришлось ввести еще пару бриков для стартовой инициализации юнита - разовая операция по чтению словаря потомка приводила к появлению у объектов одного класса разного набора характеристик. Ничего сложного - просто используем setattr или __dict__.
#Сборка атрибутов юнита
def startInit():
    cont = bge.logic.getCurrentController()
    own = cont.owner
   
    for key in own.childrenRecursive["confaUnit"]["confaUnit"]["startProp"]:
        setattr(own, key, own.childrenRecursive["confaUnit"]["confaUnit"]["startProp"][key]) 
   
    setattr(ArbitrGame, own.keyDict, own.childrenRecursive["confaUnit"]["confaUnit"])
   
    with open(bge.logic.expandPath(own.childrenRecursive["confaUnit"]["confaUnit"]["unitPath"]), 'r') as directClass:
        JSONtechnic = json.load(directClass)
        for key in JSONtechnic["listPropertys"]:
            setattr(own, key, JSONtechnic["listPropertys"][key])
            #print(getattr(own, key))
   
    if own.controlUnit == "Gamer":
        gamerConfig = ["a_x","a_y","a_z","Temp_a_x","Temp_a_y","Temp_a_z"]
        for key in gamerConfig:
            setattr(own, key, 0.0)
           
        setattr(own, "timerFuel", 0)
        setattr(own, "colorHUD", 0) 
           
        sensor1 = scene.objects['SENSOR1']
        sensor2 = scene.objects['SENSOR2']
        sensor3 = scene.objects['SENSOR3']
        #Расстановка сенсоров пустышек для отслеживания ориентации в пространстве
        sensor1.setParent(own, False,False)
        sensor1.worldOrientation = own.worldOrientation
        sensor1.localPosition = [0.0, 1.0, 0.0]
        sensor2.setParent(own, False,False)
        sensor2.worldOrientation = own.worldOrientation
        sensor2.localPosition = [1.0, 0.0, 0.0]
        sensor3.setParent(own, False,False)
        sensor3.worldOrientation = own.worldOrientation
        sensor3.localPosition = [0.0, 0.0, 1.0]

        if 'Cockpit' not in bge.logic.getSceneList():
            bge.logic.addScene('Cockpit',1)
            unit = own.unitName + own.unitNation
            typeCockpit = "//Aircraft/" + unit + "/Cockpit_" + unit + "/Cockpit_" + unit + ".blend"
            bge.logic.globalDict["cockpitPath"] = typeCockpit
   
    elif own.controlUnit == "Statist":
        own.ownType = 1
   
    #Убирем более ненужный реперный объект
    own.childrenRecursive["confaUnit"].endObject()              
   
    #Обязательно заносим юнит в списки "лагерей", сортируя по ходу дела
    ArbitrGame.UNITS[1].append(own)
    ArbitrGame.UNITS[0][own.ownType][own.target-1].append(own)  
    #print(ArbitrGame.UNITS)
   
Судьба репеного объекта соответствует известному изречению:"Мавр сделал свое дело..."
Такая вот поправочка вышла.
Кстати, аналогично я поступил и с оружием. Мне только не хватало, чтобы пущенная мною Р-24Р вдруг трансформировалась в "Сайдуиндер".
Сейчас идет возня с оживлением ботов - с их ИИ и возвращению сенсоров. с сенсорами придется попотеть - во-первых, изменились некоторые названия, во-вторых, где-то скрывается ошибка, возможно, опечатка, сейчас я переписываю скрипт, заодно убирая ставшие ненужными моменты.
Удалось также отладить камеру с ее переключениями - имеется в виду внешний обзор, а также восставноить текстовую маркировку юнитов - по их названиям, лагерю и дистанции.


понедельник, 28 ноября 2016 г.

И снова - записки бюрократа...

Давно я так плотно не работал с Geany... поскольку на подходе нарисовался F-15 Eagle, а характеристики многочисленных AIM-7/9/120 зияли пустотой, оставленные на потом, пришлось срочно  набивать джейсоны для этих (и не только) ракет "воздух-воздух". Помимо американских ракет я "раздал слонов" также нашим, плюс английским, французским, итальянским и израильским УРВВ (про английские зря я написал во множественном числе, потому как присутствует только одна ракета - Skyflash).
Работа велась по принципу "эталона". Брался аналог той или иной модели другой страны и по прикидкам и характеристикам в монографиях и всевозможных вики печатались ТТХ, в том числе скорость реакции слежения, устойчивость к помехам и тд. Понятно, что кроме дальности и скорости с массой ракеты, все остальные данные брались в общем-то "от балды", но джейсоны хороши тем, что если очень надо, достаточно открыть файл и изменить в нем нужные цифры, причем в строчке понятно, о чем идет речь.
В результате были "осчастливлены" ракеты следующих семейств:
Р-3/13/60/73/33/37/40/27/77/98/23/24,
AIM-7/9/120,
Python3/4/5,
Shafrir1/2,
Skyflash,
Matra Super 530D/F,
MICA-EM/IR,
Aspide Mk1/2,Matra R550 Magic.
Все? Кажись, все. Нет ракет типа Р-4, юаровских "Кукри", китайских PL-7/9/12 и шведских клонов. Ах да, еще есть "Метеоры" и "Ирис-Т", общеевропейские, так сказать. АМРАМ - 8 штук, Р-27 - 7 штук, "Сайдуиндеров" - около 15, дюжина (или уже больше?) - "Спэрроу". Много в сумме, короче получается.
А далее наступил черед подключения Ф-15... Сначала пришлось подправлять имена в файле модели. Затем спешно писать json для баков и пилонов самолета, поскольку БГЕ пребывал в недоумении, пытаясь понять, что от него хотят. Потом новый юнит вдруг полетел хвостом вперед и вниз, причем скорость начала приближаться к субсветовой... Как оказалось, у одной детали не был убран статки в настройках, а поскольку она оказалась внутри кубика-двигателя, тот попытался ее "выплюнуть" и "подавился". Наконец "Игл" полетел прямо вперед и строго по горизонтали. Включил внешнюю камеру обзора. Тому, что я увидел, в русском языке соответствует цензурное слово "фигня" (но есть много других, не столь благозвучных и начинающихся на "х"). Ракеты, баки и летчик сдвинуты вперед и вверх. Причем фигура летчика парит в воздухе перед носовым обтекателем.
Сначала я подумал, что где-то переборщил со шкалой потомков. Проверил - все норамльно. После нескольких попыток понять, что это было, отложил на сегодняшнее утро. Как оказалось, утро действительно мудренее вечера. Ошибку нашел почти сразу - несовпадение центра промежуточного потомка с нулевыми координатами. После чего вновь запустил тест и с гордостью пронаблюдал результат:

Сегодня успел основательно поработать над моделью F-16C, для которой теперь надо сделать текстуры формата dds и изменить скрипт (обычно я беру аналогичный скрипт из другого бленда и его изменяю под новую модель).
Что касаемо кабин, то здесь дела обстоят не столь радужно. Если центральную панель "Игла" еще как-то более-менее похожей на оригинал сделать можно, то с боковыми - просто беда. Для F-16 все обстоит гораздо лучше, подробных панелей и схем гораздо больше. Вероятно, придется делать версии кабин, а потом их обновлять по мере улучшения качества картинки.

Сегодня

аСе


четверг, 10 ноября 2016 г.

Первый сбитый, сверхзвук, штопор и подопытные кролики.

Несколько дней назад случилось знаменательное событие в жизни второй, пока еще строящейся версии проекта. Ракетой Р-23Р с борта МиГ-23МФ ВВС Ливии была поражена мишень, рольк оторой исполнил БПЛА Ла-17. Один подопытный кролик скушал второго и стех пор происходит подобное регулярно.
После долгой возни с амонведением ракет и вылавливанием ошибок в скрипте самонаведения (которые заключались лишь в неверной расстановке последовательности строчек, ракетам удалось объяснить, кого надо выбирать из скопища объектов в сцене, как на него ориентироваться . А потом пришлось думать над нанесением ущерба путем подрыва на случайной (в разумных пределах) дистанции. В зависимости от дистанции подрыва и выдается ущерб, причем не только цели но и всем объектам вокруг нее, опять-таки в некотором радиусе. Чем дальше подрыв от объекта, тем меньше вероятность для него получить смертельные повреждения. Это было сделано, чтобы при удачном стечении обстоятельств могла повториться ситуация поражения одной ракетой нескольких самолетов. как это случилось во время ирано-иракской войны, когда иранский "Томкэт" одной ракетой "Феникс" сбил сразу три иракских МиГ-23БН, шедших в плотном строю или во Вьетнаме, когда одним из первых пусков ЗРК С-75 тоже было сбито три "Фантома" (американские летчики тогда еще были непугаными).
Затем пришлось с помощью скриптов объяснять сбитой мишени, что она должна плавно падать по баллистической кривой, да еще при этом испуская огонь и дым. Дым-то она испускает, а вот огонь пока нет... Попутно на b3d.ua прозвучали предложения делать системы частиц одним объектом, состоящим из многих плейнов, управляя через скрипт их геометрией, расположением в пространстве и другими параметрами. Идея хорошая, только мой уровень пока не достиг дзена управления вершинами мешей. Я пока  ограничился беглым просмотром АПИ, но детально не вникал. Потому что впереди будет 2.78 официальная сборка, плюс я занялся еще пробитием звукового барьера и штопором.
в первой версии пробитие звукового барьера приводило к снижению слышимости двигателей, резкому хлопку с появлением быстро тающего облака и только. На сей раз я не снижаю громкость двигателя, я просто отодвигаю все источники звука назад от самолета и возвращаю их на место при переходе со сверхвука на дозвуковой режим.
И вот сегодня утром мне удалось отрегулировать вывод самолета из штопора. Этот режим я так и не ввел в первой версии, зато теперь оттянулся. Обеспечив сваливание машины в штопор, мне пришлось искать условия выхода их него. Точнее, регулировать некоторые коэффиенты в  модели полета. Я прекрасно отдаю себе отчет, что это - псевдоаэродинамика, к реальности имеющая отношение разве что лишь внешне, но это лучше, чем ничего. Кроме того, попутно ввел ограничения по крену - чем больше тангаж самолета (опущен или задран нос), тем хуже (медленнее) он крнеится (прочитал об этом на форуме Лок Она и немедленно всадил в скрипт по принципу "чтоб было и на что-то было похоже). Модель полета и раньше отличалась от первой версии, а сейчас - тем более.
В общем-то, теперь можно переходить на изготовление искусственного интеллекта летающих ботов, попутно вводя радиопереговоры, звуки кабины и прочее.
Нныче что-то Гугл не хочет картинки добавлять, не знаю уж почему, так что скрин добавить не удалось. Кому интересно, идите на b3d.ua, там последние скрины и увидите.


среда, 26 октября 2016 г.

Дао дятла, змеи и обезьяны.

Опять озадачиваю читающих эти строчки столь вычурным названием. Между тем, речь пойдет о кодинге, точнее о стиле, котрый еще именуют быдлокодингом.
Как известно, в восточных боевых искусствах существуют  "животные стили", адепты которых подражают поведению различных животных, дающих название тому или другому стилю. Програмирование -это тоже искусство и в нем тоже есть свои стили.
я лично использую в основном стиль дятла. Суть его состоит в штурме незапертой двери путем методичной долбежки стены рядом с ней. Код работает, он большой, такой, ято порой самого себя перестаешь спустя месяц понимать. В коде много повторов, выглядит он монолитно и впечатляюще.
Иногда, как недавно с форматом json, дверь оказывается запертой на сломанный замок, а пробить стенку "клювом своего кода"(о, завернул...) не удается, ибо стенка железная и дверь тоже. И тогда на помощь приходит обезьяна. Недаром же говорят: "Что человек - то и обезьяна". Наверное, именно этот способ - лучший путь к обретению новых знаний - почитать чужой код, поюзать чужие примеры, поковыряться в том, что когда-то сделали до тебя. Но иногда, как с json, не помогает и это. И тогда на помощь приходит змея. Достаточно отыскать небольшую щелку, чтобы пролезть туда, куда тебе ну очень надо. Я не слишком люблю этот стиль, потому что конструкция, выстраиваемая на этом принципе, громоздка и хрупка (но просто деваться некуда.).
Однако оставим json, и перейдем к текущим делам. dron не раз уже говорил о разбитии скрипта на множество мелких функций, которые имеют узкую специализацию и легко поддаются коррекции. Каюсь, до недавнего времени я понимал его предложения не до конца, но потом, после очередного штудирования скрипта радара и его "разборке-сборке" (Обезьяна в действии), до меня все же стало кое-чего доходить...
Сейчас идет работа над скриптом оружия, в который, кроме модели движения, должны присутствовать модель нанесения урона, эффектов взрыва, звуков и прочей мелочи, такие вещи, как самонаведение. Методов самноведения много. Как и головок самонаведения - иннфракрасные (ИКГСН), радилокационные активные (АРГСН) и полуактивные (ПАРГСН), лазерные, телевизионные инерциальные и так адалее.
Пока идет работа над ГСН УРВВ радийными и тепловыми. Алгоритм таков. в случае наличия проперти в объекте с названием typeGSN вызывается функция-коммутатор GSN. в ней производится проверка на поападание цели в обзорный конус, затем вызывается функция с названием типа ГСН, например PARGSN.  В этой функции по очереди вызываются СТАНДАРТНЫЕ функции-ограничители - по высоте, дальности, ракурсу, превышению-принижению цели, по воздействию помех, наличию препятствий и так адлее. Все дело в том, что головки самонаведения имеют различный набор ограничений - РЛ ГСН, напирмер, способны увидеть цель в облаках, а ИК ГСН в облаках "слепнут", зато им не нужна подсветка цели, как ПАРГСН. Но функции-то проверки на тип препятствия ОДИНАКОВЫ! Зачем повторять код из функции в функциюв самом модуле? Достаточно просто перечислить условия для каждого типа ГСН... Ниже я привожу сам код. Он большой, многое еще предстоит сделать, но общий принцип ясен.

# -*- coding: utf8 -*-

import sys
import bge

#Скрипт для обеспечения работы оружия - прежде всего его воздействии на юниты, движения, вызов эффектов взрывов, расчете урона
#Самонаведение планируется все же использовать в скрипте ClassSensor. Подлежит доработке в классы, с мутацией объекта.

#Класс снаряда для пушки или пули для стрелковки
class bulletGun(bge.types.KX_GameObject):
    def __init__(self, old_owner):
        bulletObj = scene.addObject('dynObj',self, 300)      #Добавляем сам снаряд
        bulletObj['calibr'] = self['calibr']                 #Снаряду даем проперти "калибр", дальше он приобретает необходимые свойства
        bulletObj.setParent(self, False, False)              #Временно парентим снаряд к источнику, чтоб летел правильно
        trasser = scene.addObject('UniversalMesh',self)      #Добавляем трассер к снаряду
        trasser.setParent(bulletObj, False, False)           #Парентим трассер к снаряду
        trasser.replaceMesh('Trasser', True, False)          #Меняем меш плейна на меш трассера
        self['BK'] -= 1
        #Возможно, стоит подумать просто над заменой меша у самого снаряда, но нужно еще выставить worldScale
       
    #Это - пушка ГШ-23Л   
    def GSh23L(self):
        self.childrenRecursive['dynObj'].removeParent()
   
def init(cont):
    sys.modules["bulletGun"] = bulletGun(cont.owner)
   


   
#Функция, задающая траекторию движения динамического объекта - баллистическая кривая
def traectory():
    import mathutils
    #Объект - dynObj, сцена - Scene, слой 2
    scene = bge.logic.getCurrentScene()
    cont = bge.logic.getCurrentController()
    own = cont.owner
    sens = cont.sensors[0]
   
    if own.worldLinearVelocity != mathutils.Vector((0.0, 0.0, 0.0)):
        own.alignAxisToVect(own.worldLinearVelocity, 1, 1.0)
       
#Функция двигателя ракеты
def engine():
    import mathutils
    #Объект - dynObj, сцена - Scene, слой 2
    scene = bge.logic.getCurrentScene()
    cont = bge.logic.getCurrentController()
    own = cont.owner
    sens = cont.sensors[0]
   
    own.localLinearVelocity.y = own['speed']
   
    if 'typeGSN' in own:
        GSN()
    

#Функция-коммутатор головок самонаведения
def GSN():
    import mathutils
    #Объект - dynObj, сцена - Scene, слой 2
    scene = bge.logic.getCurrentScene()
    cont = bge.logic.getCurrentController()
    own = cont.owner
   
    #Проперти, задействованные в этой функции
    #['sensRLscanTarget']         #Типы распознаваемых целей(0 - только небо, 01 - небо и земля, 1  - только земля, проперти строчное)
    #['sensRLscanDistMax']        #Максимальная дистанция обзора
    #['sensRLscanAngle']          #Угол обзора
    #['sensRLscanTimer']          #Время сканирования
    #['sensRLscanCanal']          #Количество одновременно сопровождаемых целей
    #['sensRLscanDeadZone']
    if 'timerImpulse' not in own:
        own['timerImpulse'] = 0
   
    own['timerImpulse'] += 1
    if own['timerImpulse'] > 100:
        own['timerImpulse'] = 0
    try:
        #Определение цели, вектора на нее и так далее
        target = scene.objects.from_id(int(own['idTarget']))
       
        if inConeOfGSN(own, target):
            vect = own.getVectTo(target)[1]
            own.alignAxisToVect(vect, 1, 0.5)
            vectX = own.getVectTo(target)[2][0]
            vectY = own.getVectTo(target)[2][1]
            vectZ = own.getVectTo(target)[2][2]
            print("La-17")
    except:
        pass
             
#Этот   блок - конус сенсора
def inConeOfGSN(own, target):
    import mathutils
   
    axisVect = mathutils.Vector((0.0, 1.0, 0.0))
    targetData = own.getVectTo(target)
    targetVect = targetData[2]
    dist = targetData[0]
   
    angleGSN = own['angleGSN']
       
    #Если объект попадает в конус действия сенсора
    if angleGSN > axisVect.angle(targetVect, None): 
       
        #Вызов метода
        g = globals()
       
        #Тип головки самонаведения - название функции
        typeGSN = own['typeGSN']
       
        #Проверка на функцирнирование ГСН и ее особенностей
        if g[typeGSN](own, target):
            return True
       
    #Или не попадает
    else:
        return False
    return False

#Полуактивная головка самонаведения радиолокационная
def PARGSN(own, target):
    #Проверка на ограничения по высотам и превышению-принижению
    if limitHeightMax(own, target) and limitHeightAbs(own, target) and limitHeightMin(own, target):
        #Проверка по дистанции и отсутствию препятствия
        if limitDistMax(own, target) and rayEARTH(own, target):
            return True
    else:
        return False                   

#Активная головка самонаведения радиолокационная
def ARGSN(own, target):
    #Проверка на ограничения по высотам и превышению-принижению
    if limitHeightMax(own, target) and limitHeightAbs(own, target) and limitHeightMin(own, target):
        #Проверка по дистанции и отсутствию препятствия
        if limitDistMax(own, target) and rayEARTH(own, target):
            return True
    else:
        return False

#Инфракрасная головка самонаведения радиолокационная
def IKGSN(own, target):
    #Проверка на ограничения по высотам и превышению-принижению
    if limitHeightMax(own, target) and limitHeightAbs(own, target) and limitHeightMin(own, target):
        #Проверка по дистанции и отсутствию препятствия и отсутствие оптических помех (дым, туман, облака)
        if limitDistMax(own, target) and rayEARTH(own, target) and rayFOGS(own, target):
            return True
    else:
        return False

#Полуактивная головка самонаведения лазерная
def PLDGSN(own, target):
    return True

#Активная головка самонаведения лазерная
def ALDGSN(own, target):
    return True

#Полуактивная головка самонаведения телевизионная
def PTVGSN(own, target):
    return True

#Активная головка самонаведения телевизионная
def ATVGSN(own, target):
    return True

##################################################################################
#БЛОК ОГРАНИЧЕНИЙ ПО ВЫСОТЕ И ДИСТАНЦИИ
"""
Этот блок - проверка оограничений по дистанции и высотам, поскольку у многих видов ракет имеются
существенные ограничения по высотам применения, превышения-принижения над целью, что ведет к усложнению
модели поведения такого типа оружия в игре.
"""
#Проверка параметров дистанции
def limitDistance(own, target):
    targetDist = own.getDistanceTo(target)
    distLimitMax = own['distMax']
   
    if distLimitMax > targetDist:
        return True
    else:
        return False 

#Проверка параметров МЕНЯЮЩЕЙСЯ дистанции
def limitDistMax(own, target):
   
    #Координаты цели и собственные
    targetPosition = target.worldPosition
    ownPosition = own.worldPosition
    targetDist = own.getDistanceTo(target)
   
    #Собственная высот а и высота цели
    ownHeight = own.worldPosition[2]
    targetHeight = target.worldPosition[2]
   
    #Поправка на ракурс цели - стрельба на догонном курсе возможна с втрое меньшей дистанции
    racursX = (2 - abs(target.getVectTo(own)[2][0]))/2
    racursY = (2 + target.getVectTo(own)[2][1])/2
    racursZ = (2 - abs(target.getVectTo(own)[2][2]))/2
       
    #Еще одна переменная, влияющая на дальность пуска - общий ракурс цели
    RACURS = (racursX + racursY + racursZ)/3
       
    distLimitMax = own['distMax']
   
    #Введение поправки на дальность ниже 3 км дальность составляет 30 процентов
    if targetHeight < 3000:
        distLimitMax = own['distMax'] * target['stealth'] * RACURS * 0.3
       
    #Введение поправки на дальность от 3 до  10 км дальность изменяется в сторону уменьшения с уменьшением высоты
    if 3000 < targetHeight < 10000:
        distLimitMax = own['distMax'] * target['stealth'] * RACURS * targetHeight/10000
       
    if distLimitMax > targetDist:
        return True
    else:
        return False 
   

#Проверка параметров высоты - максимум
def limitHeightMax(own, target):
    if own['heightMax'] > own.worldPosition[2]:
        return True
    else:
        return False

#Проверка параметров высоты - минимум
def limitHeightMin(own, target):
    DeadZone = [target.worldPosition[0], target.worldPosition[1], target.worldPosition[2] - own['heightMin']]
    if own['timerImpulse'] > 100:
        #Проверка на лимит по минимальной высоте пуска по цели
        hitEarth = target.rayCast(targetPosition, DeadZone, own['heightMin'], 'objScene', 0)               
        if hitEarth == (None, None, None):
            return True
        else:
            return False
   
    elif own['timerImpulse'] < 100:
        return True

#Проверка параметров высоты превышение-принижение относительно цели
def limitHeightAbs(own, target):
    ownHeight = own.worldPosition[2]
    targetHeight = target.worldPosition[2]
    if own['heightAbsLimit'] > abs(ownHeight - targetHeight):
        return True
    else:
        return False

##################################################################################
#БЛОК ОГРАНИЧЕНИЙ ПО  НАЛИЧИЮ ПРЕПЯТСТВИЯ
"""
Этот блок - для проверки наличия препятствия перед целью для головок самонаведегия,точнее, здесь
несколько малых функций, поскольку операция стандартная дл я всех ГСН, хотя набор препятствий как
раз неодинаков, не стоит повторять код лишний раз, достаточно просто вызвать нужные  проверки по
цепочке, плюс это упростит коррекцию кода в дальнейшем.
"""
#Препятствие - туман, облако, дым
def rayFOGS(own, target):
    return True

#Препятствие - земля
def rayEARTH(own, target):
    return True

########################################################################
########################################################################
"""
Этот блок из нескольких функций задает поведение оружия в условиях воздействия разного рода помех -
тепловых ловушек, Солнца, электромагнитных, оптических, акустических  и так далее
"""

#Отстрел тепловых ловушек
def obstacleLO(own, target):
    return True

#Отстрел диполей
def obstacleDIPOL(own, target):
    return True

#Уводящая помеха
def obstacleESCAPIST(own, target):
    return True

#Солнце
def obstacleSUN(own, target):
    return True

#Радиопротиводействие
def obstacleECM(own, target):
    return True

Там, где в функции лишь одна строчка return True, еще надо дописывать код. Пока что проверка принтом "La-17" исправно выдает нужный результат - значит, цепочка функций работает. Отдельно замечу, что метод типа rayCast и ему подобные я стараюсь вызывать раз в секунду или больше. постоянные вызовы таких вещей могут притормозить игру из-за их прожорливости. В скрипте около 300 строчек, больше половины из них пояснения и комментарии, надеюсь те, кому это нужно, поймут без дополнительных обяснений. В сущности все "это новое слово" не более, чем компиляция из старых способов, которых я использовал в первой версии чисто механически, боясь слишком сильно менять что либо (а вдруг испорчу?). Ну а теперь дело - за шлифовкой и дописыванием скрипта - раеты уже летают и цели видят. как и сенсоры юнитов...

пятница, 30 сентября 2016 г.

Повторение пройденного. повторение - мать учения...

Работа идет не шибко торопясь. Приходится иногда прямо на ходу придумывать новые схемы или вносить коррективы в уже существующее. Тем не менее, было сделано следующее:
1. Заработали цифровые и буквенные символы ИЛС.
2. Были подчищены скрипты машин, ставшие более универсальными (в смысле можно внаглую скопировать большую часть текста и загнать ее в текст другого скрипта другой машины с минимальными правками).
3. Наконец-то вменяемо заработала коррекция скорости по высоте. Все дело в том, что у земли самолеты имеют меньшую скорость, нежели на средних и больших высотах, к примеру у МиГ-23МЛ у земли скорость 1350 км/ч, на высоте же - 2500, у МиГ-29 та же скорость на высоте, но у земли - 1500, у МиГ-25 скорость у земли 1200, зато на высоте - около или даже больше 3000 км/ч.
4. Также к своему неудовольствию отметил, что не работали показатели коррекции скорости по стреловидности крыла и работе тормозов. Как выяснилось, не в ту строчку вписал нужный коэффициент. Пока возился с мешами модели, было не до этого, но когда смена мешей была обеспечена, устранил и этот недочет.
5. Наконец заработала метка цели на ИЛС. в основе этого "явления" лежит схема, которую предложил еще в первой версии denis8424. Я, как обычно творчески подошел к пересмотру догматов и получил " те же яйца, только в профиль". Надо было бы смастряить файл примера, но все как-то не соберусь. Сентябрь вообще выдался довольно насыщенным и много чего так и не удалось сделать...

6. На ИЛС заработали метки измерения дальности до цели - это для МиГ-23, для Су-25 стал работать прицел АСП-17 (опять таки надо кинуть файл примера).
7. Начала работать возможность "убитьсяАПстену", то бишь разбить самолет о землю, хотя и тут надо доработать, потому что на тех скоростях, которые есть в игре БГЕ часто не успевает среагировать. Надо изощряться...
8. Как апофеоз  всех работ сентября отмечу введение отстрела тепловых ловушек, они же ЛТЦ, они же ЛО. Пока они работают на МиГ-23МЛАЭ2 и МиГ-23МЛД. Способ отстрела весьма извращенный. В файле json самолета выставляется значение проперти startLo = 0, которое говорит о наличии на борту патронов с ЛТЦ. Далее в файле есть список "суб-объектов", как я их обозвал. Это - фигура летчика, генераторы пушечных снарядов и эти самые генераторы ловушек. Все "суб-объекты" имеют чтение определения своего локального положения и разворота относительно родителя плюс проперти. Для генераторов ЛТЦ их два - число патронов и внушительный такой список из координат генераторов ловушек и их разворотов. собственно, можно было ограничиться только координатами, но у некоторых машин выброс ловушек может идти сначала сверху из верхних кассет, а потом снизу - из нижних. поэтому пришлось делать вложенный список. каждый элемент списка включает себя координаты (всегда) и разворот в радианах (очень редко). Поэтому алгоритм отстрела таков.
а) Подается команда на отстрел проперти startLO = 1.
б) Циклом отыскиваются потомки с именем "генераторЛО" и это свойство передается им.
в) Генератор ловушек выполняет команду на выстрел.
г) Генератор ловушек уменьшает свое проперти "патронЛО" (число ловушек) на 1.
д) Генератор ловушек сдвигается на новое 2место жительства" согласно списку координат и разворотов на одно деление (отыскивается элемент с номером, соответствующем текущему значению числа ловушек).
д)Генератор ловушек проверяет, есть ли в элементе списка еще и данные для разворота. Если есть, он еще и поворачивается.
Как только число ловушек равно нулю, генератор немедленно блоуирует у своего родителя возможность стрельбы, проперти startLO самолета становится равным минус 1. И генератор исчезает "мавр сдал свое дело".

Ну а дальше пошло нудное занятие по подгонке стартовых координат и поворотов, создание дыма горящих ЛТЦ - это уже рутина...
Из эффектов полета остается сделать  вихри при маневрировании и эффект пробития звукового барьера.
И еще, штопор. Вот с ним надо крепко подумать. Имея перед глазами показатели угла атаки, пусть и такие грубые и примитивные, как у меня, несложно добиться сваливания в штопор. Более-менее ясно, как его крутить. Остается придумать, как из него выйти. С этим у меня откровенно ничего не вышло и в первой версии я это дело просто убрал, отложив до лучших времен. Не знаю, как там насчет "лучших", но делать это необходимо.
Также я занимался и МиГ-21. Сделал развертку - в первом приближении, для камуфляжа и расшивки. Дополнительные объекты вроде ниш шасси, колес и пр., я наношу на развертку потом, места для них хватает. пока получается камуфляж МиГ-21бис ВВС ГДР.

понедельник, 30 мая 2016 г.

Поход за консенсусом.

Только что удалось отработать генерацию юнитов на сцене путем чтения файла миссии. Во многом вторая версия своим появлением обязана крайне неудачно выбранному способу создания миссии в первой. Как таковая, миссия создавалась в виде отдельной функции со своим уникальным названием и при старте БГЕ приходилось открывать модуль миссий, а затем построчно читать данные для каждого юнита, генеря их, расставляя и раздавая им потомков и нужные проперти.
Во второй версии все это достигается чтением текстового файла в папке Scenery. Разумеется, от генерации, расстановки и прочего для юнитов не обойтись, но данные теперь не повисают в памяти, к тому же становится на порядок легче добавлять новые миссии и кампании. Пока правда, есть одна загвоздка. Необходимо в меню при щелчках по кнопкам, собирать данные в некую структуру и затем полдученную строчку загонять в файл. Задача решаемая, только несколько занудная - необходимо четко соблюсти порядок записи новых данных, отвечающий вырабатываемым стандартам. Так что если угодно, нужен консенсус (согласие) между меню и игровой сценой. Чем и занимаюсь - сближением позиций заинтересованных сторон, так сказать...
А пока пришло время для красивой картинки - тест на чтение текстового файла (точнее файлов, ибо теперь все проперти и потомки с скоординатами и ориентацией раздаются юнитам сразу после появления, что позволило выбросить лишнюю функцию и убрать лишний объект-потомок, который эту функцию и исполнял). Вместо полусотни сточек кода на эти четыре объекта были потрачены 4 строчки в текстовом файле, плюс некоторое количество строчек для его открытия, чтения и закрытия. В любом случае, дело это окупится.
На скотне ниже - звено ливийских МиГ-23МФ с единообразными подвесками - три ПТБ плюс по паре Р-23Р и Р-60.

четверг, 31 марта 2016 г.

Великая анимационная революция.

итак, великая анимационная революция таки свершилась. Заодно она потянула за собой и устранение старых проблем и появление новых. Собственно, из новых проблем наиболее сложной является лишь строгое следование тобой же разработанным правилам. А еще - пересоздание анимаций...
На данный момент все движения и трансформации, за исключением вращения колес шасси, пламени форсажа и свечения турбины задаются изменеием всевозможных проперти. Несомненным достоинством этого метода является возможность избежать резких рывков анимации и прыжков скоростей. Особенно это касается анимаций аэродинамических поверхностей, "рывки" при кренах, тангаже и рыске были настоящим проклятием - было отчетливо видно, как резко "дергается" стабилизатор или элерон при смене курса. Также не вызывало особого восторга стремительное, почти мгновенное возрастание скорости при смене стреловидности или выпуске тормоза. Теперь проперти, управляющие кадрами анимации, интегрированы в модель полета. Это можно рассмотреть на примере выпуска-уборки щитков воздушного тормоза.
Как выглядит работа анимации тормоза:

 if own['levelsDetails'] == 0:
                #Собственно, анимация щитков тормоза - кадр анимации задается значением проперти AIRBRAKE
                for obj in own['localDict']['deviceAirbrakes']:
                    obj.playAction(obj.name,own['AIRBRAKE'],own['AIRBRAKE'],0,0,0,bge.logic.KX_ACTION_MODE_PLAY,0.0,0,1.0)
            #Выпуск тормоза           
            if own['localDict']['AIRBRAKE'] < own['AIRBRAKE'] and own['AIRBRAKE'] < 100:
                own['AIRBRAKE'] += 1
                if own['AIRBRAKE'] == 100:  
                    own['localDict']['AIRBRAKE'] = own['AIRBRAKE']
            #Уборка тормоза
            if own['localDict']['AIRBRAKE'] > own['AIRBRAKE'] and own['AIRBRAKE'] > 1:
                own['AIRBRAKE'] -= 1
                if own['AIRBRAKE'] == 1:                   
                     own['localDict']['AIRBRAKE'] = own['AIRBRAKE']

Думаю, понятно. Вверху указывается - что работа анимации происходит только при высоком уровне детализации и наличия соответствующих деталей-потомков (списко deviceAirbrakes). Кадр анимации жестко привязан к занчению проперти AIRBRAKE. Само проперти работает от команд с клавиатуры (но для ботов - разницы никакой - там просто при выполнении ряда условий происходит отдача точног такой же команды):

 ###################################################
        #Выпуск-уборка воздушного тормоза
        if keyboard.events[bge.events.AKEY] == JUST_ACTIVATED:
            if self['AIRBRAKE'] == 1:
                self['AIRBRAKE'] += 1
            elif self['AIRBRAKE'] == 100:
                self['AIRBRAKE'] -= 1
            #Если оверлейная сцена с кокпитом уже работает
            for sceneGame in bge.logic.getSceneList():
                if sceneGame.name == 'Cockpit':
                    cockpit = sceneGame.objects['Cockpit']
                    cockpit['airbrake'] = self['AIRBRAKE']

то есть достаточно просто "подтолкнуть" проперти вперед или назад один раз. и пока проперти не получит самого большого или самого маленького значения, будет продолжаться его нарастание или убывание. Для тормоза эти значения равны 1 и 100. Аналогично происходит выпуск-уборка шасси, закрылков, смена стреловидности, открытие фонаря и так далее. Но и это не все. величина проперти AIRBRAKE еще и влияет на скорость полета. Упрощенно - скорость задается какой-то формулой, в составе которой имеется и AIRBRAKES, только вот значение его используется не прямо, а вот так:
151/(150 + AIRBRAKES)
Поясняю - минимальное значение проперти равно 1 - тормоз убран. И мы имеем в итоге 1. Скорость не падает. Но стоит только выпустить тормоз, как в конце анимации мы получаем 151/(150 + 100). Что-то коло 0.6. Тормоз действует, "съедая" сорок процентов скорости. Но при этом эти проценты съедаются постепенно - с каждым тиком - с каждым кадром анимации.

Добившись четкой работы анимации всех деталей, я занялся дальнейшей доводкой кокпитов и пополнением  авиапарка. Пока он состоит лишь из модификаций МиГ-23, да и то - одной национальности - ВВС Ливии полковника Каддафи.  изначально я собирался делать версию про египетско-ливийскую войну 1977, да ещ и не сильно отходя от, как мне казалось тогда, незыблемых канонов. оказалось, каноны не такие уж незыблемые...
Пришлось немного повоевать с моделью движения самолета. Если с разворотами все оказалось более-менее понятно - с применением силы Torque, да и с новым методом учета стрелодидности - картинка получалсь архизамечательная по сравнению с первой версией, то вот с линейным движением вышел облом. Как оказалось, сила, толкающая объект вперед, не компенсирует силу тяжести, увы. Так что пришлось опять прибегнуть к localLinearVelocity. Хотя она рассчитывается по-другому, и, как я говорил, ее изменение стало более плавным и реалистичным... Но это дело можно совершенствовать по мере дальнейшего продвижения вперед, так что, кто его знает, что в итоге получится.

Всплыла еще одна не слишком приятная проблема. Ландшафт. С ним я воевал долгог и упорно, и, казалось, победил. но не совсем. При возросших скоростях движения вдруг выяснилось, что его подгрузка не поспевает за камерой и, что хуже всего, просаживает ФПС и сильно при увеличении частоты работы. Однако варианты все же есть и можно попробовать их несколько.
Первый - увеличить размеры блока, что приведет к уменьшению их числа,а, значит, можно даже уменьшить количество обновлений террайна в игре.
Второй вариант - отшлифовать код генерации блоков. что-то мне кажется, что я недостаточно уделял ему внимания. Это, пожалуй, обязательно.
Третий - многообещающий и в то же время рискованный. БГЕ может меня неправильно понять и сильно обидеться. Вплоть до зависания и вылета. Но попробовать надо. Суть в том, что грузится ВЕСЬ ландшафт - все блоки сразу на игровую сцену. И на ней происходит замена мешей блоков на плейны. Маленькие. Но физика-то меша должна сохраниться, как мне объясняли. Грузим ландшафт второй раз, но МЕШЕМ,  из дугого файла. Дальше получается довольно приличное количество плейнов в виде "ячеек", которые будут подменяться мешаи по мере приближения к ним камеры. Проблема в том, что у меня ландшафт имеет 640 килополиков и комп начинает подтормаживать. Не в БГЕ, а в редактировании. Но не знаю, выдержит ли движок такую лютую нагрузку, пусть и на короткое время... Во всяком случае = первый вариант при этом можно применить. Или сделать блоки меша очень сильно низкополигональными. Да, пожалуй, стоит и это попробовать...

Ну, и завершаю пост красивыми (как без них) картинками.
МиГ-23МФ ВВС Ливии. Тест на замену мешей.
МиГ-23БН ВВС Ливии. Тест на анимацию механических частей.

МиГ-23МЛАЭ ВВС Ливии - тест на анимацию шасси. 


четверг, 17 марта 2016 г.

Классы и физика. Кокпит и аэродинамика...

Помимо такой увлекательной вещи, как кодинг, существует масса рутинных вещей. Например, создание номеров. номеров надо много, хороших и разных. В начале недели этим пришлось заняться весьма тщательно. Помимо создания своих собственных номеров для ливийских самолетов (четырехзначные "арабские" - не путать с настоящими арабскими цифрами, без кавычек!), на основе известных мне фото и декалей для моделей (пластиковых, не трехмерных, и самых, что ни есть настоящих, только маленьких!), поискал и нашел в своих закромах арабские номера, с настоящими, без кавычек, арабскими цифрами. Все они были маленькие и из них пришлось "клеить" большую текстуру. С обычными цифрами дело было проще - создаем в ГИМПе текстовый слой и набиваем до одурения - 6901, 6902 и так далее с вариациями для первых двух цифр.
Далее я "припаял" стекла к кабине и фонарю, в смысле, объединил стекла с их "родителями". По большому счету, чем меньше объектов, тем лучше, а прописывать в большом коде по замене мешей еще и стекла... Да ну на фиг... Та же участь постигла малодетализированный кокпит модели на внешнем игровом слое. Я его объединил с фюзеляжем. Все равно в кабине с внешней камеры ничего не видно. Правда, пути отступления я себе сохранил, создав группы вершин для стекол и этого самого кокпита. Чтобы в случае чего, быстро "отрезать".
Затем я поперся постигать Силу... Не джедайскую. Force в БГЕ. Занимает она меня тем, что с ней можно творить что-то близкое к аэродинамике, ну и поведение самолетов как бы естественней. Тем более, что на данный момент Torque задействована в управлении разворотами. Пока я не стал еще переделывать скрипт движения, потому что опять  взбрело в голову поискать, нет ли чего по аэродинамике в BGE. Оказалось, было дело - в 2009 году делалось что-то подобное и ветка на blenderartist сохранилась. С файлами. Устаревшими напрочь. Но несколько таких файликов я скачал и самый "свежий" переделал под сегодняшний Блендер. Ну как переделал? Поубирал GameLogic и вписал bge.logic, с помощью Яндекса перевел комментарии (несколько коряво, но уж лучше того же Гугла-переводчика). Результат столь же ошеломителен, сколь и непонятен... Объект то ли летает задом наперед, то ли что-то было заменено в Питоне с тех пор, в общем, летает "пуля", только очень быстро. Половина скорости света точно есть. Что с этим дальше делать - ясно. Разбираться, разбираться и еще раз разбираться (перевранное (с)). Ну ладно, аэродинамика вещь сложная, но постижимая.времени б только побольше, а то и другое делать надо.
До всех описанных выше событий я занимался кокпитом. Консоль матерится на пару текстур, есть подозрение, что dds не любит квадратные текстуры, не кратных 2 в энной степени (таких у меня 2 точно есть- надо их проверить). Однако сам принцип работы кокпита, о котором я писал ранее, на удивление, пока работает и хорошо. Все стрелки, за исключением указателей ориентации, работают,  их прилично и пульсация для них установлена 1. Если в старой версии кокпитов работа стрелочек кушала много (я проверял, отключая зеркала и метку цели), то в новой версии кокпит пока жрет 1 процент логики, в дополнение к паре процентов движка на игровом слое.
Разумеется, какая-то часть ресурсов еще будет съедена теми же зеркалами, меткой цели, СПО и прочей индикацией. однако... В старой версии, по моим подсчетам, кокпит жрал около 20 процентов, а иногда и до 30. Ненормально много, как выясняется. Причина - запись в глобальный словарь ну очень большого количества данных, да еще и с вычислением попутно, прямо в списке, да еще и с вызовом функций типа int. В общем, теперь в списке находятся 11 данных вместо более полусотни - и это только те, которые меняются постоянно. Остальные будут передаваться напрямую на сцену кокпита. И как управлять объектами оверлее с игровой сцены, не дописывая отдельные скрипты для оверлейных сцен я понял относительно недавно и сегодня успешно реализовал. Пока для переключения камер и зума камеры летчика.

Приведу кусочек кода

#Переключения камеры, если камера в кабине, заодно выставляется ее фокус
                if key == bge.events.F1KEY or key == bge.events.F2KEY or key == bge.events.F3KEY or key == bge.events.F4KEY or key == bge.events.F5KEY or key == bge.events.F6KEY or key == bge.events.F7KEY or key == bge.events.F8KEY or key == bge.events.F9KEY or key == bge.events.F10KEY or key == bge.events.F11KEY or key == bge.events.F12KEY:
                   
                    scene.active_camera = cameraPilot
                    #Если оверлейная сцена с кокпитом уже работает, переключаем камеру и там
                    for sceneGame in bge.logic.getSceneList():
                        if sceneGame.name == 'Cockpit':
                            cameraPilotOver = sceneGame.objects['CameraPilotOver']
                            sceneGame.active_camera = cameraPilotOver
                           
                    if key == bge.events.F1KEY:
                        cameraPilot.lens = 50
                        #Если оверлейная сцена с кокпитом уже работает, переключаем камеру и там
                        cameraPilotOver.lens = 50
                           
                    if key == bge.events.F2KEY:
                        cameraPilot.lens = 35
                        #Если оверлейная сцена с кокпитом уже работает, переключаем камеру и там
                        cameraPilotOver.lens = 35

Думаю, понятно. Но с одной оговоркой - на мой взгляд такие фокусы с оверлеем пройдут при нечастом вызове циклов. Я вообще стараюсь циклы вызывать пореже, где это возможно. И по возможности их не использовать вообще. Попутно сделал так, чтобы камера на оверлее при подключении сцены занимала свое место  соответственно нужному расположению в кабине и припаренчивалась к управляющим плейнам, обеспечивающим ее повороты (имитация поворотов головы летчика). Теперь пора подумать о передаче изменяемых данных непосредственно на кокпит, который будет по поступлении команд "мигать" индикацией шасси, отказов систем, и прочая и прочая... И начать писать код для смены уровней детализации и замены мешей.
Пока что скрин кабины выглядит так (я попутно тестировал еще и работу камеры, поэтому взгляд "не прямо").
В общем пока так. Впереди еще подгонка данных по движению, ЛОДы и прочая. А затем - отработка взаимодействия систем вооружения и БРЭО. Кстати о БРЭО. На мой взгляд, использовать скрипт радара все время нерационально. Скорее всего, он будет работать импульсами - раз в столько-то секунд с десятыми долями. Сильно измениться положение оппонентов за это время не успеет, а в ближнем бою у меня и так была отработана методика стрельбы из пушки и пусков ракет малой дальности с ТГСН. Заодно дополнительно можно сделать разные характеристики для разных машин. По частоте работы радара, прежде всего. Про угол обзора и дальность я уж не говорю. Цели должны попадать "под раздачу" при двух условиях - первое - дистанция меньше, чем разрешенная дальность пуска (зависит от высоты, положения цели, ее ЭПР и еще много чего) и второе  - нос самолета должен быть направлен если не строго на цель, то близко к этому - все это у меня в скриптах было, теперь это надо "очистить от шелухи" и привести в удобочитаемый вид с комментариями. И научиться запихивать в класс несколько функций сразу. И заодно сделать самолеты "ограниченно зрячими". В первой версии боты всегда видели игрока, а вот игрок их мог и не увидеть. Теперь же боты будут следовать либо по маршруту, либо к обнаруженной их радаром цели. У игрока появляется шанс "подловить" ничего не подозревающего оппонента, к примеру подойдя сбоку или сзади. Разумеется, на расстоянии этак км в 8 бот будет знать, что творится и позади него (типа имитация взгляда летчика в зеркало заднего вида). Но вот безнаказанно расстрелять группу противника, зайдя ей в хвост, с большего расстояния - это станет вполне реально. Все-таки работу систем прицеливания и обнаружения надо подтягивать поближе к реальности.

среда, 9 марта 2016 г.

Физика и классы.

Как-то быстро начинаешь привыкать к тому, что еще недавно было для самого себя непонятным и почти магическим. Даже если еще не до конца в этой магии разобрался.
Как справедливо заметили на ГеймДеве, у моих машин в первой версии поведение было излишне резким, дерганым. собственно, это я знал и сам, но без капитальной переделки кода первой версии исправить это было невозможно. А учитывая то, что я просто надстраивал код, дописывая функции и модули довольно-таки хаотично, переделка влекла за собой залезание в лютые дебри. Возможно, из этого что-нибудь и вышло, но сожрало бы уйму времени. Гораздо проще написать код заново, жестко "раскладывая все по полочкам", и используя все лучшее, что сумел наработать ранее.
Физика вращения (самое больное место) теперь задается через Torque, силу, вращающую юнит, заодно стал интенсивно использоваться дампинг для Rotation, что придало вращению юнита плавность и инерционность. Была мысль использовать изменение веса юнита через mass, однако после неудачной попытки я это дело пока отложил, решив воздействовать на поведение самолета через коэффициенты, учитывающие изменения массы топлива, наличия подвесок, и их лобового сопротивления. помимо прочего, сделал еще и плавное убывание-нарастание скорости при выпуске шасси, тормозов и так далее. Раньше скорость менялась практически мгновенно. Все это было достигнуто классами. Собственно, модуль движения юнита состоит из двух функций, которые вызывают и используют классы. Пока классов два - класс управления через клавиатуру и кдасс собственно движения.Выглядит это дело так:

import bge

#Функция, описывающая способ управления ЛА - вызов класса управления - игрок, бот или онлайн
def control():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    scene = bge.logic.getCurrentScene()
    own = cont.owner
    sensor = cont.sensors[0]
      
    #Создание экземпляра класса и его использование
    if sensor.positive:
        if own['bot'] == 0:
            import ClassGamer
            engine = ClassGamer.control(own)
           
#Функция, описывающая полет ЛА - вращение, ускорение, торможение и прочее - физика
def flight():
    cont = bge.logic.getCurrentController()
    own = cont.owner
    scene = bge.logic.getCurrentScene()
    own = cont.owner
    sensor = cont.sensors[0]
   
    #Создание экземпляра класса и его использование
    if sensor.positive:
        if own['crash'] > 0.2:
            import ClassEngineAir
            engine = ClassEngineAir.control(own)

Сами классы  управления и движения полностью здесь я приводить не буду, поскольку это вещи довольно простые - в прошлых постах их создание было описано. "Шапка" и "окончание2 текста класса одинаковы, различие лишь в "начинке". Для описания движения используется стандартный метод расчета "потребной" скорости движения и вращения. Даже не очень сильно отличается от первой версии проекта. Различия лишь в уборке ненужных проперти, и усовершенствовании "работы" остающихся. к примеру, выкинуты проперти направления движения (значения -1, 0 и +1), выкинуты такие проперти, как sdvigkrylo, krylo, krenNapr и тому подобные. Свойство аэродинамической схемы вообще, индицирующее наличие-отсутствие крыла изменяемой стреловидности, объединилось с wing(-1 - КИС отсутствует, от нуля и больше - уже положение крыла). Предполагаю, что при изменении положения крыла ЛТХ будут меняться единоразово, вызовом данных из текстового файла. В итоге будет выброшена куча проперти, оставшихся будет, конечно, много, но до 60 штук, как было в первой версии, надеюсь, не дойдет. Кроме того, отдельными функциями будет вызываться радар, и, скорее всего, шасси. У меня как-то так сложилось, что шасси представляют собой отдельный блок анимированных деталей, который используется чрезвычайно редко. Наверное, стоит его выделить в отдельную функцию. Радар же по идее, должен во второй версии работать импульсами, включаясь через равные промежутки времени, которые для разных самолетов можно задать разными. Раньше радар работал непрерывно, хотя вроде бы и немного кушал, но если есть возможность разгрузить движок от  лишней работы, да еще и весьма существенно, почему нет? Также отдельной функцией будет, по-видимому, анимирование юнита. Вызываться оно будет при небольшом расстоянии от активной камеры, все остальное время это будут либо ЛОДы, либо единый неанимированный меш.
По поводу пейзажа и небосвода. Три года назад Мартинс Упитис выкладывал примеры своих наработок шейдеров неба, земли, воды и солнца. По каким-то причинам он последнюю версию не довел, а кушает она прилично - около 20 процентов. Поэтому от идеи использовать все и сразу я пока отказался, взяв за основу менее навороченную, но гораздо более быструу версию Упитиса, солнце,  как обычно, немного внеся "своего колорита". Солнце у меня привязано к сфере-скайбоксу,  и может совершать движение по небосводу. Во всяком случае, так задумывается. Само солнце - это лампа типа Sun, к которой я рассчитываю привязать спрайт солнца, но необходимо рассчитать изменение его размеров, так чтобы для наблюдателя они оставались постоянными. Имитации эффектов линзы, которую Упитис очень хорошо продемонстрировал в своем творее, я пока делать не буду. Надо подробно разобрать код шейдера, понять, как это все работает и постараться его реализовать. Кстати, сам Упитис ссылался на работы еще одного человека, который занимался написанием шейдеров, и вообще, прошерстив Интернет, я нашел довольно много литературы по написанию шейдеров, но пока стоят более насущные задачи - доводка физики юнита, создание оверлея и кокпита, отработка уровней детализации. Работы довольно много, идет она не слишком быстро, по причине того, что я пытаюсь зафиксировать в комментариях к коду все свои действия и максимально тщательно писать скрипты, чтобы потом не искать судорожно, вспоминая, в каком скрипте и где я разместил то или иное действие.
Во всяком случае, что-то стало получаться...