Одним из главных достоинств компьютерных игр, как вы сами прекрасно знаете, является возможность играющего влиять на события, разворачивающиеся перед ним на экране. Это влияние можно реализовать по-разному, например, нажимая определенные клавиши клавиатуры или наклоняя в ту или иную сторону ручку джойстика и нажимая кнопку «огонь». При этом в большинстве игр предусматривается выбор любого вида управления, который обычно осуществляется через «Меню». Настало время и нам рассмотреть эти вопросы с разных точек зрения, а именно: как управлять спрайтами с помощью клавиатуры или джойстика и при этом учесть ограничения, обусловленные размерами экрана, как определить, подключен к компьютеру джойстик или нет, как организовать управление игрой, если играющих двое, и некоторые другие.
100 IF INKEY$<>"P" THEN GO TO 100Соответствующий ей фрагмент ассемблерной программы имеет следующий вид:
XOR A
LD (23560),A ;в системную переменную LAST_K (код
; последней нажатой клавиши) заносится 0
LOOP LD A,(23560) ;из этой системной переменной
; считывается значение кода нажатой клавиши
CP "P" ;сравнение двух кодов - находящегося
; в регистре A и символа P
JR NZ,LOOP ;если результат сравнения не равен 0,
; то переход на метку LOOP, если 0,
RET ; то выход
Надо заметить, что эта программка уже неоднократно применялась нами для разных целей, например, для выхода из циклов, для перехода к кадрам в многокадровой заставке, но она может использоваться и как образец для создания более сложных программ, например, следующей:
KEY XOR A
LD (23560),A
MET1 LD A,(23560)
CP "P" ;сравнение двух кодов
; Если результат сравнения не равен нулю (то есть нажата не P),
; то переход на метку MET2, после которой проверяются нажатия других клавиш
JR NZ,MET2
LD DE,TXT1
PRINT LD BC,5 ;вывод на экран символа,
CALL 8252 ; соответствующего нажатой клавише
LD A,13
RST 16
JR KEY ;переход на начало программы
MET2 CP "O" ;проверка нажатия клавиши O
JR NZ,MET3
LD DE,TXT2
JR PRINT
MET3 CP "Q" ;проверка нажатия клавиши Q
JR NZ,MET4
LD DE,TXT3
JR PRINT
MET4 CP "A" ;проверка нажатия клавиши A
JR NZ,MET5
LD DE,TXT4
JR PRINT
MET5 CP "0" ;проверка нажатия клавиши 0
JR NZ,MET1 ;если коды не совпадают,
; повторяем все сначала
RET ; иначе - выход из программы
; Данные для печати
TXT1 DEFM "KEY P"
TXT2 DEFM "KEY O"
TXT3 DEFM "KEY Q"
TXT4 DEFM "KEY A"
После того как вы нажмете клавишу P, O, Q или A, программа напечатает в левом верхнем углу экрана одну из фраз, перечисленных в блоке данных, например, «KEY Q».
В игровых программах, как вы знаете, часто требуется опрашивать несколько клавиш одновременно, например, чтобы выполнять сложные перемещения спрайтов, включающие помимо вертикальных и горизонтальных еще и диагональные направления. Для подобных ситуаций приведенные выше способы опроса клавиатуры оказываются непригодными и, чтобы заставить все-таки спрайты перемещаться в любую сторону, придется воспользоваться командой IN, с помощью которой выполняется ввод данных из какого-либо порта. Существует несколько способов чтения из портов, но нас будут интересовать только два из них:
IN A,(port) - ввод байта из порта с номером port и помещение его в аккумулятор. При этом полный 16-разрядный адрес порта составляется из значения port (младший байт) и значения аккумулятора (старший байт).
| Полуряд | DEC | HEX | BIN |
| Space...B | 32766 | 7FFE | 01111111 11111110 |
| Enter...H | 49150 | BFFE | 10111111 11111110 |
| P...V | 57342 | DFFE | 11011111 11111110 |
| 0...6 | 61438 | EFFE | 11101111 11111110 |
| 1...5 | 63486 | F7FE | 11110111 11111110 |
| Q...T | 64510 | FBFE | 11111011 11111110 |
| A...G | 65022 | FDFE | 11111101 11111110 |
| CS...V | 65278 | FEFE | 11111110 11111110 |
; Адрес 32766=127ґ256+254, в B заносится адрес полуряда,
; а в C - адрес порта (254).
KEY LD BC,32766
IN A,(C)
; Один из способов проверки данного бита - у отпущенной клавиши
; бит установлен (1), у нажатой сбрасывается в 0
BIT 2,A
JR NZ,KEY
RET
Второй способ принципиально не отличается от первого. Перед чтением в аккумулятор помещается старший байт адреса соответствующего порта, а младший байт задается в явном виде в команде IN:
KEY LD A,#7E ;в аккумулятор заносится старший байт
; адреса порта #7EFE
IN A,(254) ;считывание из порта (254 или #FE -
; младший байт адреса)
BIT 2,A ;проверка нажатия третьей от края
; клавиши (M)
JR NZ,KEY
RET
Рассмотрим программу, в которой при нажатии клавиш Q, A, O и P изменяются координаты точки на экране. Сами точки будем ставить в бейсик-программе, которую напишем позже, но подразумевая использование процедуры из Бейсика, воспользуемся для передачи координат точки, как и раньше, областью буфера принтера, определив адрес передаваемых параметров константой XY.
ORG 60000
XY EQU 23296
KEY LD HL,(XY) ;запись координат точки в HL
; В регистр A заносится старший байт полуряда,
; в котором располагается клавиша Q
LD A,251
IN A,(254) ;читаем из порта значения для полуряда
; Проверка бита 0 (команду RRCA вместо BIT здесь удобнее применять
; потому, что клавиша Q в полуряду занимает крайнее положение)
RRCA
; Если клавиша не нажата (на что указывает установленный бит),
; то следующую команду пропускаем
JR C,KEY1
; Увеличиваем значение вертикальной координаты, которое находится в регистре H
INC H
KEY1 LD A,253
IN A,(254)
RRCA ;клавиша A
JR C,KEY2
DEC H ;уменьшаем вертикальную координату
KEY2 LD A,223
IN A,(254)
RRCA ;клавиша P
JR C,KEY3
INC L ;увеличиваем горизонтальную координату
; Так как клавиши P и O находятся в одном полуряду,
; то выполнять команду IN дважды нет необходимости
KEY3 RRCA ;клавиша O
JR C,KEY4
DEC L ;уменьшаем горизонтальную координату
KEY4 LD (XY),HL
LD A,127
IN A,(254)
BIT 2,A
RET NZ ;выход, если клавиша M не нажата
JP 3435 ; иначе очищаем экран
Чтобы увидеть эту процедуру в действии, необходимо дополнить ее небольшой бейсик-программкой, задача которой состоит только в том, чтобы ставить на экране точку в соответствии с координатами (XY), полученными в ассемблерной программе.
100 POKE 23296,100: POKE 23297,100 110 PLOT PEEK 23296, PEEK 23297 120 RANDOMIZE USR 60000: GO TO 110Попробуйте ее ввести и исполнить, а затем понажимайте клавиши Q, A, O и P - по экрану в разных направлениях потянутся четкие прямые линии подобно использованию функции PEN в графическом редакторе. Нажав клавишу M, в любой момент можно очистить экран и начать рисовать новую «картину».
В заключение этого раздела приведем еще один пример управления с помощью клавиатуры, с которым мы иногда встречаемся, загружая те или иные игровые программы. Он полезен еще и тем, что дает вариант решения некоторых побочных проблем, таких, например, как учет ограничений на перемещение курсора (или спрайта) по экрану, введение дополнительных функций управления и некоторые другие.

Рис. 8.1. Ввод имени играющего
Представим себе, что в конце игры необходимо набрать имя играющего, чтобы затем записать его в раздел меню HI SCORE. Для этого, при достижении определенных результатов, вызывается кадр, в котором вы видите примерно такую таблицу, какая изображена на рис. 8.1. Далее, управляя курсором с помощью клавиш Q, A, O и P, требуется выбрать из таблицы буквы вашего имени, нажимая после каждой клавишу выбора M. При этом набранные буквы из таблицы будут переноситься в строку, расположенную ниже. Если какой-то символ набран неверно, его можно стереть, «нажав» в таблице букву d (delete), для печати пробела используется буква s (space), а для ввода имени и завершения этой части программы - буква e (enter). Надо сказать, что такой способ ввода имени не самый удобный, однако он имеет право на существование в случаях, когда играющий еще плохо знаком с клавиатурой ZX Spectrum, но имеет некоторое представление о латинском алфавите.
ORG 60000
ENT $
XOR A
CALL 8859
LD A,68
LD (23693),A
CALL 3435
LD A,2
CALL 5633
; Очистка строки для ввода имени
LD HL,NAME
LD DE,NAME+1
LD BC,19
LD (HL)," "
LDIR
; Вывод таблицы символов в рамке
CALL TABL
CALL LINES
LD A,68
LD (23693),A
LD BC,#506 ;начальные координаты курсора в таблице
LD E,0 ;номер символа в строке ввода
SET 3,(IY+48) ;режим ввода прописных букв
; Управление курсором и печать выбранного символа в строку
KEYS CALL SETCUR ;вывод курсора
XOR A
LD (23560),A
WAIT LD A,(23560) ;ожидание нажатия клавиши
AND A
JR Z,WAIT
CP "P" ;перемещение курсора на
JR Z,RIGHT ; один шаг вправо
CP "O" ;перемещение курсора
JR Z,LEFT ; на один шаг влево
CP "Q" ;перемещение курсора
JR Z,UP ; на один шаг вверх
CP "A" ;перемещение курсора
JR Z,DOWN ; на один шаг вниз
CP "M" ;печать выбранного символа
JR Z,SELECT ; в строке ввода
JR KEYS
; Перемещение курсора вправо
RIGHT LD A,C ;проверка достижения курсором
CP 24 ; правой границы таблицы
JR NC,KEYS
CALL RESCUR ;удаление курсора на прежнем месте
INC C ;изменение положения курсора
INC C
CALL SETCUR ;установка курсора на букву таблицы
JR KEYS
; Перемещение курсора влево
LEFT LD A,C ;проверка достижения курсором
CP 7 ; левой границы таблицы
JR C,KEYS
CALL RESCUR
DEC C
DEC C
CALL SETCUR
JR KEYS
; Перемещение курсора вверх
UP LD A,B ;проверка достижения курсором
CP 6 ; верхней границы таблицы
JR C,KEYS
CALL RESCUR
DEC B
DEC B
CALL SETCUR
JR KEYS
; Перемещение курсора вниз
DOWN LD A,B ;проверка достижения курсором
CP 11 ; нижней границы таблицы
JR NC,KEYS
CALL RESCUR
INC B
INC B
CALL SETCUR
JR KEYS
; Выбор символа, который затем будет напечатан в строке или выбор
; функции для редактирования этой строки
SELECT PUSH BC
PUSH DE
CALL SND ;звуковой сигнал, издаваемый при
; перемещении символа из таблицы в
; набираемую строку
POP DE
POP BC
LD A,B
CP 11
JR NZ,MOVE ;печать символа
LD A,C
CP 20
JR Z,DELETE ;удаление символа в строке
CP 22
JR Z,SPACE ;печать пробела в строке
CP 24
RET Z ;выход из программы
; Перемещаем символ из таблицы в набираемую строку и смещаем курсор
; на позицию вправо, при этом делаем проверку того, чтобы символ
; не вышел за заданные границы строки (слева и справа).
MOVE LD A,E
CP 20
JP NC,KEYS
LD D,0
PUSH BC
PUSH DE
LD A,B ;по вертикальной координате курсора
; определяем адрес данных строки
; таблицы (STR1, STR2, STR3 или STR4)
SUB 5
LD HL,D_STR
LD E,A
ADD HL,DE
LD E,(HL)
INC HL
LD D,(HL)
EX DE,HL
LD A,C ;по горизонтальной координате находим
; код символа в блоке данных
SUB 6
LD C,A
LD B,0
ADD HL,BC
POP DE
POP BC
LD A,(HL) ;помещаем код символа в A
LD HL,NAME ;определяем адрес в строке NAME
ADD HL,DE ; для ввода символа
LD (HL),A ;помещаем символ в строку ввода
CALL PR_STR ;выводим строку ввода на экран
INC E ;смещаем позицию ввода вперед
JP KEYS
; Удаление неправильно набранного символа
DELETE LD A,E ;проверка достижения начала строки ввода
AND A
JP Z,KEYS
DEC E ;уменьшаем позицию ввода
LD D,0
LD HL,NAME
ADD HL,DE
LD (HL)," " ;заменяем удаляемый символ пробелом
CALL PR_STR
JP KEYS
; Ввод пробела
SPACE LD A,E ;проверка достижения конца строки ввода
CP 20
JP NC,KEYS
LD D,0
LD HL,NAME
ADD HL,DE
LD (HL)," "
CALL PR_STR
INC E ;увеличиваем позицию ввода
JP KEYS
; Вывод курсора изменением байта атрибутов
RESCUR LD A,68 ;PAPER 0, INK 4, BRIGHT 1
JR PRATTR
; Удаление курсора восстановлением байта атрибутов
SETCUR LD A,79 ;PAPER 1, INK 7, BRIGHT 1
; Вычисляем адрес атрибутов знакоместа и заносим
; по этому адресу байт из аккумулятора
PRATTR LD L,B
LD H,0
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
PUSH AF
LD A,H
ADD A,#58
LD H,A
LD A,L
ADD A,C
LD L,A
POP AF
LD (HL),A
RET
; Подпрограмма печати таблицы символов
TABL LD DE,STR
LD BC,LENSTR
JP 8252
; Подпрограмма печати введенной строки
PR_STR PUSH BC
PUSH DE
LD DE,STR5
LD BC,LENLIN
CALL 8252
POP DE
POP BC
RET
; Подпрограмма рисования рамки
LINES EXX
PUSH HL
LD A,66
LD (23695),A
LD BC,#8A2C ;B = 138, C = 44
CALL 8933
LD DE,#101
LD BC,160 ;B = 0, C = 160
CALL 9402
LD DE,#FF01
LD BC,#3D00 ;B = 61, C = 0
CALL 9402
LD DE,#1FF
LD BC,160
CALL 9402
LD DE,#101
LD BC,#3D00
CALL 9402
POP HL
EXX
RET
; Короткий звуковой сигнал
SND LD B,30
LD HL,350
LD DE,2
SND1 PUSH BC
PUSH DE
PUSH HL
CALL 949
POP HL
POP DE
POP BC
SBC HL,DE
DJNZ SND1
RET
; Данные таблицы символов
STR DEFB 22,5,6
STR1 DEFM "1 2 3 4 5 6 7 8 9 0" ;символы через один пробел
DEFB 22,7,6
STR2 DEFM "A B C D E F G H I J"
DEFB 22,9,6
STR3 DEFM "K L M N O P Q R S T"
DEFB 22,11,6
STR4 DEFM "U V W X Y Z . d s e"
STR5 DEFB 22,19,5,16,5,">",16,2
NAME DEFM "····················"
DEFB 16,5,"<"
LENSTR EQU $-STR ;длина строки для печати таблицы
LENLIN EQU $-STR5 ;длина строки ввода имени
; Адреса данных символов в таблице
D_STR DEFW STR1,STR2,STR3,STR4
Эту программу можно рассматривать как вполне независимый кадр заставки. Если вы решите использовать ее в своей собственной игре, единственное, что вам потребуется, это перенести после выхода введенное имя из строки NAME в таблицу «рекордов». И, конечно же, вам нужно будет проследить, чтобы имена меток, задействованные в приведенной программе не повторялись в вашей игре. Естественно, что при необходимости наименования меток можно и заменить.
Наверное, вам известно, что в Бейсике определить положение ручки джойстика можно с помощью функции IN 31. В ассемблере для этих же целей удобнее всего применять команду IN A,(31), после выполнения которой в аккумуляторе появится некоторое число, отдельные биты которого и определяют «статус» джойстика. Значения имеют не все биты, а только 5 младших, причем, в отличие от клавиатуры, в нейтральном положении все биты сброшены в 0 (конечно, если порт джойстика вообще подключен), а установка какого-то бита в 1 означает поворот ручки или нажатие кнопки «огонь». При диагональном наклоне ручки будут установлены сразу два бита. В табл. 8.2 показано соответствие пяти младших битов, получаемых в аккумуляторе после выполнения команды IN A,(31), направлениям наклона ручки джойстика и нажатию кнопки «огонь». Три старших бита не определены, поэтому в таблице они заменены знаками вопроса.
| Направление | Код |
| Вправо | ???00001 |
| Влево | ???00010 |
| Вверх | ???00100 |
| Вниз | ???01000 |
| Огонь | ???10000 |
Давайте сначала на примере простой программки перемещения точки, аналогичной той, которую мы описали в начале первого раздела данной главы, рассмотрим принцип использования джойстика. Причем, как и в случае с клавиатурой, точку на экран будем ставить с помощью бейсик-программы.
ORG 60000
XY EQU 23296
JOY LD HL,(XY) ;в регистре H вертикальная координата,
; а в L - горизонтальная
IN A,(31) ;читаем из порта джойстика
RRCA ;проверяем бит 0
JR NC,JOY1 ;если в 0, переходим к проверке
; следующего бита
INC L ;увеличиваем горизонтальную координату
JOY1 RRCA ;аналогично проверяем остальные биты
JR NC,JOY2
DEC L ;уменьшаем горизонтальную координату
JOY2 RRCA
JR NC,JOY3
DEC H ;увеличиваем вертикальную координату
JOY3 RRCA
JR NC,JOY4
INC H ;уменьшаем вертикальную координату
JOY4 LD (XY),HL ;новые координаты передаем
; бейсик-программе
RRCA
RET NC
JP 3435 ;при нажатии кнопки «огонь»
; экран очищается
Чтобы точка, перемещаясь по экрану, не ушла за его пределы, необходимо ввести ограничения. Как это осуществить, покажем на конкретном примере, в котором мы используем приведенный выше принцип для воспроизведения реальной игровой ситуации, например, для управления самолетом. Прежде всего создадим три спрайта (блоки SAM1, SAM2 и SAM3), первый из которых будет соответствовать полету самолета прямо, второй повороту вправо (самолет при этом должен слегка наклониться) и, наконец, третий - его повороту влево. Таким образом, наклоняя ручку джойстика в ту или иную сторону, вы можете в приведенной ниже программе легко изменять положение спрайта на экране.
ORG 60000
ENT $
LD A,5
LD (23693),A
XOR A
CALL 8859
CALL 3435
; Основная часть программы
LD BC,#505 ;в регистре B вертикальная координата Y,
; а в C горизонтальная
JOY IN A,(31) ;читаем данные из порта джойстика
LD E,A ;освобождаем аккумулятор
; для проверки границ
LD HL,SAM1 ;задаем адрес первого спрайта
RRC E ;сдвигаем E вправо на один бит
JR NC,JOY1
LD A,C
CP 30 ;задаем границу перемещения вправо
JR NC,JOY1 ;если правая граница достигнута,
; то увеличивать X уже нельзя -
; переходим на метку JOY1
INC C ;увеличиваем координату X, что соответствует
; перемещению самолета вправо
LD HL,SAM2 ;задаем адрес второго спрайта
JOY1 RRC E
JR NC,JOY2
LD A,C
CP 1
JP M,JOY2
DEC C ;уменьшаем координату X
LD HL,SAM3 ;задаем адрес третьего спрайта
JOY2 RRC E
JR NC,JOY3
LD A,B
CP 22
JR NC,JOY3
INC B ;увеличиваем координату Y
JOY3 RRC E
JR NC,JOY4
LD A,B
CP 1
JP M,JOY4
DEC B ;уменьшаем координату Y
JOY4 RRC E
RET C ;если кнопка «огонь» нажата -
; выходим из программы
; Вывод на экран по принципу XOR одного из трех спрайтов самолета
PUSH BC
PUSH HL
LD A,SPRXOR ;устанавливаем режим вывода XOR
CALL PTBL ;печатаем один из самолетов
LD BC,10 ;вводим задержку
CALL 7997
POP HL
POP BC
PUSH BC
LD A,SPRXOR ;устанавливаем режим вывода XOR
CALL PTBL ;стираем изображение самолета
POP BC
JR JOY ;переходим в начало программы
; для изменения координат
PTBL .........
; Заголовок данных спрайта первого самолета, соответствующего полету вперед и назад
SAM1 DEFB 4
DEFB 0,0,5,0,1,5,1,0,5,1,1,5
; Данные для первого самолета
DEFB 0,0,5,0,95,254,56,66
DEFB 0,0,160,0,250,127,28,66
DEFB 61,1,1,5,13,0,0,0
DEFB 188,128,128,160,176,0,0,0
; Заголовок данных спрайта второго самолета, соответствующего повороту вправо
SAM2 DEFB 4
DEFB 0,0,5,0,1,5,1,0,5,1,1,5
; Данные для второго самолета
DEFB 0,0,5,0,11,95,78,35
DEFB 0,0,160,0,244,62,28,8
DEFB 29,1,1,2,2,0,0,0
DEFB 176,128,128,192,224,192,0,0
; Заголовок данных спрайта третьего самолета, соответствующего повороту влево
SAM3 DEFB 4
DEFB 0,0,5,0,1,5,1,0,5,1,1,5
; Данные для третьего самолета
DEFB 0,0,5,0,47,124,56,16
DEFB 0,0,160,0,208,250,114,196
DEFB 13,1,1,3,7,3,0,0
DEFB 184,128,128,64,64,0,0,0
а | б |
ORG 60000
ENT $
LD A,5
LD (23693),A
XOR A
CALL 8859
CALL 3435
; Основная часть программы
LD BC,#505 ;задаем исходное положение вертолета
KEY PUSH BC
CALL KBDJOY ;читаем данные из портов
POP BC
RRCA ;поворачиваем ручку джойстика вправо
; или нажимаем клавишу P -
; полет вертолета вправо
JR NC,KEY1
INC C
KEY1 RRCA ;поворачиваем ручку джойстика влево
; или нажимаем клавишу O -
; полет вертолета влево
JR NC,KEY2
DEC C
KEY2 RRCA ;поворачиваем ручку джойстика вниз
; или нажимаем клавишу A -
; полет вертолета вниз
JR NC,KEY3
INC B
KEY3 RRCA ;поворачиваем ручку джойстика вверх
; или нажимаем клавишу Q -
; полет вертолета вверх
JR NC,KEY4
DEC B
KEY4 RRCA ;при нажатии кнопки «огонь» джойстика
; или клавиши M - выход
RET C
; Подпрограмма вывода на экран изображения вертолета в двух фазах,
; каждая из которых соответствует одному из положений винта
XOR A ;формируем звуковой сигнал,
OUT (254),A ; имитирующий работу двигателя
CALL CHECK ;проверка достижения границ экрана
LD A,16
OUT (254),A
LD A,SPRXOR ;задаем режим вывода спрайта
LD HL,WERT1 ;устанавливаем адрес спрайта
PUSH BC
PUSH HL
CALL PTBL ;выводим вертолет в первой фазе
LD BC,5 ;задаем задержку между фазами
CALL 7997 ; вращения винта
POP HL
POP BC
LD A,SPRXOR ;режим вывода спрайта
PUSH BC
PUSH HL
CALL PTBL ;стираем вертолет в первой фазе
POP HL
POP BC
XOR A
OUT (254),A
; Вывод вертолета во второй фазе
LD A,16 ;звуковой сигнал
OUT (254),A
LD A,SPRXOR ;режим вывода спрайта
LD HL,WERT2 ;устанавливаем адрес спрайта
; с другим расположением винта
PUSH BC
PUSH HL
CALL PTBL ;выводим спрайт во второй фазе
LD BC,5
CALL 7997
POP HL
POP BC
LD A,SPRXOR ;режим вывода спрайта
PUSH BC
PUSH HL
CALL PTBL ;стираем с экрана спрайт во второй фазе
POP HL
POP BC
JR KEY
; Подпрограмма проверки границ экрана
CHECK LD A,C
AND A ;сравниваем координату X вертолета
; с заданной левой границей экрана
JR NZ,CONT1
INC C
CONT1 CP 29 ;сравниваем координату X вертолета
; с заданной правой границей экрана
JR NZ,CONT2
DEC C
CONT2 LD A,B ;задаем верхнюю границу экрана
AND A ;сравниваем координату Y вертолета
; с заданной верхней границей экрана
JR NZ,CONT3
INC B
CONT3 CP 21 ;сравниваем координату Y вертолета
; с заданной нижней границей экрана
RET NZ
DEC B
RET
; Подпрограмма чтения данных из портов клавиатуры и джойстика
KBDJOY IN A,(31) ;опрашиваем порт джойстика
LD E,A ;запоминаем полученные биты
; Проверяем, подключен ли порт джойстика (ручку невозможно
; повернуть сразу и вправо и влево - если оба бита установлены,
; порт не подключен)
AND 3
CP 3
JR NZ,KBDJ1 ;если да, переходим к опросу клавиатуры
LD E,0 ; иначе очищаем коллектор битов
KBDJ1 LD HL,DKEY ;адрес блока данных клавиатуры
KBDJ2 LD C,(HL) ;младший байт адреса порта
INC C ;проверка на 0 (конец блока данных)
DEC C
LD A,E ;значение коллектора в аккумулятор
RET Z ;выход, если конец данных
INC HL
LD B,(HL) ;старший байт адреса порта
INC HL
IN A,(C) ;читаем из порта
CPL ;инвертируем биты
AND (HL) ;проверяем конкретный бит
INC HL
JR Z,KBDJ3
LD A,(HL) ;если бит установлен, читаем код направления
OR E ; и объединяем с коллектором
LD E,A
KBDJ3 INC HL
JR KBDJ2 ;продолжаем чтение
; Данные управляющих клавиш:
; первое число - младший байт порта
; второе число - старший байт порта
; третье число - маска бита
; четвертое - код направления (аналогично кодам джойстика)
DKEY DEFB #FE,#FB,1,8 ;Q - вверх
DEFB #FE,#FD,1,4 ;A - вниз
DEFB #FE,#DF,2,2 ;O - влево
DEFB #FE,#DF,1,1 ;P - вправо
DEFB #FE,#7F,4,16 ;M - «огонь»
DEFB 0 ;метка конца блока данных
PTBL .........
; Заголовок первой фазы спрайта «вертолет»
WERT1 DEFB 7
DEFB 0,1,6,1,0,6,1,1,6,1,2,6
DEFB 2,0,6,2,1,6,2,2,6
; Данные первой фазы спрайта «вертолет»
DEFB 0,0,4,28,56,32,24,24
DEFB 0,0,0,1,2,2,4,4
DEFB 60,60,255,129,66,36,36,24
DEFB 0,0,0,128,64,64,32,32
DEFB 7,2,1,0,1,2,4,14
DEFB 255,36,36,255,0,0,0,0
DEFB 224,64,128,0,128,64,32,112
; Заголовок второй фазы спрайта «вертолет»
WERT2 DEFB 9
DEFB 0,0,6,0,1,6,0,2,6
DEFB 1,0,6,1,1,6,1,2,6
DEFB 2,0,6,2,1,6,2,2,6
; Данные второй фазы спрайта «вертолет»
DEFB 0,0,30,127,255,127,14,0
DEFB 0,0,0,129,231,129,24,24
DEFB 0,0,120,254,255,254,112,0
DEFB 0,0,0,1,2,2,4,4
DEFB 60,60,255,129,66,36,36,24
DEFB 0,0,0,128,64,64,32,32
DEFB 7,2,1,0,1,2,4,14
DEFB 255,36,36,255,0,0,0,0
DEFB 224,64,128,0,128,64,32,112
Глава 7 |
Глава 9