(c) М.Татаринов, г.Соликамск,
Пермская обл.
Всем, кто задумал делать ар-
кадную игру, посвящается...
Если вы решили написать игру
со скроллингом экрана и не знае-
те, как это сделать, то данная
статья поможет вам. Хочу ска-
зать, что ограниченный обьем
статьи не позволяет мне привес-
ти конкретные примеры (полный
пакет процедур для работы с кар-
той занял у меня около 2-х кило-
байт), но если вы решились пи-
сать игру, то вы достаточно ква-
лифицированный программист и
разберетесь, что к чему. Все,
сказанное в статье, имеет прак-
тическое подтверждение, поэтому
смело пишите свои процедуры.
1. Формат карты
Минимальным элементом на кар-
те является блок размером 32x32
пикселя, т.е. 4x4 знакоместа.
Такие размеры выбраны не случай-
но, вот их преимущества:
1) 4 - это одна из степеней
числа 2, так что все арифмети-
ческие операции предельно упро-
щаются за счет использования ко-
манд сдвига.
2) Огромный плюс - это малые
размеры памяти, занимаемой кар-
той. Так, карта размером 1024x16
знакомест (8x8) занимает всего
лишь 1024 байта, карта же из
блоков 8x8 займет в 16 раз боль-
ше, т.е. 16 Кб.
3) 1 блок 4x4 печатается быс-
трее, чем 16 отдельных знако-
мест.
Хотя размер одного блока ра-
вен 16x8+16=144 байта (если с
атрибутами), 30-40 блоков впол-
не хватает и не занимает много
памяти.
2. Немного о графическом наборе
В каком формате хранить ин-
формацию о графических шаблонах,
дело ваше. Я же предлагаю формат
растрового имиджа, который печа-
тается быстрее.
4 линии ───────>
┌────────┐ │ ┌────────┐ │
├───────>┤ │ │ │ │
├───────>┤ │ ├────────┤ │
├───────>┤ │ │ │ │
16 линий├───────>┤ │+атрибуты├────────┤ │
├───────>┤ │ │ │ │
├───────>┤ │ ├────────┤ │
├───────>┤\│/ │ │\│/
└────────┘ │ └────────┘ │
Стрелками показано направле-
ние печати, т.е. линия за лини-
ей.
Информацию об атрибутах я
предлагаю хранить в виде отдель-
ного файла, который приписывает-
ся в конец BitMap'а. Сделано это
опять же для упрощения расчета
адреса блока. Т.к. размер блока
без атрибутов равен 128 байтам,
то вычислить смещение в файле
шаблонов чрезвычайно просто:
;в B - номер шаблона
ADD A,A
;X2 - в данном случае уместно, т.к. для
;файла, в котором больше 127 блоков, вам
;места не хватит
LD H,0
LD L,A
ADD HL,HL ;x4
ADD HL,HL ;x8
ADD HL,HL ;x16
ADD HL,HL ;x32
ADD HL,HL ;x64
ADD HL,HL ;x128
LD DE,TABL
ADD HL,DE
3. Вывод карты с точностью до
знакоместа по произвольным коор-
динатам (имеются в виду коорди-
наты на карте, а не на экране).
Внимательный читатель навер-
няка заметил, что дискретность
карты составляет блок 4x4, сле-
довательно, и скроллинг должен
быть не меньше, чем на 4 знако-
места. Такая дискретность подхо-
дит для Map Editor'а, но никак
не для игры, поэтому необходи-
мо разработать прием, позволяю-
щий вывести в окно произвольный
участок карты с точностью до
знакоместа.
0┌────┬────┬─ Y LENGTH ──┬────┬────┬─
1│0 │1 │2 │3 │4 │5 │6 │
-│----│----│----│----│----│----│----│-
2│ │ ╔══════════════════════╗ │
3│ │ ║│ │ │ │ │ ║ │
─┼────┼───║┼────┼────┼────┼────┼─║──┼─H
0│7 │8 ║│9 │10 │11 │12 │13 │ E
1│ │ ║│ │ │ │ │ ║ │ I
-│----│---║│----│----│----│----│-║--│─G
2│ │ ║│ │ │ │ │ ║ │ H
3│ │ ║│ │ │ │ │ ║ │ T
X ─┼────┼───║┼────┼────┼────┼────┼─║──┼─
0│14 │15 ║│16 │17 │18 │19 │20 │
1│ │ ║│ │ │ │ │ ║ │
-│----│---║│----│----│----│----│-║--│-
2│ │ ║│ │ │ │ │ ║ │
3│ │ ║│ │ │ │ │ ║ │
─┼────┼───║┼────┼────┼────┼────┼─║──┼─
0│21 │22 ╚═23═══24═══25═══26═══27 │
1│ │ │ │ │ │ │ │
-│----│----│----│----│----│----│----│-
2│ │ │ │ │ │ │ │
3└────┴────┴────┴────┴────┴────┴────┴─
0123 0123 0123 0123 0123 0123 0123
Взгляните на рисунок, и вам
сразу станет понятно, как рас-
считать требуемую позицию окна с
координатами (X,Y) на карте.
Если вы не поняли, то привожу
следующие выводы:
1) Очевидно, что если карта
имеет размеры Length * Height,
то для грубого расчета позиции
окна (X,Y) стартовое смещение
распечатки будет равно X+Length*
Y (координаты заданы с точностью
4x4). Чтобы увеличить точность
позиционирования окна, мы вводим
смещение окна отдельно по X и Y.
Оно может быть от 0 до 3 и по-
казывает смещение относительно
начала текущего блока. На рисун-
ке эти координаты = (1.2;1.1),
где целая часть - номер блока на
карте, дробная - смещение.
2) Чтобы вывести карту на эк-
ран, нужно рассчитать координа-
ты печати на экране. Дробные
части координат X и Y (в данном
случае это 2 и 1), если их обра-
ботать командой NEG, дадут нам
стартовые координаты печати на
экране или в буфере, т.е. 2 ста-
нет -2, 1 станет -1 (#FE, #FF,
если угодно).
4. Как работает подпрограмма
печати блока и как ускорить вы-
вод карты.
Наверняка вы заметили, что
реальное количество знакомест,
печатаемых в окне, меньше, чем
количество знакомест, входящих в
состав окна, поэтому число выво-
димых блоков должно быть на 1
больше, чем длина и высота окна,
деленные на 4. То есть, если
размеры окна 32x16, то число пе-
чатаемых блоков 32/4+1=9; 16/4+
1=5. Из этого следует, что под-
программа печати блока должна
уметь отсекать невидимые знако-
места (клиппирование). Хочу ска-
зать, что операции сравнения и
увеличенное число блоков резко
снижают быстродействие печати.
Для увеличения скорости я приме-
нил прием использования двух
подпрограмм печати. Посмотрите
на рисунок. Мы видим, что не все
блоки требуют отсечения, поэто-
му мы создаем еще одну подпрог-
рамму печати, которая не отсе-
кает элементы блока. Эта под-
программа должна иметь цикл
только в 4 знакоместа, а 8 лиш-
них выводятся без цикла с по-
мощью LDI. Привожу вам "портрет"
окна 32x1 знакомест. Clip - от-
секать элемент, No clip - не от-
секать:
0 9 блоков clip, но если смеще-
ние=0, то 9 блоков no clip.
4 первый - clip, 7 no clip, 1
clip.
8 аналогично.
12 аналогично.
16 так же, как 0, только при
смещении = 0 не печатается.
5. Скроллинг
Ну, это элементарно. Рассмот-
рим скроллинг вперед на 1 знако-
место. Пусть переменные HPOS и
HDISP играют роль координат и
смещения. Проверяем HDISP на 3.
Если = 3, то HDISP:=0, HPOS:=
HPOS+1; иначе увеличиваем HDISP.
В другие направления - аналогич-
но.
Напоследок скажу, что печать
карты должна идти в буфер, кото-
рый я организую с адреса #E000
(подробнее об этом - см. книгу
"Прикладная графика"), и в свя-
зи с этим формат буфера задает
сам программист. Наиболее удоб-
ная раскладка буфера - линия за
линией, что существенно упрощает
процедуру печати.
И еще. Если вам необходимо
больше быстродействия, советую
пропускать нулевые элементы при
печати (пробелы), но тогда вам
придется использовать подпрог-
рамму очистки буфера. Этот метод
наиболее эффективно повышает
быстродействие, но в результате
скорость игры не постоянна.
P.S. Если вы собираетесь ис-
пользовать стек для повышения
быстродействия и намереваетесь
использовать звуковое сопровож-
дение, работающее по IM 2, то
скорость воспроизведения звука
будет "плавать". Это вызвано
тем, что при работе со стеком
необходимо запрещать прерывания.
При написании предыдущей игруш-
ки я столкнулся с этой пробле-
мой, т.к. печать блока и очис-
тка буфера использовали стек.
Попутно хочу ответить на
вопрос Васильева Антона (N 4-5,
1996). Я тоже занимался пробле-
мами обработки оцифрованного
звука на AY, и вот что я делал.
Способ записи звука практически
не отличается от предложенного
Сергеем Беловым (читаем шестой
бит, вращаем регистр), только я
использовал псевдокомпрессию. На
AY оцифрованный звук выводится
через регистры амплитуды, а мак-
симальное значение амплитуды не
превышает 15, т.е. четырех би-
тов. В связи с этим, в 1 байт
можно поместить в 2 раза больше
информации:
1) 0000xxxx=E - 1 цикл чтения
2) xxxxyyyy=E - 2 цикл чтения
3) (HL)=E - запоминание
INC HL
В регистрах 11 и 12 задается
скорость смены амплитуды при ис-
пользовании встроенного генера-
тора огибающей.
Прим.ред.: Спасибо Максиму за эту весь-
ма интересную статью. Только вот хочется
добавить пару слов по поводу использова-
ния стека при выводе карты. Да, действи-
тельно, прерывания при этом должны быть
запрещены, но избавиться от "плавания"
звука при этом все же возможно. Для этого
вывод карты надо начинать сразу после
HALT, а сам вывод должен умещаться в коли-
чество тактов между прерываниями. Тогда вы
успеете разрешить прерывания как раз к мо-
менту, когда следующее прерывание должно
произойти.
* * *