Как написать игру для ZX Spectrum на ассемблере

       

«Растворение» символов


Продолжим изучение новых команд и приемов программирования, а заодно рассмотрим еще один интересный эффект, который можно назвать «растворение» символов. Он используется, например, в таких играх, как LODERUNNER, THE DAM BUSTER и других. Возможно, он заинтересует и вас. Суть его состоит в том, что при переходе от одной картинки, формируемой программой, к другой происходит не мгновенная очистка экрана, как оператором CLS, а изображение постепенно как бы растворяется. Это очень напоминает таяние снега. Подпрограмма, создающая такой эффект удивительно проста и коротка:

ORG 60000 ENT $ THAW LD B,8 ;экран очищается за 8 циклов LD DE,0 ;адрес начала кодов ПЗУ THAW1 LD HL,#4000 ;адрес начала экранной области PUSH DE THAW2 LD A,(DE) ;берем «случайный» байт из ПЗУ AND (HL) ;объединяем с байтом из видеобуфера LD (HL),A ;помещаем обратно в видеобуфер INC HL ;переходим к следующим адресам INC DE LD A,H ;проверяем, нужно ли повторять цикл CP #58 ;если прошли еще не весь видеобуфер ; (#5800 - адрес начала области атрибутов) JR NZ,THAW2 ; то повторяем PUSH BC LD BC,1 CALL 7997 ;PAUSE 1 POP BC POP DE LD HL,100 ADD HL,DE ;увеличиваем адрес в ПЗУ на 100 EX DE,HL ;меняем HL на DE DJNZ THAW1 ;повторяем цикл JP 3435 ;окончательно очищаем экран

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

Как мы говорили в самом начале книги, микропроцессор способен выполнять элементарные арифметические операции над числами. Сложению соответствует мнемоника ADD (Addition - сложение) а вычитанию - SUB (Subtraction). В этих операциях может участвовать регистр A (арифметические операции над однобайтовыми числами) или пара HL (при сложении или вычитании двухбайтовых чисел). К содержимому аккумулятора можно прибавлять (или вычитать) значение другого регистра или непосредственную числовую величину, а к паре HL можно только прибавлять и только содержимое другой регистровой пары (кроме AF, конечно). Результат арифметического действия получается в аккумуляторе или в регистровой паре HL соответственно.


Помимо обычных операций сложения и вычитания существуют их разновидности - сложение и вычитание с переносом (или, как еще говорят, с заемом). Они отличаются тем, что в операции принимает участие еще и флаг переноса: при сложении он прибавляется к результату, а при вычитании - отнимается. Записываются такие команды с мнемоникой ADC или SBC. В отличие от обычного вычитания в операции вычитания с переносом регистровая пара HL вполне может участвовать.

Есть небольшая особенность в записи этих команд: операция вычитания с участием аккумулятора выглядит не SUB A,S или SBC A,S, как это можно было ожидать, а просто SUB S или SBC S. То есть имя регистра A не пишется. Во всех остальных командах нужно указывать и имя. Вот некоторые примеры:

ADD A,7 ;прибавить к содержимому аккумулятора 7 ADC A,C ;прибавить к аккумулятору регистр C и флаг CY SUB B ;вычесть из аккумулятора значение регистра B SBC 127 ;вычесть из аккумулятора число 127 и флаг CY ADD HL,HL ;удвоить значение регистровой пары HL ADC HL,DE ;сложить содержимое пар HL и DE и добавить ; значение флага CY SBC HL,BC ;вычесть с учетом флага переноса BC из HL

Все перечисленные команды изменяют основные флаги за исключением команды ADD HL,SS, которая влияет лишь на флаг переноса.

Другая новая команда, встретившаяся в подпрограмме «растворения» экрана - это команда EX DE,HL. Она выполняет самое элементарное действие: обменивает содержимым регистровые пары HL и DE. То, что раньше было в HL, переходит в DE и наоборот. Правда, в данном случае она использована просто для пересылки полученного в HL результата в пару DE. Такой, вроде бы, нелепый ход объясняется отсутствием в системе команд микропроцессора Z80 инструкций для пересылки значений между регистровыми парами (типа LD DE,HL), поэтому команда EX DE,HL иногда может заменять последовательность

LD D,H LD E,L

что не только сокращает запись, но и несколько ускоряет работу программы.

Теперь вернемся к нашему примеру и посмотрим, как он работает. Основную роль здесь выполняет команда AND (HL), объединяющая байт из ПЗУ с байтом из экранной области памяти. В данном случае коды ПЗУ можно рассматривать как некоторую последовательность «случайных» чисел, поэтому в результате операции AND мы получим в аккумуляторе байт из видеобуфера, но некоторые биты в нем окажутся «выключенными», а какие именно - предсказать довольно трудно. Каждый следующий байт экрана объединяется с другим байтом из ПЗУ, отчего уже после первого прохождения цикла часть изображения пропадет. После второго прохода на экране останется еще меньше «включенных» пикселей. Но для этого нужно изменить последовательность «случайных» чисел, чего легче всего добиться изменением начального адреса в ПЗУ. В нашем примере он просто увеличивается на 100 байт. Поскольку нет гарантии, что после установленных восьми циклов все изображение окончательно исчезнет, в самом конце программа переходит на процедуру полной очистки экрана. Кстати, обратите внимание, что вместо последовательности



CALL 3435 RET

стоит единственная команда

JP 3435

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

В подпрограмме «растворения» экрана есть еще один довольно интересный момент - это способ организации внутреннего цикла. Зная длину области данных видеобуфера, которая равна 6144 байт, можно было бы задать количество повторений в явном виде, но в данном случае, поскольку адрес экранной области начинается с ровного шестнадцатеричного значения (то есть младший байт адреса равен нулю) и размер обрабатываемого блока также кратен 256, достаточно проверять только старший байт адреса на достижение определенного значения, а именно, #58, так как с адреса #5800 начинается область хранения атрибутов для каждого знакоместа экрана.


Содержание раздела