Программист из меня, мягко говоря, средненький, специального образования я на этот счет не получал, так что можног сказать, самоучка.
Некоторые вещи доходят до своего осознания довольно долго, даже не с десятого раза. Вероятно, виной тому зацикленность на практических результатах и более-менее постоянно тем же Питоном я стал заниматься где-то с 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 для каждой миссии вручную - лучше один раз напрячься с написанием редактора миссий...
Некоторые вещи доходят до своего осознания довольно долго, даже не с десятого раза. Вероятно, виной тому зацикленность на практических результатах и более-менее постоянно тем же Питоном я стал заниматься где-то с 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 для каждой миссии вручную - лучше один раз напрячься с написанием редактора миссий...
А есть ведь еще такая удобная штука как наследование...
ОтветитьУдалитьДа, возможностей у класса много. Кое-что почитывал по этому, но пока не "вкурил". Плюс спешно переделываю код - вчера чистил ИИ от остатков скобочек с кавычками. Когда-то с подсказки dron-а еще применял @classmethod, но пока временно убрал. Плюс в пробах был единоразовый вызов метода в нутри самого класса - тоже убрал, пока не нужен. Полиморфизм, наследование, классовый и статический методы - много чего еще надо осваивать...
ОтветитьУдалить