воскресенье, 28 февраля 2016 г.

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

Когда-то достаточно давно я видел оба фильма. И их названия очень даже соответствовали моим извращениям по поиску алгоритма генерации блоков ландшафта. Как я уже говорил ранее, совершенно необязательно грузить весь огромный террайн, если в игре ты видишь максимум десятую часть егог (в лучшем случае). Как я писал в предыдущем посте, террайн разбивается на множество квадратных блоков, из которых на активный слой грузятся те, которые в данный момент должны присутствовать под камерой. И вот тут началось самое интересное...
Для начала о "Случай в квадрате 36-80". Фильм был снят в начале 80-х, небезызвестным режиссером Михаилом Туманишвили, который также был автором фильмов  "В зоне особого внимания" и "Ответный ход". Также в свое время он "перековался" в соответствии с 2демократическими веяниями" и снял фильм "Сто дней до приказа". За что был нещадно бит в прессе и на ковре у тогда еще советского руководства Минкультуры. Затем он перековался еще раз и снял относительно недавно еще один патриотический боевик "Ноль седьмой меняет курс". Пересказывать содержание фильмов я не буду, тем более, что "Сто дней" не смотрел - если есть желание - сами найдете. Могу только сказать, что хотя все вышеперечисленные фильмы (за исключением "Ста дней" это агитка наоборот) являются агитками, как сейчас модно "заклеймит" все, не соответствующее либеральному взгляду (анекдот середины 90-х: "В России существуют два взгляда в экономике и политике - один - либеральный, второй - неправильный"), смотреть эти фильмы можно. Если выкинуть на время просмотра из головы некоторые детали. Например, что "новейшая система заправки крыло в крыло" к началу 80-х уже была признана устаревшей, или что для ремонта реактора совершенно необязательна кувалда (хотя кто его знает, может, даже сейчас у нас найдутся умельцы, способные починить Большой Адронный Коллайдер этим инструментом), а также то, что Ту-16, как и заправщик на его базе, с отключенными по причине израсходования топлива, планирует чуть лучше брошенного кирпича, ну и для запуска крылатых ракет с подводной лодки нужно проделать много нудных манипуляций, да и выдающиеся боевые и летные качества СВВП Як-38 вызывают сомнения... Но все же уровень "Случая в квадрате 36-80" будет повыше, чем у многих американских агиток (например лично видел в каком-то боевике эпизод с советским офицером-подводником, носящим почему-то фуражку явно не черного цвета, да еще и с красным околышем (!!!) или играющих в карты советских же подводников в фильме "К-19"). Впрочем, киноляпов можно вспомнить много, но в данный момент интересен мой BGE-ляп.
Итак, мне нужно было сделать запись в текстовый файл типа:

b|30|29|Terrain.2499|110000.0|90000.0|0.0|
b|45|29|Terrain.2498|410000.4375|90000.0|0.0|
b|46|29|Terrain.2497|430000.4375|90000.0|0.0|
b|45|13|Terrain.2496|410000.4375|-230000.515625|0.0|
b|46|13|Terrain.2495|430000.4375|-230000.515625|0.0|

Первые две цифры - индексы квадрата по Х и У. Индексы 0-0 соответствуют самому дальнему левому нижнему блоку ландшафта, а 49-49 - самому дальнему правому верхнему блоку ландшафта. Соответственно координаты по Х и у у этих блоков будут минимальными и максимальными. Далее я задумывал следующую операцию - уже во время игры следовало определение квадрата, в котором находится активная камера. определялся он по формуле:

quadroX = int((int(parentCam.worldPosition[0]/1000)+ 490)/20)
quadroY = int((int(parentCam.worldPosition[1]/1000)+ 490)/20)

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

#Отыскиваем и открываем нужный нам текстовый файл с названиями, координатами и значениями квадратов для блоков ландшафта
    brikeLand = open(bge.logic.expandPath('//Terrain/Terrain_2_/BlockTerrain_2.txt'),'r')
   
    #Дальше по маркерам смотрим, что нам нужно
    for string in brikeLand:
        if string[0] == '#':
            continue
        elif string[0] == 'b':
            tempList = string.split('|')
            X = int(tempList[1])
            Y = int(tempList[2])
            #print(X, Y)
            #Вычисляем индексы квадратов, нужных для вызова
            #Если индексы квадрата по ХУ находятся внутри требуемого диапазона - добавляем название блока ландшафта в список
            #нужных для появления блоков
            if quadroY-2 < Y < quadroY+2 and quadroX-2 < X < quadroX+2:
                    listBlock.append(tempList[3])
                    blockLand = scene.addObject(tempList[3], own)
                    blockLand.worldPosition = [float(tempList[4]), float(tempList[5]), float(tempList[6])]
                   
                    
    brikeLand.close()

Как выяснилось позже, алгоритм был верен. НО! Когда я в файле с террайном создавал этот самый текстовый список с индексами, названиями и координатами, я тупо отсортировал все блоки террейна по возрастанию координат Х и у и записал индексы элементов этиъ списков в файл. ОШИБКА! Во-первых, имеются 50 блоков с одной и той же координатой, во-вторых,  индексы блоков должны быть в диапазоне от 0 до 49. у меня же максимальный индекс был 2499! И в соем террайне НИКАК не могло быть квадрата 36-80 (теперь, думаю понятен смысл первой части названия этого поста).

Потратив три дня на составление скриптов, разбивку ландшафта на блоки и попытку осознать, что я сделал не так, решение с индексами квадратов было найдено. На мой взгляд несколько коряво, но работающее. и, как ни странно, работающее довольно быстро. Если взглянуть на мой террайн, то координаты каждого его отдельного блока находятся в определнном диапазоне, начиная от -49000 до 49000. Как по Х, так и по У. Шаг составляет 20000. Поскольку в процессе присвоения новых центров нарезанным блокам были отклонения, типа, -37020. 08739, то пришлось опять немного изощриться...
 Я создал список такого вида [-49, -47, -45...45, 47, 49] Из 50 чисел от -49 до 49 , с шагом в 2. Это были примерные координаты центров блоков. И ввел для них поправки плюс-минус 1. Я специально опустил четыре нуля позади чисел в списке, чтобы выглядело попроше. Поправки с нулями были уже в коде:

for obj in scene.objects:
    if 'Terrain' in obj.name:
       
        X, Y, Z = obj.worldPosition
       
        try:
            for coordX in listCoord:
                if  (coordX-1)*10000 < X < (coordX+1)*10000:
                    blockX = listCoord.index(coordX)
               
            for coordY in listCoord:
                if  (coordY-1)*10000 < Y < (coordY+1)*10000:
                    blockY = listCoord.index(coordY) 
       
       
            coordText = open(bge.logic.expandPath('//BlockTerrain_2.txt'),'a')
            coordText.write('b|' + str(blockX) + '|' + str(blockY) + '|' + obj.name + '|'+ str(X)+'|'+str(Y) +'|'+ str(Z)+'|'+'\n')
            coordText.close()
        except:
            pass

Часть кода симпортом модулей и стандартных функций со списками я опустил - и так разберетесь. Поясню лишь, что, скажем нижний левый блок имеет координаты в пределах от -48000 до -50000 (то бишь -49-1 и -49+1, если отбросить нули. Точные его координаты и так прописаны в текстовом файле, нам же нужно знать, индексы блока для их записи в текстовый файл. Так вот у блока в нижнем левом углу обе кординаты соответствуют -49 и имеют нулевой индекс в списке [-49...49]. аналогично - для всех 2500 блоков. Отмечу, что скрипт, задействованный в файле террайна в самой игре не используется, мне он был нужен лишь для составления текстового файла, который-то как раз и используется в самой игре. Скрипт получился очень простым и довольно быстрым, даже жаль, что в игре он не нужен. А перед этим была перепробована уйма способов, и все они были отброшены. по сложности и скорости исполнения они, мягко говоря, были попросту не нужны.
Это называется - "ломиться в открытую дверь". И заодно напомнило мне эпизод из итальянской комедии "Операция Святой Януарий". Когда банда американских гангстеров вместе с их итальянскими коллегами пыталась вскрыть витрину с драгоценностями в соборе. Применялось все - хитроумные отмычки, сверхпрочные сверла, зубила. Закончилось все тем, что главный герой фильма с досады швырнул зажигалку в бронестекло... и оно рассыпалось. Теперь ясно и со второй частью названия этого поста.
А теперь немного полюбуемся на результаты. Первый скрин - сгенеренные 9 блоков ландшафта. Камера висит на приличной высоте, и видно, что сгенерились именно те 9 блоков, которые были нужны. Если бы камера находилась на высоте хотя бы 20 км, блоки заняли бы все поле зрения, даже с некоторым запасом. Кстати, как потом до меня дошло, в процессе опробования скрипта с неверными индексами списка, генерились бы блоки по левым и нижнему краю, наподобие буквы L. Очень смешно...

Второй и третий скрины - это небольшой оффтоп - очень давно я скачал свободно распространяемые модели с cайта http://www.sharecg.com/  и посмотрел, как они выглядят в Блендере. вряд ли они будут задействованы в самой игре, по крайней мере в том виде, в котором они есть сейчас, но мысль, что неплохо бы ввести старые машины, полагающиеся не на умные ракеты, а на старые добрые пушки и пулеметы, у меня мелькала не раз.


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

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