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

       

«Волна»


Предлагаем вам еще один интересный эффект, иногда встречающийся в игровых программах: по строке текста от левого к правому краю экрана как бы пробегает волна, буквы приподнимаются, затем опускаются и наконец занимают свое первоначальное положение.

Для осуществления этого эффекта прежде всего потребуется написать две подпрограммы вертикального скроллинга отдельных знакомест экрана: одну для перемещения символа вверх, а другую - для движения изображения вниз. Принцип такого рода скроллингов исключительно прост. Например, для сдвига изображения на один пиксель вверх нужно байт из второго ряда пикселей перенести на место байта первого ряда, затем байт из третьего ряда поместить во второй и так далее, а самый нижний ряд пикселей заполнить нулями. Правда, при этом потеряется содержимое самого верхнего байта, но для текстовой строки это не особенно важно, так как обычно буквы сверху и снизу имеют по пустому ряду точек (ведь между строками текста должен быть какой-то зазор). Скроллинг букв вниз аналогичен, только перемещать байты знакоместа нужно, начиная с нижнего края.

Подпрограмма вертикального скроллинга знакоместа может выглядеть так:

UP CP 32 ;проверка позиции перемещаемого знакоместа RET NC ;выход, если больше или равна 32 LD HL,(AD_LIN) ;получаем адрес экрана начала строки PUSH AF OR L LD L,A PUSH HL LD D,H ;копируем адрес в DE LD E,L LD B,7 ;повторяем 7 раз UP1 INC H ;в HL - адрес байта следующего ряда LD A,(HL) ;переносим из (HL) в (DE) LD (DE),A INC D ;переходим к следующему ряду DJNZ UP1 LD (HL),0 ;обнуляем самый нижний ряд POP HL POP AF RET

Перед обращением к этой (а также и к следующей) подпрограмме в аккумулятор нужно занести горизонтальную позицию знакоместа в строке. Если заданная позиция выходит за пределы экрана, то есть не попадает в диапазон от 0 до 31, подпрограмма не должна выполняться. Для этого в самом ее начале проверяется обозначенное условие и в случае его невыполнения происходит условный выход из подпрограммы (команда RET NC). Как видите, условными могут быть не только переходы. Сразу заметим, что по условию можно также вызывать процедуры, используя команды типа


CALL S,ADDR

где S - любое из возможных условий, а ADDR - абсолютный адрес или метка.

После проверки возможности выполнения подпрограммы в регистровую пару HL загружается адрес начала строки экрана, по которой будет пробегать «волна». Этот адрес рассчитывается заранее и помещается в двухбайтовую переменную AD_LIN, которая в программе будет задаваться инструкцией ассемблера DEFW. В остальных строках не встретилось ничего нового, поэтому, надеемся, вполне достаточно кратких комментариев.

Подпрограмма скроллинга вниз похожа на первую, но все же есть и некоторые отличия. Мы говорили, что начинать такой скроллинг нужно с нижнего края знакоместа, однако можно поступить и несколько иначе, например, так:

DOWN CP 32 ;начало такое же, как и в RET NC ; предыдущей подпрограмме LD HL,(AD_LIN) PUSH AF OR L LD L,A PUSH HL XOR A ;в аккумуляторе 0 EX AF,AF' ;отправляем его в альтернативный AF' LD B,7 DOWN1 LD A,(HL) ;считываем байт текущего ряда EX AF,AF' ;меняем аккумулятор на альтернативный LD (HL),A ;записываем в текущий ряд INC H ;переходим к следующему ряду DJNZ DOWN1 EX AF,AF' ;запись последнего байта LD (HL),A ; в самый нижний ряд POP HL POP AF RET

Раньше мы уже упоминали команду EX AF,AF', сейчас же показали ее практическое применение. Напомним, что она выполняет действие, аналогичное команде EXX, только меняет на альтернативный аккумулятор, а заодно и флаговый регистр (этим иногда тоже можно пользоваться, сохраняя флаги для последующих операций). Советуем внимательно изучить подпрограмму DOWN и проследить за «эволюциями» аккумулятора в данном примере. Это поможет вам лучше понять принцип работы многих других подпрограмм, с которыми вы еще встретитесь.

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



ORG 60000 XOR A ;инициализация переменных: LD (HEAD),A ; начальной позиции «волны» CALL 3742 LD (AD_LIN),HL ; и адреса строки экрана WAVE LD HL,HEAD LD A,(HL) INC (HL) ;увеличивать или уменьшать можно не ; только содержимое регистров или ; регистровых пар, но и значение в ; ячейке памяти, адресованной парой HL CP 35 ;ушла ли «волна» за пределы экрана? RET Z CALL UP ;первый символ вверх DEC A CALL DOWN ;второй - вниз DEC A CALL DOWN ;третий тоже вниз DEC A CALL UP ;последний - вверх LD BC,5 CALL 7997 ;небольшая задержка (PAUSE 5) JR WAVE HEAD DEFB 0 ;позиция «головы» синусоиды AD_LIN DEFW 0 ;адрес экрана начала строки

Данная подпрограмма создает эффект «волны» в самой верхней строке экрана, а чтобы получить то же самое в другой строке, нужно перед командой

CALL 3742

добавить

LD A,N

где N - номер требуемой строки.

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

RANDOMIZE USR 60000

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


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