Введение.
До этого были цветочки, а ягодки еще впереди. Теперь когда мы знаем кое-что о палитре и об отображении картинок, а самое главное, о преобразовании массива байтов в пиксмапы мы можем продолжить.
Тайлсеты.
Всю информацию о том как хранятся тайлсеты и карты в игре Warcraft I я вынес во вторую часть статьи. И вот почему, тайлсеты для игры хранятся не в картинках. Здесь используется несколько другой подход. Если для отображения картинки было достаточно иметь 2 файла (саму картинку и палитру к ней), то для тайлсета нужно уже обследовать 3 файла. Кстати для тех, кто не знает что такое тайлсет и с чем его едят, рекомендую ознакомиться с другими моими статьями. Для тех же кто знает, я напомню, что тайлсет - это картинка в которой содержатся все тайлы нужные для построения уровня. Тайл в Варкрафт1 имеет размеры 16х16 пикселей, во второй части тайл уже имеет размеры 32х32. Как я уже говорил вторая часть более совершенна в техническом плане, но все ее основы или по крайней мере большинство из них, были заложены в части первой. Итак в игре варкрафт изображения тайлов хранятся в очень интересном виде. Всего в игре 3 тайлсета - forest(лес), swamp(оркский лес) и dungeon(пещеры). Для каждого набора тайлов существуют 3 файла отвечающих за них.
1)мегатайлы
2)минитайлы
3)палитра
Например тайлсет леса(forest) это секции 189(мега), 190(мини), 191(палитра). Начнем с 3- это палитра. Да и что там начинать, про палитру я уже сказал в прошлой части. Здесь лишь стоит заострить внимание на том, что в уровне используеюся не все индексы палитры. Есть одна глобальная палитра она находится в 217 файле. Палитра для тайлсета имеет размер 384 байта. Объединив эти две палитры (глобальную и тайлсетную) можно получить правильные цвета, для отображения.
Мегатайлы. Мммм... как бы это так рассказать попонятнее. Как я уже говорил тайл имеет размер 16х16 пикселей. Так вот каждый тайл состоит из 4 минитайлов.
Минитайл это картинка 8 на 8 пикселей. Из 4 минитайлов сосотоит 1 мегатайл(он же тайл). То есть в секции мегатайлов один тайл определяется 4 словами( 8-мью байтами). Где каждое слово - это ссылка на 1 минитайл. Причем 2 последних бита в слове-это флаги отражений по оси Х и по оси У. Таким образом тайлов в тайлсете столько, сколько размер мегатайлов деленый на 8. Для леса мы имеем, размер секции мегатайлов 2488 байт. Деленая на 8 это дает 311, значит в тайлсете леса(forest) - 311 тайлов. А теперь посчитаем из скольки минитайлов они состоят. Размер секции минитайлов 60800 деленная на 64 ( это 8*8 пикселей ) = 950 минитайлов. Очень порядочная сумма, если учесть, что все они рисовались вручную на компе, да еще "приталены" все друг к другу. Дабы не считать все остальное, сообщу заранее размеры тайлсетов: swamp = 283 и dungeon = 338 тайлов. Алгоритм составления тайлсета очень прост. Мы смотрим 4 слова в мегатайле, находим соответствующие им 4 минитайла и объединяем их в 1 конечный тайл, который и записываем в тайлсет, потом берем очередные 4 слова из мегатайловой секции. В коде это выглядит так:
Function make_tileset:Int(image:Byte Ptr , width:Int , mega:TBank , mini:TBank , numtiles:Int)
Local i:Int, x:Int , y:Int Local tiles:Short[MINI_PER_TILE]
' здесь будет лежать raw-картинка минитайла Local mini_raw_image:Byte Ptr = MemAlloc( HALF_TILE_SIZE * HALF_TILE_SIZE ) ' здесь будет pixmap минитайла Local mini_pixmap:TPixmap = CreatePixmap( MINI_TILE_SIZE, MINI_TILE_SIZE, PF_RGB888 ) ' здесь будет храниться собранный тайл из минитайлов Local tile_pixmap:TPixmap = CreatePixmap( TILE_SIZE, TILE_SIZE, PF_RGB888 )
' открываем банк как поток Local mega_stream:TBankStream = TBankStream.Create( mega ) Local counter:Int = 0 While( Not mega_stream.Eof() ) ' считываем информацию о 4 минитайлах из потока мегатайлов For i = 0 Until MINI_PER_TILE tiles[ i ] = mega_stream.ReadShort() Next
For i = 0 Until MINI_PER_TILE ' находим индекс нужного минитайла Local index:Short = (tiles[ i ] & $FFFC) Shl 1 Local flipx:Short = tiles[ i ] & 2 Local flipy:Short = tiles[ i ] & 1 ' находим raw-минитайл DecodeTile( mini_raw_image , mini.buf() , index , flipx , flipy ) ' преобразуем его в картинку, а точнее в pixmap mini_pixmap = create_pixmap_from_raw( MINI_TILE_SIZE , MINI_TILE_SIZE , mini_raw_image , pallete.Buf() )
' собираем тайл из минитайлов tile_pixmap.Paste( mini_pixmap, (i Mod 2) * MINI_TILE_SIZE, (i / 2) * MINI_TILE_SIZE)
Next
' запихиваем его в тайлсет tileset_pixmap.Paste( tile_pixmap, (counter Mod TILE_PER_ROW) * TILE_SIZE, (counter / TILE_PER_ROW) * TILE_SIZE)
counter:+1 Wend Return counter End Function
Здесь я все прокоментировал, стоит отметить что банк я открыл как поток, потому могу и использовать конструкцию while(not stream.eof())-wend. Все достаточно просто. Таким образом я собрал все 3 тайлсета из игры. Смотрите исходники там все подробно написано.
Карты.
Теперь о том как хранятся карты. Вообще все карты в первом варкрафте квадратные и имеют всегда один и тот же размер 64х64 тайла. Что так же помогло вычислить их по размеру :) каждый тайл в карте шифруется словом(2 байта) значит 64*64*2 = 8192 байт должна занимать карта. Фильтруем по размерам и опачки находим нужные секции. Надо сказать что карты из них, только секции с нечетными номерами, те что с четными это видимо карты для fog of war(тумана войны). Мэпвьвер получился настолько элементарным и простым, что я даже не привожу здесь его исходный код. Но в архиве, что будет под статьей, вы найдете и исходные коды всех файлов и ехе-шники, а так же тайлсеты. Спасибо за внимание. ;)
http://dimanche.ucoz.ru/war1.ZIP
ссылки по теме:
|