ДонНТУ   Портал магистров

[изображение]

Мой опыт в написании игр

Здесь я расскажу о своем лучшем на данный момент проекте – игре, написанной после четвертого курса на WinAPI. На то время в памяти всплывала старая добрая игра battle-city, и я решил попробовать сделать похожую. По времени на это ушло около двух месяцев, хотя большая часть там была не существенна, и сам движок был разработан значительно быстрее. По сути, единственной средой, которой я владел к тому времени, была всего-то WinAPI, а ее показатели оставляют желать лучшего. Вследствие этого я сразу решил позаботиться о графике вручную, к тому же у меня уже был большой разносторонний опыт в этом направлении, но так как игра 2D и сделана полностью на текстурах, работа с графикой там, по сути, заканчивается на одной функции.

Графический движок.

Та основная функция, как сразу можно догадаться – функция вывода картинки поверх другой, в режимах копирования и альфа – перехода плюс зацикливание текстуры для фона и стен. В итоге был сделан класс 32-битной картинки, в котором делалось все, что нужно, а после готовая пиксельная матрица непосредственно выводилась в окно функцией SetDIBitsToDevice, результат был значительно приятнее всяких BitBlt – нет мерцания, синхронизированный вывод, да и побыстрее вроде-бы :). Сами текстуры были благополучно найдены в интернете и обработаны. С анимациями было уже посложнее, один взрыв был удачно извлечен и обработан из 2го «Крепкого Орешка» :), второй уже был чисто сгенерирован, хоть и криво но успешно в последовательности particle illusion/virtualdub/моя функция/virtualdub/sony vegas, еще несколько анимаций были сделаны в последнем. Все это в конце концов заняло целых 100 tga файлов, которые были склеены группами в целях удобства и чтобы не мучить файловую систему :). Функции для работы с Tga, кстати, тоже писались мной, т.к. не являются встроенными, хотя естественно в интернете их можно найти и это open-source.

Основной (физический движок).

В оригинальной игре стенки уничтожались кусками определенного размера, но мне такое не по душе и я сделал все векторным, то есть для задеваемой стены рассчитывалась область уничтожения и удалялась, преобразуя прямоугольный объект в 1-4 (реально в 1-3) новых. Я сделал специальный менеджер объектов, который по моим представлениям является основой любой игры со сложными взаимодействиями. Менеджер выделяет массив объектов и массив ссылок на них, при создании и освобождении объектов работа идет только со ссылками. В результате получены необходимые характеристики:

Для удаления объекту приходится хранить его реальный индекс в памяти менеджера. Цикл жизни игры проходит 30 раз в секунду, и прорисовка соответственно (33 мс между прерываниями таймера). Цикл идет по всем объектам в порядке их ссылок в менеджере, в зависимости от типа объект «знает, что ему делать» и может перебирать в таком же цикле всех остальных. По сути все, что нужно проверять – это пересечение и «пересечение, если подвинуть в такую-то сторону на столько-то», и в зависимости от ситуации как-то реагировать. Здесь возникает серьезное осложнение – если посреди цикла какой-то объект удаляется, то ссылки после него «едут», это было решено передачей глобального индекса и глобального количества в вызываемые методы объекта. Еще одна особенность была в создании «моментальной цепной реакции», когда взорвавшийся динамит детонировал соседний, тот еще один, и т.д. – объект удаляется и сразу же выделяется, попадая таким образом в конец очереди менеджера. Такой общий подход к циклу жизни на первый взгляд громоздкий и при большом количестве объектов может занимать значительное время, но реально это не так, все-таки «действующих» объектов мало и зависимость не квадратичная, а линейная, ну а сделать алгоритм с планированием событий вместо перебора – дело совсем не простое.

Интеллект соперников.

Самая сложная часть игры, я долго придумывал саму идею, оставляя при этом случайное поведение соперников. В итоге придумал векторный алгоритм поиска игрока противником, сначала он был «безшансовый» то есть находил кратчайший путь куда угодно, если таковой был. Но это было слишком и требовало немеряно вычислений, конечный вариант хорошо оптимизирован и «видит не дальше одного поворота». Идея рекурсивного алгоритма заключается в пускании лучей во все стороны от текущей позиции соперника, разбивании их о преграды и смены направления с вертикального на горизонтальное и наоборот. Новые лучи имеют ширину, равную длине породившего их луча. Выглядит это так:


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

Представление текстур.

На каком-то этапе я решил что ~1.5 мегабайта на эту игру – это сильно много, а поскольку работать здесь с png было неудобно (громоздкая система вызовов функций в найденной библиотеке и невозможность паковать по многу картинок в один файл), так я решил попробовать написать свой кодек для изображений со сжатием без потери качества. Кодеку дал банальное название CIMG от Compressed Image (как позже оказалось, уже существует открытая библиотека с таким названием но другим назначением - что не удивительно). В итоге за довольно небольшое время я получил неплохой результат, и потом продолжал развитие этой идеи уже в отдельной библиотеке (на данный момент у меня четыре своих библиотеки: сжатия по Хаффману, скоростного сжатия по «моему методу» ориентированному на изображения, CIMG, библиотека графических функций). Вся сотня текстур игры в 32-битном цветовом формате (RGBA) с суммарным размером 0.357 мегапикселя упакована в 5 файлов с общим сжатием в 2.11 раза, что определенно сильный результат. Потестировав CIMG на различных файлах могу сказать, что он не так сильно жмет скриншоты десктопа и картинки с повторяющимися участками, как png, но в среднем не уступает ему. Например, я взял 10 высококачественных обычных фотографий разного плана с 24 бит цвета, уменьшил до 1296х972, это занимает столько места:

Результат на лицо, в некоторых случаях png – лучше, в некоторых – хуже, и я не скажу что он работает быстрее cimg, скорее наоборот :), хотя в cimg и перебирается множество методов, но можно задать несколько последних, которые выиграют в 99% случаев, а если и проиграют то совсем немного, и все вместе все равно будут работать очень быстро :). При уменьшении фото в 2, в 4 раза по обоим координатам соотношение png и cimg примерно то же самое. Как и с графическим движком, написание собственного кодека это лишнее в данном деле, я это сделал так как увлекаюсь графикой, хотя во многих играх графика и звук хранятся в нестандартных форматах, пожалуй - для защиты от постороннего вмешательства.

В заключении возвращаюсь непосредственно к игре. Слова словами, а посмотреть и опробовать результат – совсем другое дело, поэтому ниже расположены скриншот и ссылка на архив с игрой. Меню отсутствует, здесь нет видимости завершенной игры рассчитанной на распространение, т.к. она такой и не является. Загрузка карты – файл *.sce (прилагается и конструктор карт :)) и вперед. Основное управление – стрелки, wasd, home, c, shift, pause, подробнее можно посмотреть по «F1».

По части программирования:


Скачать игру

У меня были проблемы с форматами при создании текстур и видео, а именно - из основных форматов альфа канал поддерживают png и tga, рендерить файлы с ним я мог только в png, свободного конвертора png32 -> tga32 в интернете я найти не смог и пришлось написать свой, с использованием открытой библиотеки PNGlib и хочу выложить его в свободное использование.
Скачать конвертор png32 bit -> tga32 bit (Win32)
Его возможности: