вторник, 5 апреля 2016 г.

"Случай в квадрате 36-80 или "Операция Святой Януарий". Вторая серия, однако...

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

import bpy
#print('xxx') # пoтому что камасутра чистой воды
scene = bpy.context.scene

listCoord = [-49,-47,-45,-43,-41,-39,-37,-35,-33,-31,-29,-27,-25,-23,-21,-19,-17,-15,-13,-11,-9,-7,-5,-3,-1,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49]

listIndex = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49]

blockX = 0
blockY = 0

cursorX = 0
cursorY = 0

for obj in scene.objects:
    if '.' in obj.name: # у тебя должно быть другое имя
        obj.select = True
        X, Y, Z = obj.location
        obj.data.name = obj.name
        bpy.ops.object.origin_set(type = 'ORIGIN_GEOMETRY', center = 'MEDIAN')
      
        for coordX in listCoord:
            if (coordX-1)*10000 < X < (coordX+1)*10000:
                blockX = listCoord.index(coordX)
                scene.cursor_location[0] = coordX*10000
              
        for coordY in listCoord:
            if (coordY-1)*10000 < Y < (coordY+1)*10000:
                blockY = listCoord.index(coordY)
                scene.cursor_location[1] = coordY*10000
      
        scene.cursor_location[2] = 0.0
        bpy.ops.object.origin_set(type = 'ORIGIN_CURSOR')
      
        newName = str(blockX) + '_' + str(blockY)
        obj.name = newName
        obj.data.name = obj.name
        print(obj)
        obj.select = False

Смысл всего этогог заключается в том, что каждый блок получает конкретное название, состоящее из слова "блок" и индекса квадрата, в котором он находится. в коде, думаю, ясно, как формируются индексы квадратов по Х и Y. Такое же название получает и меш блока. Теперь не надо создавать текстовый файл с длиннющим списком названий блоков, и их координатами. КООРДИНАТЫ каждого блока ВШИТЫ в его имя. с определенной поправкой, правда. У меня нет блоков с отрицательными значениями типа -35 или -2. Все индексы блоков заключены в интервале от 0 до 49.
А теперь приведем код подгрузки блоков ландшафта в новом варианте. Он пока еще не полон, осталось ввести список блоков района боевых действий для наземки, чтобы та не теряла опору под собой. Я не буду приводить "шапку" и окончание класса для экономии места

        listCoord = [-49,-47,-45,-43,-41,-39,-37,-35,-33,-31,-29,-27,-25,-23,-21,-19,-17,-15,-13,-11,-9,-7,-5,-3,-1,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49]
        listIndex = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49]
       
        #Камера ТВ-прицела - вычисление нужного квадрата ее местонахождения
        targetTV = scene.objects["CameraWorld"]
        targetTVquadroX = int((int(targetTV.worldPosition[0]/1000)+ 490)/20)
        targetTVquadroY = int((int(targetTV.worldPosition[1]/1000)+ 490)/20)
       
        #Индексы "догружаемых" в сцену блоков - для этой камеры хватит и 9
        targetTVblockX = str(listIndex.index(targetTVquadroX))
        targetTVblockY = str(listIndex.index(targetTVquadroY))
        targetTVblockX0 = str(listIndex.index(targetTVquadroX+1))
        targetTVblockY0 = str(listIndex.index(targetTVquadroY+1))
        targetTVblockX1 = str(listIndex.index(targetTVquadroX-1))
        targetTVblockY1 = str(listIndex.index(targetTVquadroY-1))
       
        #Жестко зафиксированный список для 9 блоков - "догружаемых" к камере ТВ-прицела
        targetTVtempIndex = [('block_' + targetTVblockX + '_' + targetTVblockY + '_'),
                             ('block_' + targetTVblockX0 + '_' + targetTVblockY0 + '_'),
                             ('block_' + targetTVblockX1 + '_' + targetTVblockY1 + '_'),
                             ('block_' + targetTVblockX1 + '_' + targetTVblockY + '_'),
                             ('block_' + targetTVblockX + '_' + targetTVblockY1 + '_'),
                             ('block_' + targetTVblockX0 + '_' + targetTVblockY + '_'),
                             ('block_' + targetTVblockX + '_' + targetTVblockY0 + '_'),
                             ('block_' + targetTVblockX1 + '_' + targetTVblockY0 + '_'),
                             ('block_' + targetTVblockX0 + '_' + targetTVblockY1 + '_')]
       
        for block in targetTVtempIndex:
            if block not in scene.objects:
               
                blockTerrain = scene.addObject(block, self)
                blockTerrain.worldPosition[2] = 0.0
               
                blockX = blockTerrain.name.split('_')[1]
                blockY = blockTerrain.name.split('_')[2]
               
                blockTerrain.worldPosition[0] = int(blockX)*20000 - 490000
                blockTerrain.worldPosition[1] = int(blockY)*20000 - 490000
       
        #Вычисление нужного квадрата, центрального блока ландшафта под камерой, целочисленные значения
        #20 - размер блока в км, 490 - поправка сдвиг влево и вниз на "начало отсчета" от левого нижнего угла
        #1000 - чтобы было меньше возни, отбрасываем метры, нас интересуют целые числа в диапазоне от 0 до 49
        activeCam = scene.active_camera
        quadroX = int((int(activeCam.worldPosition[0]/1000)+ 490)/20)
        quadroY = int((int(activeCam.worldPosition[1]/1000)+ 490)/20)
       
        #Вычисление индексов "огружаемых" блоков к камере игрока на ЛА - 25 блоков
        blockX = str(listIndex.index(quadroX))
        blockY = str(listIndex.index(quadroY))
        blockX0 = str(listIndex.index(quadroX+1))
        blockY0 = str(listIndex.index(quadroY+1))
        blockX1 = str(listIndex.index(quadroX-1))
        blockY1 = str(listIndex.index(quadroY-1))
        blockX2 = str(listIndex.index(quadroX+2))
        blockY2 = str(listIndex.index(quadroY+2))
        blockX3 = str(listIndex.index(quadroX-2))
        blockY3 = str(listIndex.index(quadroY-2))
       
        #Жестко зафиксированный список для 25 блоков - "догружаемых" к камере игрока на ЛА
        tempIndex = [('block_' + blockX + '_' + blockY + '_'),
                     ('block_' + blockX0 + '_' + blockY0 + '_'),
                     ('block_' + blockX1 + '_' + blockY1 + '_'),
                     ('block_' + blockX1 + '_' + blockY + '_'),
                     ('block_' + blockX + '_' + blockY1 + '_'),
                     ('block_' + blockX0 + '_' + blockY + '_'),
                     ('block_' + blockX + '_' + blockY0 + '_'),
                     ('block_' + blockX1 + '_' + blockY0 + '_'),
                     ('block_' + blockX0 + '_' + blockY1 + '_'),
                     ('block_' + blockX2 + '_' + blockY + '_'),
                     ('block_' + blockX2 + '_' + blockY0 + '_'),
                     ('block_' + blockX2 + '_' + blockY1 + '_'),
                     ('block_' + blockX2 + '_' + blockY2 + '_'),
                     ('block_' + blockX2 + '_' + blockY3 + '_'),
                     ('block_' + blockX3 + '_' + blockY + '_'),
                     ('block_' + blockX3 + '_' + blockY0 + '_'),
                     ('block_' + blockX3 + '_' + blockY1 + '_'),
                     ('block_' + blockX3 + '_' + blockY2 + '_'),
                     ('block_' + blockX3 + '_' + blockY3 + '_'),
                     ('block_' + blockX0 + '_' + blockY2 + '_'),
                     ('block_' + blockX1 + '_' + blockY2 + '_'),
                     ('block_' + blockX + '_' + blockY2 + '_'),
                     ('block_' + blockX0 + '_' + blockY3 + '_'),
                     ('block_' + blockX1 + '_' + blockY3 + '_'),
                     ('block_' + blockX + '_' + blockY3 + '_')]
                    
        for block in tempIndex:
            if block not in scene.objects:
               
                blockTerrain = scene.addObject(block, self)
                blockTerrain.worldPosition[2] = 0.0
               
                blockX = blockTerrain.name.split('_')[1]
                blockY = blockTerrain.name.split('_')[2]
               
                blockTerrain.worldPosition[0] = int(blockX)*20000 - 490000
                blockTerrain.worldPosition[1] = int(blockY)*20000 - 490000
           
        #Проверка на наличие лишних блоков и их уборка  
        for terrain in scene.objects:
            if 'block_' in terrain.name:
                if terrain.name not in tempIndex:
                    if terrain.name not in targetTVtempIndex:
                        terrain.endObject()

Суть в том, что есть два жестко фиксированных списка - один для камеры игрока на ЛА и вообще активной камеры в игре. Он рассчитан на 25 блоков, чтобы не было "пустот" на горипзонте (скорости-то большие). Второй список  рассчитан на 9 блоков и нужен он для камеры ТВ прицела, передающей изображение на мониторы в кабине. Вроде бы он и лишний, но в то же время могут произойти такие события, когда он понадобится. Обратите внимание на длинные списки переменных для вычисления индексов сопутствующих блоков. Названия, наверное, не вполне удачные, а списки имен блоков я сделал "напрямую", без циклов и перебора значений в списке. Зато это работает и ничто не мешает в будущем это дело изменить. Как вычисляются координаты блоков по Х и Y, исходя из их имен, думаю, тоже понятно. Там просто вводится поправка по причине отсутствия отрицательных значений - так сложилось.
в конце идет проверка на наличие лишних блоков и их удаление. Перед тем, как задействовать этот алгоритм я пытался действовать через замену мешей террайна. Однако он кушал лишние 10 процентов логики, потому что объектов в сцене было ну очень много. При проверке работоспособности данного скрипта выяснилось, что кушает он меньше процента при частоте обновления раз в секунду (против 70 процентов при частоте обновления раз в три секунды). Зарекусь пока говорить о полной и безоговорочной победе, чтоб не сглазить - об этом можно будет уверенно сказать при работающих миссиях и кампаниях. Тем не менее, это явный шаг вперед, по сравнению с предыдущими вариантами. И да, ландшафт имеет 640 килополиков в сумме, вылетов БГЕ пока не отмечено, игровой процесс пока кушает  4 процента.
Картинок пока не будет - поскольку изменения были внутренние, а не внешние.
Теперь необходимо переходить к созданию меню с возможностью выбора оружия и редактирования миссий и кампаний. К тому же меню еще и будет завязано на выбор района БД, погоды и 2декораций", типа городов и авиабаз.
В заключение о декрациях. что-то мне не улыбается добавлять построчно каждый объект на тот же аэродром при его вызове. Гораздо проще сделать вызов группы объектов - ВПП и ее потомков - ангаров, башен и прочего. И произвести замену мешей. Опять будут задействованы имена объектов с "отсечением" лишнего типа _021. И вообще сильно мне полюбилось менять меши, да. Недавно тестил новые эффекты взрывов с помощью замены мешей-кадров, а не вызова плейнов-объектов, как раньше. выяснилось что две сотни одновременных взрывов кушают всего-то 5 процентов логики. Для движка это большое облегчение. Чуть позже напишу и об этом.






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

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