"Неожиданное путешествие"
"Неожиданное Путешествие" - взгляд изнутри
STD
Недавно на zx-pk.ru форумчанин из Пско─
ва под ником STD выложил в общий дос─
туп свою текстово-графическую адвентюру
"Неожиданное Путешествие", которая испол─
нена в достаточно нестандартной манере на
фоне массы современных игр, сделанных на
AGD -движке.
Мы попросили автора рассказать о техни─
ческой части этой игры.
* * *
Необходимое лирическое вступление:
Автор сам прекрасно понимает, что соз─
данный им код топорный и деревянный, что
он жрет память Спекки, как не в себя, а
также,что при просмотре листинга мастерами
уровня Alone Coder и GoodBoy они рискуют
заработать глазное кровотечение. Но. Мой
движок все-таки имеет одно достоинство. Он
вопреки всему работает! Так что рассматри─
вайте его и эту статью как совокупность
неких идей,которые кто-то уже обдумал, как
исходный материал для своего творчества и
совершенствования, будь на то ваша воля.
Итак, что представляет собой "Неожидан─
ное Путешествие" с точки зрения программи─
ста и как там всё устроено?
Движок программы мной написан полностью
на ассемблере и полностью в ZXASM - 100%
аутентичная разработка в2017 г., что дос─
тавило мне много удовольствия уже само по
себе.
Распределение памяти
При разработке игры под расположение
движка в памяти я отвел место с26000 по
32767(#7FFF), то есть до самого конца 2-го
окна памяти или всего около7 КБ. В дейст─
вительности же в откомпилированном виде
движок занял 4 с небольшим килобайта, но
менять я ничего не стал.
С адреса 32768 (#8000) и до 37900 рас─
положен буфер для обработки текущей сцены
игры. Таким образом, любая отдельно взятая
сцена игры не может занимать более5123
байта памяти. О сценах подробнее далее.
С адреса 37900 и до 38000 расположено
место под флаги в игре.1 флаг = 1 байт.
Таким образом, в игре можно оперировать
сотней флагов.
С 38000 расположен буфер для вырезки
разных маленьких спрайтов. Я его использо─
вал для вырезки и временного хранения ку─
сочков экрана, когда открывал окно "листо─
чки" (в котором игрок выбирал все дейст─
вия), т.к. оно имело не строго прямоуголь─
ную форму, ввиду чего стандартная заложен─
ная в программу процедура сохранения гра─
фики под открываемым окном с ним не справ─
лялась.
С адреса47000 хранится шрифт игры: 2КБ
в кодировке 866 до самого конца 3-го окна
памяти, то есть по49151 (#BFFF) включите─
льно.
Как видно, с адреса38000 до 47000 аж
целых 9 КБ места. Для вырезки маленьких
спрайтов столько, конечно, не надо. Да так
уж получилось, что такая дырка осталась.
С адреса 49152 (#C000), как известно
даже малышам, начинается 4-е окно памяти,
куда на128K можно подключать банки (стра─
ницы) памяти0,1,3,4,6,7. Их я использовал
следующим образом:
Страница 0 - в неё всегда грузятся бло─
ки сцен, т.е. собственно текстовые файлы с
описанием локаций,команд и т.д.В моей игре
на диске они имеют именаblscOO, blscO1,
blscO2, ... blsc13.
Страница 1 - в неё грузятся блоки спра─
йтов, которые игрок видит в окне "фотогра─
фии" и которые сопровождают показ текстов.
На диске это файлыblspOO ... blspO5.
Страница 3 - в неё грузятся отдельные
спрайты, нужные для игры (скрепыш, медаль─
ка в окне достижений, мем "мудрый старик",
дискета "сохранить" и "листочки" для окна
выбора действия"). Все они хранятся в фай─
леgfxOO.
Страница 4 - с адреса #C000 в ней хра─
нится главное меню игры, с адреса57000 -
основной игровой экран (собственно блок─
нот, ручка, фотография).
Страница 6 - не используется.
Страница 7 - отведена под буфер для со─
хранения содержимого экрана под открывае─
мым окном. Процедура сохранения может сох─
ранить последовательно до4 открытых окон.
Программисту об адресах, куда именно это в
пределах данной страницы сохраняется, ду─
мать не надо.
Принцип построения движка
Движок можно разделить4 логически обо─
собленные части.
1.Часть инициализации.
Начиная отORG 26000 и до метки GLVOO.
Этот кусок кода работает только при первом
запуске программы, выводит на экран заста─
вки, инициализирует внутренние переменные
программы,грузит шрифт и загружает в стра─
ницу0 первый текстовой файл с первым бло─
ком сцен игры -blscOO.
Поле этого движок переходит кп.2.
2.Переброска текущей сцены в буфер об─
работки.
С меткиGLVOO до GLVO2 небольшой кусо─
чек программы берёт из внутренний перемен─
ной движкаPOZGL (то есть ПОЗиция ГЛобаль─
ная) адрес начала конкретной сцены в блоке
сцен, которую сейчас надо обрабатывать, и
перебрасывает её из этого адреса в выше─
указанный буфер текущей сцены на32768
(#8000). При этом одна сцена от другой от─
деляются маркером#FE. То есть в результа─
те работы этой части программы кусок памя─
ти из нулевой страницы с адресаPOZGL до
первого встреченного кода#FE будет переб─
рошен в адреса с32768 (#8000). При этом
этот кусок, как я уже писал,не должен быть
больше5123 байт, иначе он затрёт флаги!
При первом запуске программыPOZGL за─
носится#C000, поэтому процедура GLVOO...
GLVO2 перебросит в буфер самую первую
(нулевую) сцену изblscOO.
После того, как программа встретит код
#FE, переброска сцены заканчивается. В пе─
ременную POZIC (т.е. текущая ПОЗИЦия) за─
носится число#8000, то есть встаём на на─
чало буфера, куда попала обрабатываемая
сцена, и переходим кп.3.
3.Обработка текущей сцены или "блок
распознания управляющих кодов".
Начинается с меткиOSNOO и идёт до мет─
ки OSNЗЧ. В данном блоке движок работает
90% времени.
Из переменной POZIC берется адрес в
буфере обработки текущей сцены. Если мы
только начали обрабатывать сцену,это будет
#8000. Теперь берём из этого адреса имена
команд и начинаем их сравнивать с команда─
ми, зашитыми в данной части движка. Имена
всех возможных команд зашиты в этом блоке
программы. Как только все три последова─
тельно считанные из буфера буквы совпадут
с тремя буквами какой-либо команды, заши─
тыми в этом блоке, то этот блок вызывает
из4-й части программы уже непосредственно
её обработчик. После обработки в4-й части
программы и выполнения команды управление
вновь возвращается сюда, переменнаяPOZIC
увеличивается (так как после команды обыч─
но ведь идут её параметры, которые только
что использовали, обработали, и теперь их
надо пропустить) на столько байтов, чтобы
она начала указывать на следующую команду,
и управление возвращается в начало этого
блока.
Если в данном блоке попалась команда
"перейти к другой сцене", то после её вы─
полнения в переменнуюPOZGL будет занесён
адрес этой сцены, к которой надо перейти,
и управление вернётся не в начало блока3,
а будет передано на блок2.
4.Процедуры обработки управляющих ко─
дов.
Если блок 3 программы лишь распознаёт
команды и после распознания вызывает их
обработчики, то в блоке4 содержатся имен─
но эти самые обработчики.
То есть тут находятся все процедуры
"открыть окно","закрыть окно", "напечатать
спрайт","напечатать текст", "ждать нажатия
любой клавиши" и т.п.
Больше, собственно, сказать нечего. Это
нижний уровень, сама основа программы.
Команды
Для реализации своей игры я придумал
следующие команды, которых мне хватило с
лихвой:
WWN- устанавливает параметры текущего
окна, с которым дальше будут работать все
процедуры окна;
WC1- очищает всё текущее окно целиком,
включая поле рамки;
WC2- очищает внутреннюю часть текущего
окна целиком, без поля рамки;
WCL- заливает текущее окно цветом;
WRM- рисует в текущем окне рамку;
WCT- вырезает фон под текущим окном в
буфер. Можно последовательно сохранить 4
окна! Вырезанный фон окон помещается в
банк 7;
WST- полностью рисует текущее окно -
очищает его,заливает цветом,рисует рамку;
WPT- восстанавливает сохраненный фон
из-под окна из буфера. Процедура может по─
следовательно восстановить фон 4 окон, со─
хранных процедуройWCT;
WN1- быстрая установка текущимИ ВЫВОД
окна игры 1 (т.е. собственно страница дне─
вника, где печатается весь текст);
W2O- быстрая установка, сохранение фо─
на и вывод спрайта окна "Листочки"-"выбора
действия";
W2С- быстрое закрытие окна "выбора де─
йствия";
WЗO- быстрая установка,сохранение фона
и вывод спрайта окна "помощь";
WЗC- быстрое закрытие окна "помощь";
WЧO- быстрая установка,сохранение фона
и вывод спрайта окна "достижение";
WЧC- быстрое закрытие окна "достиже─
ние";
";"- комментарий.Весь дальнейший текст
игнорируется до перевода строки;
"Enter"- знак перевода строки игнори─
руется. Введено для удобства редактирова─
ния;
BNK- "Включение выбранного банка памя─
ти. Байт с номером страницы памяти +48
(т.е. просто текстовая цифра от 0 до 9)";
PAU- ожидание нажатия любой клавиши;
CLS- очищает экран;
FDI- зажигает экран;
FDO- гасит экран;
LDF- загрузка файла по имени. Загрузка
происходит всегда по адресу#C000и в тот
банк памяти, который в этот момент впеча─
тан в этот адрес командойBNK;
TXT- команда печати текста. Имеет свои
собственные управляющие коды;
CSP- вырезка произвольного спрайта;
PSP- печать произвольного спрайта;
SP1- выводит спрайт с номером от00
до16 из блока спрайтов в окно "фотогра─
фии";
JMP- безусловный переход к сцене с
указанным номером в текущем блоке сцен;
FON- включает выбранный флаг в блоке
переменных;
FOF- выключает выбранный флаг в блоке
переменных;
JMF- переход к сцене в зависимости от
того, включен выбранный флаг или нет;
VIB- переход на сцену в соответствии с
нажатием клавиш1-4,в окне "листочков";
VIN- спецоператор в игре. Используется
единственный раз, для проверки,выполнил ли
главный герой все три задания, и если да,
то перебрасывает его к горе ведьмы.
Этих немудрёных команд хватило, чтобы
написать игру. Скажу больше, из них всех в
95% случаев используется с десяток.
Команды WN1, W2O, W2С, WЗO, WЗC, WЧO,
WЧC введены для удобства набора сцен. Их
можно было бы не вводить, но тогда выпол─
нение очень частых действий, типа открытия
и закрытия окон "скрепыша", "листочков" и
т. д. приходилось бы выполнять серией опе─
раторовWWN, WC1, WCT, WST, WPT с парамет─
рами. Поэтому я посчитал, что самые глав─
ные окна в игре можно обозначить собствен─
ными операторами и открывать, закрывать их
надо по "имени собственному", например,
W2O/W2С. Раз - и всё!
Строение блоков сцен
Весь текст игры занимает порядка18ОКБ.
Он разбит на файлы размерами до1бКБ:
blscOO, blscO1, blscO2, ... blsc13.
В каждый момент времени в страницу0
может быть загружен только один из этих
файлов.
Внутри каждый файл состоит из отдельных
сцен, которые между собой разделены марке─
рами#FE.
Каждая сцена состоит из команд для дви─
жка, параметров этих команд и текста для
игрока, который печатается на экране кома─
ндойTXT.
Движок забирает из загруженного в стра─
ницу 0 блока сцен одну сцену (называемую
текущей) в буфер обработки текущей сцены с
адреса #8000 и в этом буфере последовате─
льно обрабатывает все её команды.
Так как сцена обрабатывается в этом бу─
фере, а не в нулевой странице, то в ходе
выполнения этой текущей сцены находящимися
в ней командами можно спокойно переключать
банки памяти, грузить туда спрайты,грузить
другие блоки сцен и переходить на них.
Буфер был введён именно для этого.
Ну а теперь, для примера, кусок исход─
ного текста блока сцен. Как это выглядит в
игре, вы видели, а вот как это выглядит
для её автора в Notepad++:
;Сцена 00 "Меню"
BNK 1 - включили банк 1
LDF blspOO C - загрузили туда первый блок
спрайтов
BNK 4 - включили банк 4
FDI 49152 - вывели оттуда картинку
главного меню игры, которая
туда уже была загружена
BNK 0 - вернулись к банку 0
FOF 03:FOF 04:FOF 05:FOF 06 FOF 07:FOF 08
FOF 09:FOF 10:FOF 11:FOF 12:FOF 13:FOF 14
FOF 15:FOF 16:FOF 17:FOF 18 FOF 19:FOF 20
FOF 21:FOF 22 - сбросили все флаги игры
JMP 01 - перешли на сцену 1
· - это #FE маркер конца сцены
;Сцена 01 "Меню"
VIB 3,02,06,03 - сцена состоит из одной
команды: ждём, когда игрок
нажмёт одну из трёх возможных
клавиш: 1, 2 или 3,
и соответственно переходим
на сцены 2, 6 или 3.
·
;Сцена 02 "Вступление"
WWN 03,03,26,18,096,180,06,04
WCT:WST - этими командами мы вывели окно
для вступления, сохранив фон под
ним
TXT
Здравствуй, мой юный друг!
Я не знаю кто ты, а ты, в
свою очередь, не знаешь, что
за книга у тебя в руках. И хо-
тя твоя личность для меня нав-
сегда останется тайной, свою
тайну я тебе открою.
Это - Дневник. Более того -
это ЖИВОЙ дневник, который со-
держит мои ЖИВЫЕ воспоминания.
Раз ты держишь его в руках,
значит я, наконец,спустя годы,
нашел время, чтобы записать те
PAU:WC2:TXT - ждём нажатия любой клавиши,
очищаем и печатаем дальше...
Заключение
Мне кажется, что всё получилось в целом
очень просто и весьма элегантно. Если ис─
пользовать именно такой интерфейс, как у
меня, то игру в данном стиле, но со своим
сюжетом может, в принципе, разработать че─
ловек, вообще не знакомый ни с Бейсиком,ни
с ассемблером,просто в Notepad++ (конечно,
если не учитывать необходимость создания
блоков спрайтов для "фотографий", которые
я также формировал ассемблерными програм─
мами, и необходимости изменения титульных
экранов). Но в целом, всё-таки...
Безусловно, есть определённые шерохова─
тости и нелепости даже в придуманных мной
командах. Уже в процессе набора сцен я по─
нял, что пару из них следовало бы весьма
изменить, но было набрано уже много игры,и
переделывать я не стал. Именно это обусло─
вило наличие в ней многих "технических"
сцен, которые не видны игроку, но их приш─
лось вводить для того, чтобы правильно га─
сить окно диалога при ветвлениях сюжета.
В целом меня весьма увлекла идея возмо─
жности разработки действительно универса─
льного движка для такого типа игр, о чём я
уже писал на форуме. Мне кажется, это было
бы здорово, если бы на ZX-платформе появи─
лся такой продукт, который бы позволял
использовать разные шрифты, задавать пара─
метры своих окон, и прочая, и прочая,и всё
это - не выходя за пределы Notepad++. Это
был бы наш с вами AGD - Адвентюре Гейм
Дисингер фром Раша виз Лав!8)
Всегда Ваш, STD.
Other articles: