пятница, 21 апреля 2017 г.

И снова "Операция "Святой Януарий". Теория классовой борьбы.

Программист из меня, мягко говоря, средненький, специального образования я на этот счет не получал, так что можног сказать, самоучка.
Некоторые вещи доходят до своего осознания довольно долго, даже не с десятого раза. Вероятно, виной тому зацикленность на практических результатах и более-менее постоянно тем же Питоном я стал заниматься где-то с 2013.
Довольно давно, года уж два как минимум, мне говорили, что осознание дзена классов объектов Питона ведет к экономии ресурсов и выигрышу в использовании БГЕ. Несколько неудачных попыток, в том числе с применением мутации, попытки написания собственных классов в конце концов навели на путь истинный. Опять получилось что-то вроде бросания зажигалки на бронированное стекло в фильме "Операция "Святой Януарий". Все оказалось довольно просто. Определение класса я здесь излагать не буду - есть много статей на эту тему. Изложу свой крайне конкретный и приземленный взгляд на эту тему. И главное, зачем, это надо? 
Сточки зрения дилетанта, меня то есть, проблема вот в чем - в коде постоянно используются проперти вида ["speed"], которые пишутся после священного слова own, либо какого-то другого имени объекта. Если их много, они начинают мешать, а если учесть, что очень многие из них используются редко, либо вообще разово, получается мертвый груз. Хотелось бы их убрать, да нельзя - раз проперти названо - все, уничтожить егог нельзя. Да и от скобочек с кавычками в глазах рябит...
А теперь смотрим, что делает класс на примере создания экземпляра класса (если я правильно написал это название) юнита летательного аппарата.

import bge
import json

scene = bge.logic.getCurrentScene()
cont = bge.logic.getCurrentController()
own = cont.owner

Ind = "UnitAir"+str(id(own))
ArbitrGame = scene.objects["ArbitrGame"]
KEY = getattr(ArbitrGame, Ind)
  
#Часть данных записываем сразу с нулевыми значениями
config = {"WINGS":-1, "Temp_WINGS":-1, "FLAPS":0, "Temp_FLAPS":0, "SLATS":0, "Temp_SLATS":0, "CANOPY":0, "Temp_CANOPY":0,
          "AIRBRAKE":0, "Temp_AIRBRAKE":0, "CHASSY":0, "Temp_CHASSY":0, "ROLL":0, "Temp_ROLL":0, "YAW":0, "Temp_YAW":0,
          "PITCH":0, "Temp_PITCH":0, "ROLLwings":0, "Temp_ROLLwings":0, "avto":0, "Temp_avto":0, "PR":0, "Temp_PR":0,"LockOn":0,"enemy":0,
          "weapon":-1, "Temp_weapon":-1, "crash":1.0, "Temp_crash":1.0, "correctSpeedAngleOfAttack":0.0,
          "levelsDetails":3, "Temp_levelsDetails":3, "angleOfAttack":0.0,"ownType":0,
          "rotatX":0.0,"rotatY":0.0,"rotatZ":0.0,"rollSelf":0, "pitchSelf":0, "yawSelf":0, "antiForce":0.0,
          "massFuel":0.0, "massChild":0.0,"massFuelTank":0.0, "ownAntiForce":0.0001,"lovushki":0,
          "correctRotat":1.0, "correctSpeed":1.0, "slideRotat":0.0, "speedTemp":0.0,"typeShtopor":"NULL",
          "Temp_BK":0 ,"BK":0,"typeSensor":0,"targetType":0, "timerImpulse":0,"sonicBoom":0, "idTarget":["00000"],
          "PuskSbros":0, "Temp_PuskSbros":0, "indexRadarDist":0, "timerShoot":0, "classWeapon":"", "nameWeapon":"",
          "Temp_typeSensor":0, "localTargetList":[], "THREAT":{
          "UnitAir":{'RL':[],'TP':[],'LD':[],'RD':[],'TV':[],'MG':[],'SN':[],'EL':[]},
          "UnitGround":{'RL':[],'TP':[],'LD':[],'RD':[],'TV':[],'MG':[],'SN':[],'EL':[]}},
          "threatWeapon":[], "sbrosInterval":0, "ochered":0, "Temp_ochred":0, "dictWeapon":{}}
   
#Первое обновление - стартовые проперти - управление, сторона, статус, задача
config.update(KEY['startProp'])
   
#Второе обновление
with open(bge.logic.expandPath(KEY['unitPath']), 'r') as directClass:
    config.update(json.load(directClass)["listPropertys"])
   
class air(bge.types.KX_GameObject):
    nameIndex = Ind
    def __init__(self, old_owner):
        for key in config:
            setattr(self, key, config[key])
            #print(key)
       
        #Небольшое примечание - если самолет изображает мишень на стоянке, то он переводится в разряд наземных объектов
        if self.controlUnit == "Statist":
            self.ownType = 1
       
        if self.controlUnit == "Gamer":                   
           
            gamerConfig = ["a_x","a_y","a_z","Temp_a_x","Temp_a_y","Temp_a_z"]
            for key in gamerConfig:
                 setattr(self, key, 0.0)
           
            setattr(self, "timerFuel", 0)
            setattr(self, "colorHUD", 0) 
           
            sensor1 = scene.objects['SENSOR1']
            sensor2 = scene.objects['SENSOR2']
            sensor3 = scene.objects['SENSOR3']
            #Расстановка сенсоров пустышек для отслеживания ориентации в пространстве
            sensor1.setParent(self, False,False)
            sensor1.worldOrientation = self.worldOrientation
            sensor1.localPosition = [0.0, 1.0, 0.0]
            sensor2.setParent(self, False,False)
            sensor2.worldOrientation = self.worldOrientation
            sensor2.localPosition = [1.0, 0.0, 0.0]
            sensor3.setParent(self, False,False)
            sensor3.worldOrientation = self.worldOrientation
            sensor3.localPosition = [0.0, 0.0, 1.0]

            if 'Cockpit' not in bge.logic.getSceneList():
                bge.logic.addScene('Cockpit',1)
                unit = self.unitName + self.unitNation
                typeCockpit = "//Aircraft/" + unit + "/Cockpit_" + unit + "/Cockpit_" + unit + ".blend"
                bge.logic.globalDict["cockpitPath"] = typeCockpit
               
        elif self.controlUnit == "Bot":                   
            setattr(self, "etalonDvig", 0)
            setattr(self, "typeManeur", "")


def mutate(cont):
    air(cont.owner)


До строчки со словом class происходит вскрывание json-файлов и обновление словаря config. В этот словарь уже "вшиты" некоторые стандартные значения будущих атрибутов (ну, тех же свойтв-проперти), которые присущи всем машинам этого класса. Это позволило выкинуть эти свойства из перечисления в файле json, уменьшив его объем и сделав более удобочитаемым. В принципе, словарь config можно было бы втиснуть в тело класса (опять же, не совсем уверен в правильности терминологии), а по-простому говоря - между строчками со словами class и def __init__, но в этом случае объект получит еще один атрибут - этот самый словарь с дублированием всех данных внутри него - оно мне надо? Сами свойства объект получает из словаря config либо циклом-перебором всех ключей и значений из config, либо можно и проще  self.__dict__.update(config). В итоге вместо доставших скобочек и кавычек получаем значения типа self.speed = 50. Что немаловажно, этими свойствами атрибутами можно оперировать - добавляя новые - в коде вы увидите строчки с командой setattr - добавть новый атрибут. Кроме них имеются еще hasattr и delattr. Настоятельно рекомендую эти вещи, и в особенности getattr. Что это такое и с чем их едят, вы найдете сами (я имею в виду новичков и самоучек вроде меня, серьезные программисты и так все знают). С помощью этих команд можно закручивать хитроумные комбинации, получая нужные результаты.
После добавления всех атрибутов следует мутация объекта - его трансформация в новый объект с атрибутам, перечисленными в классе. Это можно сравнить с превращением гусеницы в бабочку или фиксацией проявленной фотографии раствором фиксажа (было дело, работал я с ними, но очень недолго - уже наступала эра цветных пленок, а теперь и они сошли на нет - цифровики вытеснили. Прогресс, одним словом).
Функция фиксации результата - def mutate. Кстати, dron предупреждал, что в примере к БГЕ по созданию класса, разработчики намудрили лишнего - достаточно обойтись лишь этой простенькой функцией.
Теперь процесс создания юнита выглядит так - срабатывает ОДНОРАЗОВО сенсор, дающий команду контроллеру на создание экземпляра класса. После чего включается скрипт поведения юнита - этот уже идет непрерывно. Да, логики стало чуть больше, может потом допру, как сделать одноразовый запуск скрипта создания экземпляра класса.
Уже проврено создание и удаление атрибутов сенсоров в зависимости от его названия, написаны новые функции стрельбы ракетами, пушками, сброса бомб и баков, работают кабины для МиГ-23МФ и БН. Подобрался к сенсорам и поведению ботов. плюс можно начинать отработку самонаведения ракет и противодействия им. Теперь борьбу ведут классы.
На мой взгляд, использование классов сильно упрощает работу и дает прирост в скорости.  Единственно, что надо осознать сразу - создание экземпляра класса и мутация объекта делается ОДИН РАЗ. Моя проблема была именно в том, что я этого не понимал и заставлял объект непрерывно мутировать и пересоздавать класс. Надеюсь, те новички, которые читатют этот текст, избегнут моих ошибок.
Картинок в этот раз не будет, потому как идет процесс переписывания по большей части кода с вырезанием кавычек и скобок. Скорее всего, после восстановления работы сенсоров, РЭБ, самонаведения и ИИ ботов я займусь меню. Что-то мне влом писать json для каждой миссии вручную - лучше один раз напрячься с написанием редактора миссий...

суббота, 1 апреля 2017 г.

Напоминание о своем существовании...

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