![]() |
Добро пожаловать, гость ( Вход | Регистрация )
![]() ![]() |
![]() |
LexSafonov |
![]()
Сообщение
#21
|
Member ![]() ![]() Группа: Authorized Сообщений: 21 Регистрация: 29-October 20 Пользователь №: 18,034 Спасибо сказали: 1 раз(а) ![]() |
|
-=CHE@TER=- |
![]()
Сообщение
#22
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
А функция fwrite() жаловаться не будет? У меня же все данные в основном в конец дозаписываются Какая разница куда у тебя данные записываются, если файл открыт для записи? Если ты помимо записи что-то читаешь или по файлу туда-сюда ходишь, то сделай "w+b".И ещё ты делаешь главную ошибку: вместо того чтобы попробовать и посмотреть как будет работать, ты задаёшь вопрос. А так у тебя уйдёт 1 минута чтобы проверить или 5 чтобы спросить на форуме. Если бы жёсткий диск форматировал или человека в космос запускал - переспрашивать и перепроверить было бы логично для надёжности, ибо последствия могут быть необратимыми. А смысл это здесь делать? Добавлю: я твой код не смотрел, так что если ты несколько файлов в один зачем-то пишешь, тогда тебе нужно первый создавать с "w+b", а остальные уже с добавлением. |
LexSafonov |
![]()
Сообщение
#23
|
Member ![]() ![]() Группа: Authorized Сообщений: 21 Регистрация: 29-October 20 Пользователь №: 18,034 Спасибо сказали: 1 раз(а) ![]() |
Какая разница куда у тебя данные записываются, если файл открыт для записи? Если ты помимо записи что-то читаешь или по файлу туда-сюда ходишь, то сделай "w+b". И ещё ты делаешь главную ошибку: вместо того чтобы попробовать и посмотреть как будет работать, ты задаёшь вопрос. А так у тебя уйдёт 1 минута чтобы проверить или 5 чтобы спросить на форуме. Если бы жёсткий диск форматировал или человека в космос запускал - переспрашивать и перепроверить было бы логично для надёжности, ибо последствия могут быть необратимыми. А смысл это здесь делать? Добавлю: я твой код не смотрел, так что если ты несколько файлов в один зачем-то пишешь, тогда тебе нужно первый создавать с "w+b", а остальные уже с добавлением. Ладно, исправлю, не ругайся только ![]() |
-=CHE@TER=- |
![]()
Сообщение
#24
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Ладно, исправлю, не ругайся только Я не ругаюсь, у меня просто голос такой. Кстати, вспомнился, похожий случай 13 лет назад. Время летит - офигеть можно.![]() Смысл в том, что вопрос нужно задавать, когда ты уже сам всё перепробовал и упёрся в тупик и не понимаешь что делать дальше. Или сделал так-то, но сомневаешься и хочешь узнать можно ли сделать лучше. И тому подобные случаи. Я ж говорю - я готов помочь, мне не жалко. Просто человек когда сам до чего-то доходит, то лучше усваивает материал: лучше запоминает, плюс в схожей ситуации попробует так же сделать - решение уже будет само напрашиваться. |
LexSafonov |
![]()
Сообщение
#25
|
Member ![]() ![]() Группа: Authorized Сообщений: 21 Регистрация: 29-October 20 Пользователь №: 18,034 Спасибо сказали: 1 раз(а) ![]() |
Так, решил своим же инструментом попробовать извлечь все спрайты из игры, и наткнулся на пару стрёмных багов. А именно:
- декомпановщик пару файлов неправильно раскомпановывает(COLONIST.B16 и SYNTH.B16), причину пока не понял, вроде бы какие то файлы создаёт на выходе, при чём полностью рабочие, но пару раз показывает ошибку на то, что не может создать файл. На досуге разберусь в чём дело. - декомпрессор неправильно декомпрессует секции в файле BURSTER.B16. Позже обнаружил, что в одной секции есть непожатый спрайт, при чём в конце. Надо будет тоже исправить. Пока извлекал ресурсы, нашёл неиспользуемые спрайты перезарядки для огнемёта ![]() ![]() http://i.piccy.info/i9/7c1602f3294a292c00f...403118/D021.png http://i.piccy.info/i9/599c75347dafe5dff29...403118/D022.png Это видимо, то, что я нашёл не так давно в анимационных структурах(поле, которое игнорится). Есть ещё несколько интересных спрайтов у взрослого чужого (файл WARCEIL.B16), складывается ощущение, что этот типаж мог не только лазить по потолку, но и залазить на этот самый потолок с пола(И видимо обратно и неоднократно). В оригинальной игре ни разу не видел подобного. Пример: http://i.piccy.info/i9/981499a7785b2690d5a...403118/D040.png http://i.piccy.info/i9/a5783dfe48405e2edf3...403118/D041.png http://i.piccy.info/i9/f4ec6a3d75c3b5a9ff5...403118/D042.png http://i.piccy.info/i9/a6e3b839e820d3e2d53...8/63603D043.png Параллельно решил пробежаться по формату MAP и сопоставить его с форматом моделек. Карта трёхмерная, видимо так же, как и модель, состоит из квадов и вершин. Но устройство немного другое. Содержит в себе такие секции: MAP0 - геометрия карты(и не только) D000\1\2\3 - видимо динамические объекты. По первой карте я пока только понял, что это двери.(Два типажа, первая дверь - на старте и в конце уровня, вторая - промежуточная, везде одна и та же модель применяется). Формат как у обычных моделей. Текстурная сетка для карты содержится в B16 файлах карты рядом с текстурой. Секция BX00. По поводу устройства формата скриншот для наглядности: ![]() ![]() Там есть 32 байта непонятные поля. Пока не понял, какие значение могут отвечать за общее кол-во вершин. Если брать по 4 байта на длину, то значение получается какое то огромное(несколько миллионов, по факту всего несколько сотен) Вершины я пробовал обнулять, чтобы посмотреть реакцию игры - работает, геометрию начинает искривлять местами. |
-=CHE@TER=- |
![]()
Сообщение
#26
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Пока извлекал ресурсы, нашёл неиспользуемые спрайты перезарядки для огнемёта (...) Есть ещё несколько интересных спрайтов у взрослого чужого (файл WARCEIL.B16), складывается ощущение, что этот типаж мог не только лазить по потолку, но и залазить на этот самый потолок с пола(И видимо обратно и неоднократно). Перед выпуском зачастую забывают вычистить рабочие файлы или оставшиеся неиспользуемыми. Иногда какую-то вещь до самого последнего момента пытаются починить или вставить в игру, но из-за ошибок или проблем которые она создаёт в итоге перед самым выпуском просто в коде отключают. А ресурсы, конечно, остаются.В оригинальной игре ни разу не видел подобного. Там есть 32 байта непонятные поля. Пока не понял, какие значение могут отвечать за общее кол-во вершин. Если брать по 4 байта на длину, то значение получается какое то огромное(несколько миллионов, по факту всего несколько сотен) Возможно, там дробные числа с фиксированной точкой, т.е. когда первые два байта это целая часть, а вторые - дробная часть после запятой. Бывают и просто дробные числа в 4 байта (float), но т.к. игра портировалась на консоли, а с дробными часлами там всё тогда было очень плохо (тупо не было), то я поставил бы всё же на дробные с фиксированной точкой. Хотя, конечно, на PC могли что-то моменять, но тут смотреть нужно. Чтобы понять о чём речь рекомендую вот эту статью - она про другую игру, но общее представление о том как выкручивались в то время понять можно.Вершины я пробовал обнулять, чтобы посмотреть реакцию игры - работает, геометрию начинает искривлять местами. Когда работаешь со старыми играми или программами зачастую это не столько дизассемблирование, сколько археология получается, ибо некоторые решения в форматах и общей архитектуре обоснованы ограниченными возможностями оборудования того времени. |
LexSafonov |
![]()
Сообщение
#27
|
Member ![]() ![]() Группа: Authorized Сообщений: 21 Регистрация: 29-October 20 Пользователь №: 18,034 Спасибо сказали: 1 раз(а) ![]() |
Так, продолжаю свои разборы формата карты. Ещё раз решил перепроверить себя, сопоставил снова с форматом моделей. Нашёл кажись квады:
![]() ![]() Формат квадов у моделей такой: 0x04 - индекс первой точки. LITTLE-ENDIAN 0x04 - вторая точка 0x04 - третья точка 0x04 - четвёртая точка. может быть -1 (0xFFFFFFFF), тогда это треугольник и надо продублировать третью точку. 0x02 - индекс текстуры квада (см. формат PICKGFX.BND дальше) 0x02 - некий параметр. может быть 11, тогда текстуру надо перевернуть по Y (?). может быть 128. неизвестно зачем. Как я понял, что это квады: в файле есть индексы FFFFFFFF. По ним я начал тупо идти наверх в файле, пока не упёрся в место, отмеченное на скриншоте. Логика рушится на 4-х байтах отмеченных синим цветом. В цепочке байт - 00 FA 00 08 00 25 00 00 00 FA 00 08 - не может быть индексом, больно число большое. 00 25 00 00 - вполне тянет на индекс(9472) Под описание подходят вершины, но их кол-во чёт больно большое(25 тысяч примерно, если общее кол-во разделить на 4, по формату вершины). На счёт дробных чисел, в формате моделей применяются целые значения. Скорее всего в формате карт то же самое... |
LexSafonov |
![]()
Сообщение
#28
|
Member ![]() ![]() Группа: Authorized Сообщений: 21 Регистрация: 29-October 20 Пользователь №: 18,034 Спасибо сказали: 1 раз(а) ![]() |
Обновляю данные по поводу формата карт.
![]() ![]() Вообщем по поводу вершин и квадов был прав, но не допирал каким образом всё расчитывается, т.к. одно место меня упрямо сбивало с толку. После поля с квадами есть поле, в котором полно байт FFFFFFFF, но отвечает оно за что то другое, пробовал обнулять, изменений на карте не заметил(либо я не понял, что поменялось) Теперь небольшое объяснение. Кол-во вершин и квадов забито в файле порядком Little-Endian(в обратном). Вершины: C0 2F - В little-endian это 12224, умножаем на 8. 8 байт один элемент - 6 байт на 3 координаты XYZ и 2 байта пустых, как я понял, это сделано, чтобы сделать данные кратными двойке. После применения данной формулы как раз приходим точно в начало поля с квадами Квады: 02 2С - В little-endian это 11266, умножаем на 20. 20 байт один элемент - 16 байт на 4 индекса точек и 4 байта с информацией о текстурной сетке и режиме отображения. Данные расчёты я проверил на трёх разных файлах с картами, всё сходится. Для извлечения геометрии вполне этого может хватить, но карта будет везде светлая, т.к. пока не ясен принцип работы света - вроде бы есть какие то источники, но динамические они или нет - не ясно. По мере выяснения буду дополнять информацию о формате карт. |
LexSafonov |
![]()
Сообщение
#29
|
Member ![]() ![]() Группа: Authorized Сообщений: 21 Регистрация: 29-October 20 Пользователь №: 18,034 Спасибо сказали: 1 раз(а) ![]() |
И так, сейчас будет хороший такой пост по разбору формата карт.
Для начала, разобранный заголовок на данный момент: ![]() ![]() Текущее описание заголовка формата карт 0x04 46 4F 52 4D FORM 0x04 - размер данных файла в байтах, BIG-ENDIAN 0x04 - количество карт в файле текстом.(обычно нуль, т.к. больше одной карты в файлах не встречал) - дальше идет информация о геометрии карты и её содержании, а именно: размер содержимое комментарий ------------------------------------------------------------------------------------------------------------------------- 0x04 - Название карты, текст 0x04 - размер данных карты, BIG-ENDIAN(прямой порядок байт) 0х02 - Кол-во вершин?.LITTLE-ENDIAN(обратный порядок байт) Формула - значение этих двух байт умножить на 8 (6 байт на 3 точки + 2 байта нули) 0x02 Кол-во квадов(прямоугольников).LITTLE-ENDIAN (обратный порядок байт). Формула - значение этих 2-х байт умножить на 20 (16 байт индексы точкек и 4 байта информация) 0x02 ------------ Длина "прямоугольника" мини карты(физ. движка)(Little-Endian) 0х02 ------------ Ширина "прямоугольника" мини карты(физ. движка)(Little-Endian) Формула для этих байт = умножить длину на ширину и полученое значение умножить на 16 16 байт описывают одну ячейку. Пока что не расшифровал все значения одной ячейки. Эти поля что то описывают для физического движка, осязаемость, высота. Попробовал подменить пару блоков данными от "неосязаемых", и получилось - игра убирает осязаемость и с миникарты убирает характерную "точку". Исходя из этого можно предположить, что игра с трёхмерной картой практически не взаимодействует. 0х06 - Непонятные значения 0х02 - Поле описания монстров, которые просто спавнятся. Формула = кол-во элементов умножить на 20(20 байт на одного монстра) 0х02 - Поле описания пикапов, формула = кол-во элементов умножить на 8 0х02 - Поле описания "коробок" и подобных объектов(свитчей, бочек) Формула = кол-во элементов умножить на 16 0x16 - Непонятные значения. Теперь отдельно по форматам данных. На самом первом скриншоте вершины отмечены. - формат вершины: размер содержимое комментарий ------------------------------------------------------------------------------------------------------------------------- 0x02 - координата X (signed, LITTLE-ENDIAN, short) 0x02 - координата Y 0x02 - координата Z 0x02 - неизвестное значение, вроде бы всегда 0 Следующий скриншот показывает "границу" - конец квадов и начала "блоков физ. движка". ![]() ![]() - формат прямоугольника: размер содержимое комментарий ------------------------------------------------------------------------------------------------------------------------- 0x04 - индекс первой точки. LITTLE-ENDIAN 0x04 - вторая точка 0x04 - третья точка 0x04 - четвёртая точка. может быть -1 (0xFFFFFFFF), тогда это треугольник и надо продублировать третью точку. 0x02 - индекс текстуры квада 0x02 - некий параметр. Видимо что то по отображению. Формат одного блока физ. движка пока не расшифровывал, подозреваю, что там есть что то по осязаемости, высоте, может быть какие то индексы для логики на карте. Как и писал выше - я пробовал подменять данные от блоков, которые неосязаемые, данными от осязаемых и наоборот - эффекты есть и весьма ожидаемые.(Как и на автокарте) Пока не ясен ещё один нюанс - какая система применяется в игре, пол-потолок(как в играх типа дум\дюк), или же блоки полностью трёхмерные. Но ясно одно точно - трёхмерная карта это чисто декорация. Очевидно связано с тем, чтобы не делать сложный физический движок и все ресурсы пустить на рендеринг(Если посчитать кол-во квадов на первой карте, то там уже 11 тысяч штук!). Следующий скриншот показывает поле с описанием монстров ![]() ![]() Оранжевым цветом помечены лицехваты, светло-сиреневым помечены монстры, которые не заспавнились на карте, серым помечены взрослые чужие. Возможно, монстры, отмеченные светло-сиреневым, зависят как то от уровня сложности, но это только предположение. Формат данных одного монстра: 0х01 - Тип атаки?(Может быть и тип монстра) 0х01 - X координата?(Весьма странно описаны координаты, максимум 255? fixed числа?) 0х01 - Y координата?(Тем не менее монстра они двигают) 0х01 - Z координата?(Видимо FF обозначает отспавнить на полу) 0х02 - Кол-во хелс-поинтов(видимо в фиксед числе) 0x01 - Какой объект спавнит при смерти(индекс) 0х01 - Непонятный байт, если больше нуля, то монстра не спавнит 0х04 - Непонятные байты, не ясен эфффект от изменения. 0х02 - Непонятные байты, изменения не заметны(возможно угол поворота при спавне) 0х02 - Скорость перемещения объекта(монстра). 0х04 - Непонятные байты, при изменении не ясен эффект. Один и тот же монстр может иметь разные значения Ну и вдовесок к разбору монстров видос, где я изменил параметры лицехвата, который попадается на старте: https://www.youtube.com/watch?v=NNl59yII4Ys По поводу типажа монстра - пробовал подменить значение 02 на 08 - спавнит чужого, однако при выставлении значения 03 спавнит монстра, у которого не рендерятся спрайты, на вид атака похожа на ту, что у грудолома. Следующий скриншот показывает 2 поля - поле с пикапами и поле с "коробками" - спец. объектами(бочками, коробками, свитчами). ![]() ![]() Формат данных одного пикапа(По всей видимости 8 байт): 0х01 - Координата X? 0х01 - Координата Y? 0х01 - Тип пикапа, индекс Типажи: 0 - пистолет 1 - дробовик 2 - пульсатор 3 - огнемёт 4 - смарт-ган 5 - не используется 6 - сейсмо-заряд 7 - батарея(для свитчей, использующих тип "батарея") 8 - очки ночного видения 9 - пистолетная обойма 10 - патроны для дробовика 11 - обойма для пульсатора 12 - подствольная граната для гранатомёта 13 - топливо для огнемёта 14 - обойма для смарт-гана 15 - идентификационная карта(которая вылетает из колонистов\охранников) 16 - автокарта 17 - гипер-пак 18 - броня (acid west), видимо защищает от кислоты 19 - броня простая 20 - аптечка 21 - бинт(+1 хелс) 22 - защитные ботинки 23 - адреналин 24 - бинт? 25 - солдатская лампа Типажи выше можно поднять, следующие неподнимаемые(видимо использовали для отладки) 26 - гильза от дробовика 27 - гильза от пистолета Значения выше 27(28 и далее), стабильно приводят к вылету. 0х01 - кол-во, которое выдаёт пикап, при поднятии 0х01 - какой то множитель для предыдущего значения 0х01 - непонятное значение, везде вроде нуль 0х01 - видимо Z координата 0х01 - тоже какое то кол-во для пикапа, непонятно как работает. Формат "коробок"(видимо 16 байт), один нюанс, в поле коробок описываются не только коробки. 0х01 - Координата X? 0х01 - Координата Y? 0x01 - Тип "коробки"(Видимо и типаж и модель одновременно) Есть такие типы: 19 - коробка, которую нельзя взорвать 20 - обычная коробка, которую можно взорвать 21 - пустой объект(на данный момент), может быть свитч для уровней на корабле 22 - ещё один мелкий свитч, отличие внизу у модели(нарисована молния) 23 - бочка, взрывается. 24 - мелкий свитч без молнии 25 - "двойная коробка"(две коробки друг над другом, которые можно взорвать) 26 - широкий свитч с молнией 27 - широкий свитч без молнии 28 - пустой объект, который можно прострелить 29 - пустой объект, который можно прострелить, что то спавнит при смерти 30 - обычная коробка, которую можно взорвать 0х01 - что объект заспавнит при смерти 00 - видимо пикап, 02 - видимо монстр 0х02 - пока не понял, что данные два байта делают 0х01 - видимо индекс объекта, который надо заспавнить 0х01 - видимо индекс второго объекта, который надо заспавнить 0х08 - несовсем понятные значения, два последних байта каким то образом влияют на скорость, с которой вылетают заспавненые объекты На последок опишу последний эксперимент. Я решил выяснить - зависит ли как то набор монстрия от номера уровня, т.е. не забито ли это в движке. Для этого я файл первого уровня подменил файлом от шестого. Результат меня приятно удивил - монстры заспавнились как положено, и остальные данные заработали тоже как нужно. Однако не заработали звуки тех монстров, которых на первом уровне не должно быть. Но я уже понял причину - это связано с тем, что ПК вариант игры подгружает набор звуков из текстовых файлов в папке SFX. Тексты миссий и их скрины остаются от первого уровня. Пока что на данный момент это всё. Пока буду продолжать дальше разделять границы полей и примерно описывать эффекты, которые они делают. |
-=CHE@TER=- |
![]()
Сообщение
#30
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Нифига себе сколько. Кстати, на первом скриншоте опечатка - XYX, вместо XYZ.
Прочитал и, пока что, только две мысли: 0х01 - X координата?(Весьма странно описаны координаты, максимум 255? fixed числа?) Может оно тут как в Minecraft? Когда уровень делится на условные кубы и в данном месте задаются координаты куба, в середине которого будет создаваться монстр или предмет.0х01 - Y координата?(Тем не менее монстра они двигают) 0х01 - кол-во, которое выдаёт пикап, при поднятии А это случайно не одно значение 0x02 (word, 2 байта) в LITTLE-ENDIAN?0х01 - какой то множитель для предыдущего значения |
LexSafonov |
![]()
Сообщение
#31
|
Member ![]() ![]() Группа: Authorized Сообщений: 21 Регистрация: 29-October 20 Пользователь №: 18,034 Спасибо сказали: 1 раз(а) ![]() |
По поводу опечатки, да.... Я заметил это в самый последний момент. Ладно, суть то не больно меняет)))
По поводу координат, скорее всего да, система очень похожая, т.к. один элемент - это 1 блок, он же чётко рисуется на автокарте. Скорее всего в координатах указываются X и Y "блока", а остальные координаты "дорассчитываются" в процессе. Но это пока чисто предположения. Далее по поводу значений пикапов. Нет, это два разных значения, т.к. я пробовал менять их. Не ясна логика работы "множителя". Я смотрел пару пикапов - пикап пистолетной обоймы и пикап патронов для дробовика. У пикапа пистолетных патронов такие значения 0F 01, что значит - 15 1(15 патронов), а у пикапа патронов дробовика там 0A 01 - 10 1(10 патронов). Если читать в по 2 байта, то больно большое значение получается.... Возможно множитель работает как то от уровня сложности. Ещё одна проблема в том, что я очень туго соображаю по рисованию графики в С++. Даже если найду все поля, то для написания простенького редактора карт, надо будет применять что то из 3д.... У меня на простой декомпрессор спрайтов чуть ли не неделя ушла) |
-=CHE@TER=- |
![]()
Сообщение
#32
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
Ещё одна проблема в том, что я очень туго соображаю по рисованию графики в С++. Даже если найду все поля, то для написания простенького редактора карт, надо будет применять что то из 3д.... У меня на простой декомпрессор спрайтов чуть ли не неделя ушла) Вот, нашёл - слегка поправленные мной исходные коды простенького 3D-лабиринта на OpenGL (если найти выход, то игра начнётся заново). Автор Stan Melax - см. комментарии сверху. Для работы программы необходим в том же каталоге что и программа файл maze.bmp с рисунком 128x128 в 24-х битах - это текстура стен, любой файл туда положи указанного размера и глубины цвета.Можешь разбираться как работает и переделывать под себя - будет с чего начать. Обрати внимание, что для сборки исполняемого файла тебе нужно указать линковку библиотек "GLU32.dll" и "OpenGL32.dll" помимо стандартных Windows'ых. maze.c CODE /* * OpenGL Maze Example * * by Stan Melax melax@bioware.com * * In this little demo the player navigates through a simple maze * using the arrow keys. The maze is defined by a 2D array where * each element in the array indicates solid or empty space. This * program wraps polygon (quad) walls around the solid space and * disallows the player to navigate into solid space during the demo. * Note that all the walls are limited to being 90 degrees to each * other - there are no "angled" features. The purpose of this * sample program is to show a beginning 3D game programmer some * things they can do. * * One other cool thing that this program does is that it constucts * a single quad strip to draw all the walls by doing a recursive * depth first search on the maze array data. * * Permission to execute this program, or look at the code is only * granted to those who do not like to sue other people :-) * Some of the window setup code was stolen from a simple Cosmo example. * OpenGL is a trademark of SGI. */ #include <assert.h> #include <windows.h> #include <GL/gl.h> #include <GL/glu.h> #include <GL/glext.h> #include <math.h> #define IDM_APPLICATION_EXIT (101) #define IDM_APPLICATION_TEXTURE (102) #define IDM_APPLICATION_BANK (103) HMENU hMENU; HWND hWND; HDC hDC; HGLRC hGLRC; int enablebank=0; int enabletexture=0; #define MAZE_HEIGHT (16) #define MAZE_WIDTH (16) // unfortunately due to the way the polygon walls are generated there // are restrictions on what the wall/maze data can look like. See below. char mazedata[MAZE_HEIGHT][MAZE_WIDTH + 1] = { "****************", "* * *", "* * *** * * *", "* ** * ** * * *", "* * * *", "********** *** *", "* * *", "* ***** *** ****", "* * * * *", "* ******* *", "* * * * * *", "* ***** **** * *", "* * * *", "** ** **** *** *", "* * * * *", "************* **", }; int wall(int x, int y) { // true if the region at x,y is solid space that // should be surrounded by other solid space or polygon walls return((x >= 0) && (y >= 0) && (x < MAZE_WIDTH) && (y < MAZE_HEIGHT) && (mazedata[y][x] != ' ')); } /* * The next group of routines implements the depth-first search * that is used to wrap a quad strip around all the solid regions of the * maze. Note this enforces certain topological restrictions on the * maze data itself. There cant be any loops, clusters, or floating pieces * existing by themselves. The solid nodes must be a tree (graph theory speak). * */ int onopen(int x, int y) { // returns whether node x,y is on the depth-first search open list assert(wall(x, y)); return(mazedata[y][x] == '*'); } void closeit(int x, int y) { // puts node x,y on the closed list assert(wall(x, y)); assert(onopen(x, y)); mazedata[y][x] = 'X'; } int neighbor(int x, int y, int w, int *nx, int *ny) { // if x,y has a neighbor in direction w then returns true switch (w) { case 0: *nx = x-1; *ny=y; break; case 1: *nx = x; *ny=y+1; break; case 2: *nx = x+1; *ny=y; break; case 3: *nx = x; *ny=y-1; break; default: assert(0); } return(wall(*nx, *ny)); } int diagnol(int x, int y, int w, int *nx, int *ny) { switch(w) { case 0: *nx = x-1; *ny=y-1; break; case 1: *nx = x-1; *ny=y+1; break; case 2: *nx = x+1; *ny=y+1; break; case 3: *nx = x+1; *ny=y-1; break; default: assert(0); } return(wall(*nx, *ny)); } // normal vectors for each wall direction float nrml[4][3] = { { -1.0f, 0.0f,0.0f}, { 0.0f, 1.0f,0.0f}, { 1.0f, 0.0f,0.0f}, { 0.0f,-1.0f,0.0f}, }; // default color for each wall direction float clr[4][3] = { { 1.0f, 0.0f,0.0f}, { 0.0f, 1.0f,0.0f}, { 0.0f, 0.0f,1.0f}, { 1.0f, 1.0f,0.0f}, }; static float texcoordX = 0.0f; int dw(int x, int y, int p) { // the recursive draw wall routine that extends the quad strip int w = p; // w is the current wall direction being considered closeit(x, y); do { int x2, y2; if (neighbor(x, y, w, &x2, &y2)) { if (onopen(x2, y2)) { dw(x2,y2,(w+3)%4); } else { assert(((w + 1) % 4) == p); // or a loop or cluster exists return(1); } } else { float fx; float fy; if (diagnol(x, y, w, &x2, &y2) && onopen(x2, y2)) { dw(x2,y2,(w+2)%4); } glNormal3fv(nrml[w]); // useful iff using lighting glColor3fv(clr[w]); texcoordX = (texcoordX < 0.5) ? 1.0f : 0.0f; fx = (float) x + (((w == 1) || (w == 2)) ? 1.0f : 0.0f); fy = (float) y + (((w == 0) || (w == 1)) ? 1.0f : 0.0f); glTexCoord2f(texcoordX, 0.0f); // useful iff using textures glVertex3f(fx, fy, 0.0f); glTexCoord2f(texcoordX, 1.0f); glVertex3f(fx, fy, 1.0f); } w++; w %= 4; } while (w!=p); return(1); } int drawwalls(void) { int dl; glNewList(dl = glGenLists(1), GL_COMPILE); glBegin(GL_QUAD_STRIP); glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(0.0f, 0.0f, 1.0f); dw(0, 0, 0); glEnd(); glEndList(); return(dl); } //----------------------------------------------- int drawtop(void) { // draws the top and the bottom of the maze // which is useful for overhead views // The display list created here is only used for the intro // spinning bit. No optimizations such as using quad strips // or combining adjacent polygons are done here. int x, y, dl; glNewList(dl = glGenLists(1), GL_COMPILE); glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_QUADS); for (y = 0; y < MAZE_HEIGHT; y++) { for (x = 0; x < MAZE_WIDTH; x++) { if (wall(x, y)) { // bottomside: glVertex3f(x+0.0f ,y+0.0f ,0.0f ); glVertex3f(x+0.0f ,y+1.0f ,0.0f ); glVertex3f(x+1.0f ,y+1.0f ,0.0f ); glVertex3f(x+1.0f ,y+0.0f ,0.0f ); // topside: glVertex3f(x+0.0f ,y+0.0f ,1.0f ); glVertex3f(x+1.0f ,y+0.0f ,1.0f ); glVertex3f(x+1.0f ,y+1.0f ,1.0f ); glVertex3f(x+0.0f ,y+1.0f ,1.0f ); } } } glEnd(); glPopAttrib(); glEndList(); return(dl); } #define STARTING_POINT_X (1.5f) #define STARTING_POINT_Y (1.5f) #define STARTING_HEADING (90.0f) float player_x = STARTING_POINT_X; float player_y = STARTING_POINT_Y; float player_h = STARTING_HEADING; // player's heading float player_s = 0.0f; // forward speed of the player float player_m = 1.0f; // speed multiplier of the player float player_t = 0.0f; // player's turning (change in heading) float player_b = 0.0f; // viewpoint bank (roll) int walllist = 0; int mazelist = 0; void spinmaze(HDC hDC); void entermaze(HDC hDC); void navmaze(HDC hDC); void (*idlefunc)(HDC hDC) = NULL; void spinmaze(HDC hDC) { // spin the maze around on 2 axis static float spin = 720.0f; spin -= 5.0f; // change this line to be time dependant! glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glTranslatef(0.0f, 0.0f, -20.0f); glRotatef(spin, 0.0f, 1.0f, 1.0f); glTranslatef(-MAZE_WIDTH / 2.0f, -MAZE_HEIGHT / 2.0f, 0.0f); glCallList(walllist); glCallList(mazelist); glPopMatrix(); SwapBuffers(hDC); if (spin <= 0.0f) { spin = 720.0f; idlefunc = entermaze; player_x = STARTING_POINT_X; player_y = STARTING_POINT_Y; player_h = STARTING_HEADING; } } void entermaze(HDC hDC) { static float p=0.0f; p += 0.02f; // hmmm, should be time dependant glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glRotatef(-90.0f*p, 1.0f, 0.0f, 0.0f); glRotatef(player_h*p, 0.0f, 0.0f, 1.0f); glTranslatef( -(player_x*p + MAZE_WIDTH/2.0f*(1 - p)), -(player_y*p + MAZE_HEIGHT/2.0f*(1 - p)), -(0.5f*p + 20.0f*(1-p)) ); glCallList(walllist); glCallList(mazelist); glPopMatrix(); SwapBuffers(hDC); if (p >= 1.0f) { p = 0.0f; idlefunc = navmaze; } } int forward(float px, float py, float bf) { // this routine does wall collision detection // the inputs to this routine are: // - the desired location // - the minimum distance to wall allowed // changes: // - the player's x and y coordinates // returns: // - whether a wall caused change in target position // This is really easy with these walls that lie only on axes. // If the player collides into a wall at an angle he/she will // still slide along the wall - I hate programs where you stick // to the polygon and cant move until you back away from it. // This collision detection isn't perfect - if you're precise you // can jump through at a corner - but its tough. int x = ((int)player_x); int y = ((int)player_y); int h = 0; // number of walls hit if ((px > x + 1.0f - bf) && wall(x + 1, y)) { px = (float)(x) + 1.0f - bf; h++; } if ((py > y + 1.0f - bf) && wall(x, y + 1)) { py = (float)(y) + 1.0f - bf; h++; } if ((px < x + bf) && wall(x - 1, y)) { px = (float)(x) + bf; h++; } if ((py < y + bf) && wall(x, y - 1)) { py = (float)(y) + bf; h++; } player_x = px; player_y = py; return(h); } void navmaze(HDC hDC) { // navigate through the maze and render it from the // players point of view. // Ideally updates to heading and position should be time dependant forward( player_x + player_m*player_s*(float)sin(player_h*M_PI/180), player_y + player_m*player_s*(float)cos(player_h*M_PI/180), 0.2f ); player_h += player_t; player_b = 3*player_b/4 + player_t/4; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); if (enablebank) { glRotatef(-player_b, 0.0f, 1.0f, 0.0f); // add roll to viewpoint } glRotatef(player_h, 0.0f, 0.0f, 1.0f); glTranslatef(-player_x, -player_y, -0.5f); glCallList(walllist); // no need to draw the top since we're in the maze now glPopMatrix(); SwapBuffers(hDC); if ((player_x > MAZE_WIDTH) || (player_y > MAZE_HEIGHT)) { // start over idlefunc = spinmaze; } } #define IMG_SIZE 128 static BOOL bTexLoaded = FALSE; void readtexture(void) { BYTE *image; DWORD dw; HANDLE fl; if (bTexLoaded) { return; } // the bitmap must be a 24 bit bmp file thats 128x128 // I think I mixed up red and blue componants - oh well :-) fl = CreateFile("maze.bmp", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (fl != INVALID_HANDLE_VALUE) { SetFilePointer(fl, 54, NULL, FILE_BEGIN); dw = IMG_SIZE*IMG_SIZE*3; image = (void *) LocalAlloc(LMEM_FIXED, dw); if (image) { ReadFile(fl, image, dw, &dw, NULL); glTexImage2D(GL_TEXTURE_2D, 0, 3, IMG_SIZE, IMG_SIZE, 0, GL_BGR, GL_UNSIGNED_BYTE, image); // let texture wrap-around glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // use point sampleing (fastest) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glEnable(GL_TEXTURE_2D); LocalFree(image); bTexLoaded = TRUE; } CloseHandle(fl); } } static void SetupDC(HDC hDC) { PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), /* size of this pfd */ 1, /* version num */ PFD_DRAW_TO_WINDOW | /* window types */ PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, /* RGBA type */ 8, /* 8-bit color depth */ 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ 0, /* no alpha buffer */ 0, /* alpha bits (ignored) */ 0, /* no accumulation buffer */ 0, 0, 0, 0, /* accum bits (ignored) */ 16, /* 16-bit depth buffer */ 0, /* no stencil buffer */ 0, /* no auxiliary buffers */ PFD_MAIN_PLANE, /* main layer */ 0, /* reserved */ 0, 0, 0, /* no layer, visible, damage */ /* masks */ }; int SelectedPixelFormat; BOOL retVal; // see if the pixel format exists SelectedPixelFormat = ChoosePixelFormat(hDC, &pfd); if (SelectedPixelFormat == 0) { MessageBox( WindowFromDC(hDC), "Failed to find acceptable pixel format.", "OpenGL application error", MB_ICONERROR | MB_OK ); ExitProcess(1); } // use the pixel format retVal = SetPixelFormat(hDC, SelectedPixelFormat, &pfd); if (retVal != TRUE) { MessageBox( WindowFromDC(hDC), "Failed to set pixel format.", "OpenGL application error", MB_ICONERROR | MB_OK ); ExitProcess(1); } } LRESULT APIENTRY WinProc(HWND hWND, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: hDC = GetDC(hWND); SetupDC(hDC); hGLRC = wglCreateContext(hDC); wglMakeCurrent(hDC, hGLRC); glEnable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE); glEnable(GL_CULL_FACE); glShadeModel(GL_FLAT); walllist = drawwalls(); mazelist = drawtop(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0, 1.0, 0.1, 60.0); glMatrixMode(GL_MODELVIEW); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glLoadIdentity(); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); idlefunc = spinmaze; return(0); break; case WM_DESTROY: if (IsZoomed(hWND)) { ShowWindow(hWND, SW_RESTORE); } if (hGLRC) { wglMakeCurrent(NULL, NULL); wglDeleteContext(hGLRC); } ReleaseDC(hWND, hDC); PostQuitMessage(0); return(0); break; case WM_PAINT: if (hGLRC) { // not necessary to do anything here // since we're constantly drawing to the window anyway //PAINTSTRUCT ps; //BeginPaint(hWND, &ps); //Redraw(hDC); //EndPaint(hWND, &ps); return(0); } break; case WM_CONTEXTMENU: TrackPopupMenu( hMENU, TPM_LEFTALIGN | TPM_RIGHTBUTTON, LOWORD(lParam), HIWORD(lParam), 0, hWND, NULL ); break; case WM_SIZE: glViewport(0, 0, LOWORD(lParam), HIWORD(lParam)); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_APPLICATION_EXIT: PostQuitMessage(0); break; case IDM_APPLICATION_TEXTURE: enabletexture ^= 1; ((enabletexture) ? glEnable : glDisable)(GL_TEXTURE_2D); if (enabletexture) { readtexture(); } break; case IDM_APPLICATION_BANK: enablebank ^= 1; break; } break; case WM_CHAR: switch (LOWORD((int)wParam)) { case VK_ESCAPE: PostQuitMessage(0); break; case 'b': enablebank ^= 1; break; case 't': enabletexture ^= 1; ((enabletexture) ? glEnable : glDisable)(GL_TEXTURE_2D); if (enabletexture) { readtexture(); } break; } break; case WM_KEYDOWN: switch (LOWORD((int)wParam)) { case VK_LEFT: player_t = -5.0f; break; case VK_RIGHT: player_t = 5.0f; break; case VK_UP: player_s = 0.05f; break; case VK_DOWN: player_s = -0.02f; break; case VK_SHIFT: player_m = 3.0f; break; case VK_RETURN: if (IsZoomed(hWND)) { ShowWindow(hWND, SW_RESTORE); } else { ShowWindow(hWND, SW_MAXIMIZE); } break; } break; case WM_KEYUP: switch (LOWORD((int)wParam)) { case VK_LEFT: // the reason for the "if(" is that sometimes // the player hits the right key down before the // left key is all the way up. if (player_t < 0.0f) { player_t = 0.0f; } break; case VK_RIGHT: if (player_t > 0.0f) { player_t = 0.0f; } break; case VK_UP: player_s = 0.0f; break; case VK_DOWN: player_s = 0.0f; break; case VK_SHIFT: player_m = 1.0f; break; } break; default: break; } return(DefWindowProc(hWND, message, wParam, lParam)); } //int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst, LPSTR lpszCmdLine, int nCmdShow) { int main(void) { char *className = "OpenGLWnd"; char *winName = "Maze Example"; WNDCLASS winClass; MSG msg; RECT rc; // Define and register the window class ZeroMemory(&winClass, sizeof(winClass)); winClass.style = CS_HREDRAW | CS_VREDRAW; winClass.lpfnWndProc = WinProc; winClass.hInstance = GetModuleHandle(NULL);//hCurrentInst; winClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); winClass.hCursor = LoadCursor(NULL, IDC_ARROW); winClass.hbrBackground = GetStockObject(WHITE_BRUSH); winClass.lpszClassName = className; RegisterClass(&winClass); // create window hWND = CreateWindow( className, winName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 320, 240, NULL, // Parent window's handle NULL, // Menu handle winClass.hInstance, // Instance handle NULL // No additional data ); // center window ZeroMemory(&rc, sizeof(rc)); rc.right = 320; rc.bottom = 240; AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, FALSE); rc.right -= rc.left; rc.bottom -= rc.top; rc.left = (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2; rc.top = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2; MoveWindow(hWND, rc.left, rc.top, rc.right, rc.bottom, FALSE); // add quit menu item hMENU = CreatePopupMenu(); AppendMenu(hMENU, MF_STRING, IDM_APPLICATION_EXIT, "Exit"); AppendMenu(hMENU, MF_STRING, IDM_APPLICATION_TEXTURE, "Add/Remove Texture"); AppendMenu(hMENU, MF_STRING, IDM_APPLICATION_BANK, "Add/Remove Banking"); ShowWindow(hWND, SW_SHOWNORMAL);//nCmdShow); UpdateWindow(hWND); // DEBUG: use textures by default SendMessage(hWND, WM_COMMAND, MAKELONG(IDM_APPLICATION_TEXTURE, 0), 0); msg.wParam = 0; // process events while (1) { // oops, busy wait when no messages or idlefunc - ohwell if (idlefunc) { idlefunc(hDC); // PATCH: do not eat 100% of CPU Sleep(1); } if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if (GetMessage(&msg, NULL, 0, 0) != TRUE) { break; } TranslateMessage(&msg); DispatchMessage(&msg); } } return(msg.wParam); } |
LexSafonov |
![]()
Сообщение
#33
|
Member ![]() ![]() Группа: Authorized Сообщений: 21 Регистрация: 29-October 20 Пользователь №: 18,034 Спасибо сказали: 1 раз(а) ![]() |
Так ребята, всем привет. Долго меня не было. Вообщем сразу по делу буду, без лишних разговоров
![]() Решил я доразобрать по сильнее файл с картой. Сначала первый заход был с так называемым "полем", отвечающим за коллизию, а именно "коллижн-блоки". На данный момент структура одного такого блока. Напомню, 1 блок - это 16 байт описание. CODE - формат одного квадрата коллизии(поле с блоками физ. движка) ------------------------------------------------------------------------------------------------------------------------- 0x04 - порядковый номер? пока не совсем ясно как это работает, некоторые номера дают стабильный вылет. Кажись это связано как то с тем, что игра некорректно определяет два одинаковых блока в разных местах. 0x02 - непонятно что это и непонятно для чего оставили. Пока просмотрел 5 разных карт и почему то везде там нули. Вполне вероятно, что там может быть что то по эффектам. 0x01 - значение есть, но не ясен эффект 0x01 - то же самое 0x01 - кажись высота рендеринга потолка блока(черный туман) 0x01 - кажись высота рендеринга пола блока(черный туман)(не точно) 0x01 - высота потолка у блока?(эти значения работают и редактируются в хекс-редакторе) 0x01 - высота пола у блока? 0x01 - непонятное значение 0x01 -хм... блок перестаёт быть неосязаемым, если туда забить простые числа. значение от 55 и ниже блочат игрока. Кажись это какая то высота для блока, только непонятно для чего оно и не совсем ясна логика работы этой высоты. 0x01 - цвет освещения в блоке? Нашёл вот такие значения: FF - окрашивает в красный цвет 64 - моргает красный цвет 128 - синий цвет 160 - желтый 192 - серый? 224 - толи оранжевый, толи красный. от 1 до 10 - в блоке яркий свет От 11 до 17 - в блоке темно? 18 - ярко красно моргает 20 - полный свет в блоке 22 - оранжево моргает 24 - моргает тёмно-оранжевым 30 - моргает с темного на белый 0x01 - походу байт, который отвечает за действия. если забить 1, то открывает стартовую дверь. значение: 1 - стартовая дверь 3 - дверь, которая открывается рубильником 9 - конец уровня Из опыта с высотами блоков на первый взгляд выяснилось, что используется система пол-потолок, как в думе\дюке. Становится понятна логика работы движка. Видимо игра действительно технически поделена на "сетку из блоков" и в качестве координат у объектов принимает позицию блока(длина-строка). Остальное "считается" уже дальше. Такая система имеет и свои изъяны, а именно, двери и свитчи можно открывать "спиной", ведь движок по факту смотрит чисто нажатие кнопки в самом блоке. Этот прикол уже проверен и неоднократно) Далее я немного дорасшиффровал заголовок файла: CODE - сначала заголовок файла: размер содержимое комментарий ------------------------------------------------------------------------------------------------------------------------- 0x04 46 4F 52 4D FORM 0x04 - размер данных файла в байтах, BIG-ENDIAN 0x04 - количество карт в файле текстом.(обычно нуль, т.к. больше одной карты в файлах не встречал) - дальше идет информация о геометрии карты и её содержании, а именно: размер содержимое комментарий ------------------------------------------------------------------------------------------------------------------------- 0x04 - Название карты, текст 0x04 - размер данных карты, BIG-ENDIAN(прямой порядок байт) 0х02 - Кол-во вершин?.LITTLE-ENDIAN(обратный порядок байт) Формула - значение этих двух байт умножить на 8 (6 байт на 3 точки + 2 байта нули) 0x02 Кол-во квадов(прямоугольников).LITTLE-ENDIAN (обратный порядок байт). Формула - значение этих 2-х байт умножить на 20 (16 байт индексы точкек и 4 байта информация) 0x02 ------------ Длина "прямоугольника" мини карты(физ. движка)(Little-Endian) 0х02 ------------ Ширина "прямоугольника" мини карты(физ. движка)(Little-Endian) Формула для этих байт = умножить длину на ширину и полученое значение умножить на 16 16 байт описывают одну ячейку. 0х02 - Стартовая позиция игрока по осиX (Здесь пишется так же ) 0х02 - Стартовая позиция игрока по осиY 0х02 - Пока не ясно что, изменения приводят к зацикливанию игры на этапе подгрузки карты, иногда к вылету. 0х02 - Поле описания монстров, которые просто спавнятся. Формула = кол-во элементов умножить на 20 (20 байт на одного монстра) 0х02 - Поле описания пикапов, формула = кол-во элементов умножить на 8 0х02 - Поле описания "коробок" и подобных объектов(свитчей, бочек) Формула = кол-во элементов умножить на 16 0x02 - Исправление, походу 2 байта это кол-во всех дверей на карте. Формула: значение умножить на 8(8 байт один элемент) Формат двери ниже. 0х02 - Пока не ясно за что отвечает. 0x02 - Похоже на стартовый угол поворота игрока, игрока на старте карты это значение крутит. 0x06 - Не ясно что это, эффект постоянно случайный от изменения. 0x04 - Неизвестное значение, каким то образом влияет на монстров на уровне. Если монстры на уровне есть и выставить нули, то у монстров отключается рендеринг спрайтов, но сами они не пропадают Теперь по порядку, я нашёл ещё 4 разных значения, а именно координаты игрока X и Y , стартовый угол игрока и поле с кол-вом и описанием дверей на карте. Формат одной двери: CODE ------------------------------------------------------------------------------------------------------------------------- 0x01 - координата X 0x01 - координата Y 0х01 - непонятный байт 0х01 - время простоя двери в открытом состоянии 0х01 - тэг двери(для использования в коллижн блоках) 0х01 - непонятный байт 0х01 - угол поворота модели двери относительно карты 0х01 - индекс модели из секции D000\1\2\3... Пока что я не совсем понял вот такие вещи, а именно: - Если трёхмерная модель карты имеет координаты, то и её коллизия тоже должна иметь какие то стартовые координаты первого блока. - Так же я не совсем понял, что за последнее поле имеется в файле карты, после поля описания дверей. Там примерно 4000 байт.... Байты каким то образом там упорядочены, но изменения делают вообще случайные вещи(отключают двери, либо наоборот вешают другие эфффекты на "коллижн-блоки". Не могу понять логику их работы... - Каким образом дверям задаётся движение и их собственная коллизия(если дверь крутить, то игрок и монстры её коллизию видят).В некоторых картах есть двери, которые, видимо, вообще крутятся чисто вокруг своей оси(вроде 4 уровень в игре, где крео-камеры, сами модули имеют походу двери, которые "открываются" крутясь). В теории если это выяснить, то возможно будет вообще делать двери, которые будут открываться в стороны, а не вверх-низ, как в думе. Ладно, пойду спать, отпишусь по результатам, если чего выйдет)) |
-=CHE@TER=- |
![]()
Сообщение
#34
|
Walter Sullivan ![]() ![]() ![]() Группа: Root Admin Сообщений: 1,360 Регистрация: 4-February 08 Пользователь №: 3 Спасибо сказали: 313 раз(а) ![]() |
- Так же я не совсем понял, что за последнее поле имеется в файле карты, после поля описания дверей. Там примерно 4000 байт.... Байты каким то образом там упорядочены, но изменения делают вообще случайные вещи(отключают двери, либо наоборот вешают другие эфффекты на "коллижн-блоки". Не могу понять логику их работы... Предположу (точно не знаю), что, возможно, это таблица отсортированная для чего-то, чтобы не упорядочивать данные каждый раз при запуске. В смысле, что по этой таблице, возможно, игра как-то получает доступ уже к остальным данным до неё. |
![]() ![]() |
Упрощённая версия | Сейчас: 10th September 2024 - 16:20 |