Как написать игру. Том 3
Часть первая
(c) Дронов Константин
"Способ стойки на ушах"
Если вы говорите с богом
это молитва , если же
бог говорит с вами , то
это шизофрения .
Предисловие
То что вы видите является статьей на-
писаной по просьбе "стаи товарищей", с
мольбой в глазах, со скрючеными пальцами
судорожно сжимающих мышку и криком : "А
ну поделись опытом #ля-я-я , а то заксо-
рю !!!". Ну хошь-не хошь, а делиться на-
до. Эта статья основана на личном опыте
и представляет интерес в основном для
дизайнеров и програмеров. В основном она
будет полезна для разработчиков игр типа
ACTION или, на крайняк, RTS, но ограни-
чено и для других. Здесь не будет гото-
вых процедур, а только намеки как сде-
лать то или иное, а как это сделать ре-
шайте сами, основываясь на личном опыте.
Выбор системы програмирования не являет-
ся самым важным, так выбор актуален
только на SPECCY, так как кроме как на
ASSEMBLER'е сделать что-либо стоящее не-
возможно. Для современных платформ этот
выбор не актуален так как здесь все мож-
но свалить на мощность процессора.
"С чего начать писать игру ?"
Самый часто задаваемый вопрос выведен
во главу этой статьи. Ответ столь же
прост сколь и странен : "Я НЕЗНАЮ !". У
каждого должен появиться свой собствен-
ный подход. Лично я сначала обдумываю
идею, которая безусловно должна вас за-
разить, заставить вас думать, хорошо и
во всех деталях представить будущий
проект. Взять для примера можно что-либо
из существующего, к примеру для моей иг-
ры "PROJECT X" таким прототипом стала
серия "ALIEN BREED", а для "CYBEREAL"
серия "STAR DUST". Нет нужды изобретать
каждый раз велосипед, так как это до-
вольно сложно, а на мой взгляд с су-
ществующим уровнем техники просто
невозможно. Все так называемые новинки
есть ремиксы старых игр и кроме совер-
шенствования графики и звука ничего но-
вого не несут. Лично для меня кажется
интересным поразить каждого конкретного
игрока чем-нибудь в вашей игре: так в
"PROJECT X" это были 50FPS и мощное
оформление (позже я понял ошибку, 50 FPS
далеко не самое главное), в "CYBEREAL"
это сама игра с красивой графикой и зву-
ком плюс сама глобальность происходяще-
го. Итак, у вас есть идея, но приступать
так же еще рано, Важно оценить возмож-
ность создания на вашей компьютерной
платформе этого будущего шедевра ;-) .
Здесь вам необходим весь опыт, который у
вас разумеется должен быть, поскольку
если у вас нет опыта программирования,
то из написния игры не выйдет ничего хо-
рошего. Идеален опыт demomaker'а, этот
опыт позволит вам подойти к написанию
игры с огромной библеотекой знаний и го-
товых процедур. Вам необходимо осмыс-
лить, представить всю вашу программу так
хорошо, чтобы к моменту, когда вы сядете
за компьютер у вас было бы полное
представление о том, что вы будете де-
лать.
" Ты начал ... "
Разработай все необъходимые тебе
программы, например: редактор уровней и
т.п. Какие возможности у него должны
быть решать тебе я могу сказать, что мой
редактор для игры "Incubation Period"
имеет функции загрузки спрайтов, нарезка
спрайтов из большой карты, загрузка па-
литры, редактор атрибутов блоков, редак-
тор крупных изображений, редактор анима-
ции для блоков, редактор карты, редактор
накладки изображений второго уровня, ре-
дактор описателя, работа с пре-файлами и
наконец компилятор файла уровня. Но на-
писание такого редактора тема отдельного
разговора или можете воспользоватся лю-
быми другими, уже готовыми, например,
моими для SPECCY и AMIGA, они будут ско-
ро выложены на страницу LASER DREAMS в
сети INTERNET. Но это не выход, так как
они расчитаны на отдельный случай.
Заведите себе основную тетрадь, разде-
лите тетрадь на две части, где вы будете
хранить данные о переменных, их месте
расположения и о процедурах с данными на
вход и выход. Внесите все возможные пе-
ременные, которые придут вам на ум. К
примеру: жизни, энергию, заряды к ору-
жию, тип оружия, время, режим отладки и
т.д. Отдельно выделите место для внут-
ренних переменных игры как то: какой эк-
ран активен, адрес расположения открытой
библиотеки и т.д. И оставляйте как можно
больше места для будущих внесенных изме-
нений. Определите как вы хотите работать
с экраном, оцените быстродействие, опре-
делите как вы будете выводить графику на
экран. Мой совет: забудьте возможность
рисования прямо в экран, используйте бу-
фер или работайте в режиме двух экранов,
иначе возникнут проблемы с синхрониза-
цией вывода на экран. Так, например, на
AMIGA есть возможность организовать эк-
ран, где угодно в памяти, что позволит
вам применить схему :
┌───────────┐
│ проверить │
│ счетчик │ <────────┐
└───────────┘ │
равен 0 / \ равен 1 │
/ \ │
┌──────────┐ ┌──────────┐ │
│показываем│ │показываем│ │
│в экран 0 │ │в экран 1 │ │
└───┬──────┘ └────┬─────┘ │
│ │ │
┌───┴─────┐ ┌───┴─────┐ │
│ рисуем │ │ рисуем │ │
│в экран 1│ │в экран 0│ │
└─────────┘ └─────────┘ │
\ / │
\ / │
│ │
┌───────────────────────┐ │
│ увеличим счетчик на 1 │ │
└───────────┬───────────┘ │
└─────────────────┘
Разумеется счетчик можно оптимизиро-
вать. Так на SPECCY можно организовать
работу с двумя экранами и применить
блок:
BWRITE LD A,23
XOR 10
LD (BWRITE+1),A
LD BC,32765
OUT (C),A
Разумеется это несет известные ограни-
чения и сложности при работе со страни-
цами, но также даст возможность не тра-
тить время на переброску экрана. Поэтому
оцените возможности и посмотрите, если
объемы данных превышают размеры 32kb, то
возможно есть смысл тратить процессорное
время на организацию програмной переб-
роски. Хотя я, например, в игре PROJECT
X делал так: переключал страницу памяти,
перекидывал нужные данные в буффер, и
работал далее с двумя экранами.
На AMIGе при работе напрямую с чипсе-
том можно просто изменить указатель на
BITPLAN'ы в COOPER LIST. А при работе с
видеокартами можно пользоватся функциями
системы, то есть библиотеками, а можно и
ознакомиться с возможностями видеокарто-
чек и работать на прямую, но это потре-
бует больше времени и нервов. К примеру,
воспользоватся функцией переброски блока
памяти, но это на мой взгляд очень грубо
и есть более элегантные способы, напри-
мер, открыть два экрана и воспользоватся
функцией переключения экранов :
-252 ScreenToFront из intuition.library
Но это несколько нестандартный способ и
не стоит им пользоваться, это лишь при-
мер своеобразного подхода. Вообще есть
куча способов для работы с двумя экрана-
ми, просто загляните в список функций
библиотек.
ЕСЛИ ХОТИТЕ ИМЕТЬ КАК МОЖНО
МЕНЬШЕ ПРОБЛЕМ С ОТЛАДКОЙ И С
ЖЕЛЕЗОМ, ЧТО БЫ ВАША ИГРА
ИСПРАВНО ПОДДЕРЖИВАЛА ВСЕ НО-
ВОЕ ЖЕЛЕЗО, РАБОТАЙТЕ ПОД СИС-
ТЕМУ, ПИШИТЕ OS-FRENDLY ПРОГ-
РАММЫ
Но опять же не нужно абсолютно упи-
раться в систему не все функции системы
являются идеальными, они расчитаны на
обший случай, поэтому заложите в прог-
рамму возможность работы в разных режи-
мах, то есть предоставьте возможность
выбора: система или ваша процедура.
Первоначально создайте основной цикл,
который будет отображать блок схему, но
вместо "вывод на экран" можно внести вы-
зов подпрограммы с процедурой вывод на
экран. И вообще, старайтесь везде (где
это не скажется на скорости) вводить
подпрограммы и не используйте ни каких
"извращенных" приемов в основном цикле
программы, легче будет разобраться. В
каждом цикле указаной выше схемы жела-
тельно обратиться к процедуре синхрони-
зации. Для SPECCY есть команда процессо-
ра HALT, которая синхронизуется по нача-
лу прорисовки экрана, а для AMMY это мо-
жет быть функция:
-270 WaitTOF из graphics.library
Накидав основной цикл, вы ножете прис-
тупить к написанию отдельных процедур.
Тут вы могли бы разделить написание каж-
дой процедуры на несколько человек сог-
ласовываясь с данными из вашей тетради.
"Восток дело тонкое ..."
К началу желательно иметь уже хотя бы
часть графики к игре. Нужна также карта
игры.
Перейдем к частностям. Ну, к примеру,
как сделать процедуру прорисовки графики
в буффер здесь нужно смотреть какая игра
2D или 3D графика в ней используется.
Разберем сначала 2D. Ваша задача сво-
диться ...
1. изменить карту соответстенно вашим
описателям анимации
2. напечатать карту в буффер
3. нанести сверху объекты
4. спецэффекты
5. конец
Пункт 1: не является обязательным,
но... Вообщем решайте сами. Как же проще
всего организовать анимацию блока на
карте ? А очень просто !!! Можно к при-
меру задать в памяти такую структуру :
┌───────────────────┬──────────────────┐
│первый блок памяти │второй блок памяти│
├───────────────────┼──────────────────┤
│ данные первого │ номер следующего │
│ спрайта │ спрайта │
├───────────────────┼──────────────────┤
│ данные второго │ номер следующего │
│ спрайта │ спрайта │
├───────────────────┼──────────────────┤
: : :
. . .
. . .
: : :
├───────────────────┼──────────────────┤
│ данные NNNNNNN │ номер следующего │
│ спрайта │ спрайта │
├───────────────────┼──────────────────┤
│ данные NNNNN+1 │ номер следующего │
│ спрайта │ спрайта │
├───────────────────┼──────────────────┤
: : :
. . .
. . .
: : :
├───────────────────┼──────────────────┤
│ данные KKKKKKK │ номер следующего │
│ спрайта │ спрайта │
├───────────────────┼──────────────────┤
│ данные KKKKK+1 │ номер следующего │
│ спрайта │ спрайта │
├───────────────────┼──────────────────┤
: : :
. . .
Здесь каждому блоку присваивается
порядковый номер. Таким образом вам нуж-
но будет создать структуру, где каждый
сегмент содержит указатель на следущий
сегмент, а последний сегмент зациклен на
первый. Так если блок является не аними-
рованным, то зациклен на себя. Такой
способ позволяет избежать лишних затрат
памяти и быстродействия, а также избе-
жать не нужных проверок. В принципе мож-
но обойтись и без изменения карты. Так
можно организовать цикл и следовать сле-
дующим шагам:
┌─────────────────────┐
│ N = данные счетчика │
└──────────┬──────────┘
│
┌────────────────┴────────────────┐
│ A = номер блока из карты уровня │
└────────────────┬────────────────┘
│
┌─────────────┴─────────────┐
│A=номер блока следующего за│
│ блоком A из таблицы │<─┐
└─┬─────────────────────────┘ │
│ │
│ ┌─────────────────┐ │
└─────┤ повторить N раз ├────┘
└───────┬─────────┘
│
:
.
Но запомните, счетчик должен иметь
цикл больше или равный самому большому
количеству фаз анимации блока. Остальные
изменения являются одноразовыми и могут
быть занесены прямо в карту игры. Можно
также изменить карту используя специаль-
но написаный SCRIPT, но о нем позднее...
Пункт 2: Здесь даже объяснять ничего
не надо, достаточно просто произвести
печать в буффер последовательно каждого
блока. Единственный совет старайтесь
сделать так, чтобы в размеры блока были
пропорциональными 8, 16, 32 и т.д. Самим
будет легче. Но это я так, ведь енто и
ежику ясно ;-) ...
Пункт 3 : Здесь тоже все как в парке
днем. Так же все понятно. Проблема самая
большая это обрезание ( ;-) ) объектов
границами экрана, по-научному клиппиро-
вание. Решения могут быть разными, ну,
например, если вы копируете буффер, то
вы вполне можете сделать буффер таким,
чтобы у него был своеобразный бордюр, то
есть пространство в которое можно без
проблем записать весь объект. Типа:
┌──────────────────────────────────────┐
│ AAAA-объект │
│ X1,Y1 AAAA │
│ ┌────────────────────────────────┐ │
│ │ │ │
│ │ │ │
│ │ область перекидываемая │ │
│ │ в экран │ │
│ │ │ │
│ │ │ │
│ └────────────────────────────────┘ │
│ бордюр X2,Y2 │
│ │
└──────────────────────────────────────┘
Это имеет смысл только если объекты
являются независимыми от карты уровня,
то есть не задаются блоками, иначе вся
проблема сводиться к проверке на выход
за границы области типа :
┌────────────────────────┐
│ X,Y-верхний левый угол │
│ объекта XD=X │
└──────────┬─────────────┘
│
┌───┴────┐ нет
│ X < X2 ├────────────────┐
└───┬────┘ │
│ да │
┌───┴────┐ нет │
│ Y < Y2 ├────────────────┤
└───┬────┘ │
│ да │
┌───┴────┐ нет │
┌─────┤ X > X1 ├──────────────┐ │
│ └───┬────┘ │ │
│ │ да │ │
│ ┌───┴────┐ нет │ │
│ │ Y > Y1 ├────────────┐ │ │
│ └───┬────┘ │ │ │
│ │ да │ │ │
│ ┌───────┴──────────────┐ │ │ │
│ │ блок входит в пределы│ │ │ │
│ │ экрана │ │ │ │
│ └───────┬──────────────┘ │ │ │
│ │ │ │ │
│ ┌──┴───┐ │ │ │
│ │ X=X+1├─────────────┘ │ │
│ └──┬───┘ │ │
│ │ │ │
│нет┌─────┴─────────┐ │ │
├───┤ X=максимальный│ │ │
│ │ размер по X │ │ │
│ └─────┬─────────┘ │ │
│ │ да │ │
│ ┌───┴───┐ │ │
│ │ Y=Y+1 ├───────────────┘ │
│ │ X=XD │ │
│ └───┬───┘ │
│ │ │
│нет┌─────┴─────────┐ │
└───┤ Y=максимальный│ │
│ размер по Y │ │
└─────┬─────────┘ │
│ да │
┌────┴────────┐ │
│ все , конец ├────────────┘
└────┬────────┘
│
:
.
Этот прием можно применить и для
независимых объектов, но нужно его моди-
фицировать, так как, иначе вам потре-
буется проверять каждую точку объекта, а
это тянет ненужные затраты времени CPU.
Да, бесплатный совет, нет нужды пытаться
оптимизировать эту схему, если вы пишете
на ASM'е, то попытка оптимизировать та-
кое количество сравнений похожа на само-
убийство, вы конечно сможете, но нервов
и мата будет много.
Продолжение читайте в следующем разде-
ле.