УПРАВЛЕНИЕ СПОМОЩЬЮ КЛАВИАТУРЫ
УПРАВЛЕНИЕ С ПОМОЩЬЮ КЛАВИАТУРЫ
При разработке игровых программ немыслимо обойтись без опроса клавиатуры. Действительно, чтобы во время игры управлять спрайтами, перемещая их хотя бы по четырем направлениям, программа обязана безошибочно различать одну из четырех нажатых клавиш. Например, O должна соответствовать движению влево, P - вправо, Q - вверх и A - вниз. В Бейсике, как вы помните, для этой цели мы пользовались функцией INKEY$, а одна из возможных программ, «узнающих», к примеру, символ P, могла бы выглядеть так:
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 reg,(C) - ввод байта из порта и помещение его в регистр, причем reg - один из регистров A, B, C, D, E, H или L, а адрес порта содержится в паре BC (в C - младший байт адреса, в B - старший).
IN A,(port) - ввод байта из порта с номером port и помещение его в аккумулятор. При этом полный 16-разрядный адрес порта составляется из значения port (младший байт) и значения аккумулятора (старший байт).
Применяя одну или другую команду, можно получить два способа опроса клавиатуры. Первый из них очень похож на использование функции IN в Бейсике. Напомним, что все клавиши группируются по полурядам, то есть по 5 клавиш. Каждому полуряду соответствует определенный порт. Адреса «клавиатурных» портов отличаются только старшим байтом, а младший всегда равен 254 (#FE). Все эти адреса представлены в табл. 8.1 в десятичной, шестнадцатеричной и двоичной нотации. Предположим, что нам нужно определить нажатие клавиши M, тогда в регистровую пару BC необходимо записать адрес 32766. Из порта считываем значение для полуряда, а затем, чтобы определить нажатие конкретной клавиши, проверяем соответствующий ей бит (от бита 0 - для крайних клавиш до 4-го бита - для центральных). Так как клавиша M занимает третье место от края, то она будет определяться состоянием 2-го бита полученного из порта байта. Если этот бит окажется сброшенным в 0, это будет означать, что клавиша нажата. (Из-за упрощенной аппаратной реализации клавиатуры, примененной в ZX Spectrum, достоверно (в общем случае) можно определить одновременное нажатие не более двух каких-либо клавиш - Примеч. ред.)
Таблица 8.1. Адреса портов для опроса клавиатуры
Полуряд | 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 |
Второй способ принципиально не отличается от первого. Перед чтением в аккумулятор помещается старший байт адреса соответствующего порта, а младший байт задается в явном виде в команде 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, в любой момент можно очистить экран и начать рисовать новую «картину».
В заключение этого раздела приведем еще один пример управления с помощью клавиатуры, с которым мы иногда встречаемся, загружая те или иные игровые программы. Он полезен еще и тем, что дает вариант решения некоторых побочных проблем, таких, например, как учет ограничений на перемещение курсора (или спрайта) по экрану, введение дополнительных функций управления и некоторые другие.