2.2.4 Управление окном от прерываний 2-го рода.
Выше, в разделе 2.1.5
мы рассмотрели процедуру FN h(), предназначенную для управления
спрайтами от клавиатуры с использованием прерываний второго рода Как мы
только что убедились, "оконная" технология, связанная со скроллингом
позволяет в некоторых случаях получать более интересные результаты, чем
технология работы со спрайтами. Было бы интересно объединить процедуру,
управления от клавиатуры с использованием прерываний второго рода с
процедурой скроллирования спрайта в окне, чем мы здесь и займемся на
примере процедуры FN о(s,x,y,1,n,d,г).
Эта процедура уже может стать основным приводом
(engine) Вашей будущей самостоятельной игры типа Space Raders, в
которой Вы управляете движением своей пушки "влево-вправо" и
расстреливаете проплывающих над Вами инопланетян. При этом движением
(скроллингом) "инопланетян" как бы управляет от прерываний 2-го рода
процедура FN о(), а движенчем спрайта "пушки" - процедура FN h( ) .
Параметры процедуры.
s параметр старт/стоп. Поскольку процедура
работает от пре рываний 2-го рода, то ее надо не только уметь
запустить, но и уметь остановить. Средствами БЕЙСИКа она не
остановится. Для этого и введен дополнительный параметр s. При задании
s=0 процедура стартует, а при з=1 - останавливается .
х,у - координаты окна. Они задаются для левого верхнего угла окна. Способ задания координат здесь принят в знакоместах.
0<=х<=31; 0<=у<=21
1 - ширина окна (в знакоместах 0... 31) п - номер спрайта, скроллируемого в окне.
d - direction - параметр, определяющий направление перемещения .
d=0 - скроллинг вправо. d=l - скроллинг влево.
г - флаг повтора: г=0 - есть повтор; г=1 - нет повтора.
Листинг 25
Загрузчик машинного кода процедуры скроллирования спрайта в окне с использованием IM2.
10 REM *** Загрузчик машинного кода
20 LET adr=49200: LET long=315: LET
check=81594: LET sum=0 30 FOR k=0 TO long-1: READ a 40 POKE (adr+k).a:
LET sum=sum+a 50 NEXT k
60 IF sumocheck THEN PRINT "??": STOP 100 REM *** Данные для машинного кода
110 DATA 243,042,011,092,001
120 DATA 004,000,009,126,254
130 DATA 000,032,009,017,252
140 DATA 207,237,083,250,207
150 DATA 251,201,017,139,192
160 DATA 237,083,250,207,014
170 DATA 008,009,086,009,094
180 DATA 009,126,050,100,193
190 DATA 009,126.050,108,193
200 DATA 009,126,230,001,050
210
|
DATA
|
107
|
,193,
|
009,
|
126,
|
230
|
220
|
DATA
|
001
|
,050,
|
106,
|
193,
|
062
|
230
|
DATA
|
001
|
,050,
|
104,
|
193,
|
050
|
240
|
DATA
|
109
|
,193,
|
050,
|
101,
|
193
|
250
|
DATA
|
123
|
,230,
|
024,
|
246,
|
064
|
260
|
DATA
|
103
|
,123,
|
230,
|
007,
|
183
|
270
|
DATA
|
031
|
,031 ,
|
031,
|
031,
|
130
|
280
|
DATA
|
111
|
,034,
|
102,
|
193,
|
251
|
290
|
DATA
|
201
|
,058,
|
107,
|
193,
|
254
|
300
|
DATA
|
000
|
,040,
|
006,
|
058,
|
100
|
310
|
DATA
|
193
|
,133,
|
061 ,
|
111,
|
058
|
320
|
DATA
|
101
|
,193,
|
071 .
|
016,
|
005
|
330
|
DATA
|
205
|
,240,
|
192,
|
006,
|
008
|
340
|
DATA
|
120
|
,050,
|
101 ,
|
193,
|
017
|
350
|
DATA
|
110
|
,193,
|
042,
|
102,
|
193
|
360
|
DATA
|
058
|
,107,
|
193,
|
254,
|
000
|
370
|
DATA
|
040
|
,003,
|
017,
|
152,
|
193
|
380
|
DATA
|
006
|
,003,
|
229,
|
197,
|
120
|
390
|
DATA
|
254
|
,001,
|
032,
|
004,
|
006
|
400
|
DATA
|
005
|
,024,
|
002,
|
006,
|
008
|
410
|
DATA
|
197
|
,213,
|
229,
|
058,
|
107
|
420
|
DATA
|
193
|
,254,
|
000,
|
032,
|
005
|
430
|
DATA
|
205
|
,042,
|
193,
|
024,
|
003
|
440
|
DATA
|
205
|
,071 ,
|
193,
|
225,
|
209
|
450
|
DATA
|
193
|
,036,
|
019,
|
016,
|
231
|
460
|
DATA
|
193
|
,225,
|
062,
|
032,
|
133
|
470
|
DATA
|
111
|
,048,
|
004,
|
062,
|
008
|
480
|
DATA
|
132
|
,103,
|
016,
|
204,
|
195
|
490
|
DATA
|
252
|
,207,
|
058,
|
109,
|
193
|
500
|
DATA
|
061
|
,050,
|
109,
|
193,
|
192
|
510
|
DATA
|
062
|
,003,
|
050,
|
109,
|
193
|
520
|
DATA
|
058
|
,108,
|
193,
|
017 >
|
063
|
530
|
DATA
|
000
|
,071 ,
|
033,
|
072,
|
213
|
540
|
DATA
|
167
|
,237,
|
082,
|
025,
|
016
|
550
|
DATA
|
253,
|
067,
|
017,
|
110,
|
193
|
560
|
DATA
|
058,
|
104,
|
193,
|
254,
|
000
|
570
|
DATA
|
040,
|
001,
|
126,
|
018,
|
035
|
580
|
DATA
|
019,
|
016,
|
243,
|
058,
|
106
|
590
|
DATA
|
193,
|
254,
|
000,
|
200,
|
062
|
600
|
DATA
|
000,
|
050,
|
104,
|
193,
|
201
|
610
|
DATA
|
167,
|
006,
|
003,
|
213,
|
026
|
620
|
DATA
|
031,
|
018,
|
245,
|
062,
|
021
|
630
|
DATA
|
131 ,
|
095,
|
048,
|
001 ,
|
020
|
640
|
DATA
|
241,
|
016,
|
242,
|
209,
|
058
|
650
|
DATA
|
100,
|
193,
|
071,
|
203,
|
030
|
660
|
DATA
|
035,
|
016,
|
251,
|
201,
|
167
|
670
|
DATA
|
213,
|
006,
|
003,
|
026,
|
023
|
680
|
DATA
|
018,
|
245,
|
123,
|
214,
|
021
|
690
|
DATA
|
095,
|
048,
|
001 ,
|
021,
|
241
|
700
|
DATA
|
016,
|
242,
|
209,
|
058,
|
100
|
710
|
DATA
|
193,
|
071,
|
203,
|
022,
|
043
|
720
|
DATA
|
016,
|
251 ,
|
201 ,
|
005,
|
004
|
730
|
DATA
|
000,
|
000,
|
000,
|
000,
|
000
|
Листинг 26
Дисассемблер процедуры, управляющей скроллингом спрайта в окне при использовании прерываний 2-го рода.
Адрес Маш.код Метка Мнемоника
СОЗО F3 С031 2А0В5С
С034 010400 С037 09
DI LD
LD ВС,#0004 ADD HL,BC
;Отключение прерываний. ;Указание на адрес, в
;котором располагаются ;параметры функции пользователя FN п().
;Вычисление адреса первого параметра.
Адрес Маш-код Метка Мнемоника
С038 7Е
С039 FEOO
СОЗВ 2009
СО3D 11FCCF
С040 ED53FACF
С044 FB С045 С9
A,(HL.) ;Проверка параметра
#00 ;s.
NZ,START ;Еслн не 0, то стартуем DE,#CFFC
;Иначе надо прекратить (#CFFA),DE обработку прерываний ;2-го рода.
Оформляем ;выход из процедуры ;FN h() - см.с. 56. ;Разрешение
прерываний .Возврат.
C04D 0Е08 C04F 09
С050 С051
С052 5Е С053 09
СО 54 7Е С055 3264С1
С058 09
С059 7Е
С05А 326СС1
C05D 09
С05Е 7Е
DE,IM2 (#CFFA),DE
C, #08 HL.BC
D.(HL) HL.BC
LD E,(HL) ADD HL.BC
A, (HL) (WIDTH) ,A
ADD HL.BC
LD A.(HL)
LD (NUMBER),A
ADD HL,ВС
LD A,(HL)
С046 118ВС0 START LD С049 ED53FACF LD
.Включение процедуры. .В процедуре FN h( ) ;
выставляется новый .адрес для обработки прерываний 2-го рода ;Переход
ко 2-му пара-,метру.
;Прием параметра х ;Переход к 3-му пара-,метру.
;Приен параметра у. ; Переход к 4-му параметру.
;Прием параметра 1. ;Сохранили ширину окна ,в программной переменной .
;Переход к 5 му пара-,метру.
;Прием параметра п. Сохранили в переменной ; Переход к 6-му пара-;метру.
;Прием параметра d
C05F £601
С061 326ВС1 С064 09
С065 7Е С066 Е601
326АС1
ЗЕ01
3268С1
С070 326DC1
СО 73 3265С1
AND #01
LD (DIREC).A
ADD HL,BC
LD A,(HL)
Адрес Маш-код Метка Мнемоника
AND #01
(REPIT),A A,#01 (FLAG),A
LD (COUNT),A
LD (COUNT8),A ;Маскирование старших ;битов.
;Сохранили в переменной. ;Переход к 7-му пара ;метру.
;Прием параметра г. ;Маскирование старших ;битов
;Сохранили в переменной.
инициализация флаговой Переменной. Инициализация троичного счетчика. Инициализация восьмеричного счетчика.
LD AND OR LD LD AND OR RRA RRA RRA RRA
СО 7 6 С077 С079 С07В С07С C07D C07F С080 С081 С082 С083 С084 С085
7В
Е618
F640
67
7В
Е607 В7 1F 1F 1F 1F 82 6F
A, E #18 #40 H,A A, E #07 A
ADD A,D
L, A
Поиск в дисплейном файле адреса, соответствующего коор динатам, заданным знакоместах-
Адрес выставляется в регистровой паре HL
LD (SCRAD) , HL
EI RET ;Сохранили его в про ;граммной переменной. ;Разрешение прерываний. ;Возврат
С086 2266С1
С089 FB С08А С9
Резидентная процедура, обрабатывающая
прерывания 2-го рода. Мы попадаем сюда из процедуры Fn h(), см с.56,
поскольку операцией #С049 там был выставлен именно этот адрес.
Адрес Маш.код Метка Мнемоника
COBB ЗА6ВС1 IM2 LD A,(DIREC) ;Направление^скроллинга.
С08Е FEOO CP #00 ;Проверка направления.
С090 2806 3R Z.LBL-1 :Если вправо, то переход
С092 ЗА64С1 LD A,(WIDTH) .Ширина окна.
С095 85 ADD A,L Получили х+1
С096 3D DEC А ;Получили х+1-1.
С097 6F LD L,A ;что равно координате х
последнего (правого) .столбца окна. Если
;скроллинг идет влево, ;то эта координата нужна ;как исходная.
;Проверка восьмиразрядного счетчика, ;Выставляется как параметр цикла.
;Элегантный пример того, ;как инструкция D3NZ
используется не для организации цикла, а для .организации
периодического ветвления. ;Прием спрайта в буфер. ;Установка значения в
восьмиразрядном счет ;чике.
;Адрес в буфере, указывающий на начало левого ;столбца спрайта. СОАА 2А66С1 LD HL,(SCRADD) .Экранный адрес
COAD ЗА6ВС1 LD A,(DIREC) Направление скроллинга.
LBL-1 LD А,(COUNT8) LD В, А D3NZ BRANCH
CDF0C0 0608 78
3265С1 116ЕС1
CALL GETSPR LD В,#08 BRANCH LD А,В
LD (COUNT8),А LD DE.BUFFER
Адрес Наш.код Метка Мнемоника
СОВО FE00 С0В2 2803
С0С6 С0С7 С0С8 С0С9 СОСС СО СЕ C0D0
СОВ4 1198С1
С0В7 0603
С0В9 Е5 СОВА С5
СОВВ 78 СОВС FE01 СОВЕ 2004
COCO 0605
С0С2 1802 С0С4 0608
C5 D5 E5
3A6BC1 FEOO 2005 CD2AC1
C0D3 1803 C0D5 CD47C1
C0D8 El C0D4 D1
CP #00 OR Z,LBL-2
LD DE,#C198
LBL-2 LD B,#03
LOOP-l PUSH HL PUSH ВС
LD А,В CP #01
OR NZ,LBL-3
LD B,#05
LOOP-2 В, #08
LBL-3
LOOP-2
PUSH ВС PUSH DE PUSH HL LD A,(DIREC) CP #00 OR NZ.LBL-4 CALL RIGHT
OR LBL-5 CALL LEFT
POP HL POP DE
;Вправо?
;Если движение вправо, ; то обход следующей опе-;рации.
.Адрес, с которого в буфере начинается правый
;столбец спрайта. ;Цикл по трем вертикаль-;ным рядам спрайта.
;Сохранение регистров на ;стеке перед организацией ;цикла
;Проверка, с каким рядом :мы имеем дело. ;Если не с последним, ;то обход следующей ;операции.
;В последнем ряду спрайта только пять линий, ,Обход.
;В двух верхних рядах ;спрайта по восемь ли ;ний. Это организация ;счетчика очередного .цикла.
Направление скроллинга.
.Если влево, то обход :Вызов процедуры ;скроллинга вправо. ;Обход.
;Вызов процедуры Скроллинга влево. ;Восстановление регистров :со стека перед оконча
АНИМАЦИЯ В РАСТРОВОЙ ГРАФИКЕ _Комментарий.
Адрес Маш.код Метка Мнемоника
POP ВС INC Н
INC DE
D3NZ LOOP-2
POP ВС
POP HL
LD A, #20
ADD A,L
LD L,A
3R NC,LBL-6
С0Е7 ЗЕ08 СОЕ9 84 • СОЕА 67
СОЕВ 10СС LBL-6 COED C3FCCF
LD A, #08 ADD A,H LD H,A
D3NZ LOOP-1 3P #CFFC
,нием цикла.
;Переход к соседней сциэу ;линии знакоместа на зк-гране .
;Переход к соседней снизу ;линии в шаблоне спрайта. ;Конец цикла. ;Восстановление регистров ;со стека перед окончанием цикла.
;Переход к соседнему сни-;зу знакоместу на экране.
;Если не произошло переполнение регистра L, то ;обход следующих опера ;ций.
;Если же такое переполнение произошло, то это
;означает, что мы вошли ;в новый экранный сегмент ;и регистр Н
увеличивается на 8 пунктов. ;Конец цикла. ;Выход через процедуру ;Fn
h(), см.с.56.
Процедура GETSPR.
(COUNT),A NZ
C0F0 3A6DC1 GETSPR LD A,(COUNT)
;Приняли данные из ;троичного счетчика. ;Сняли с него единицу. ,И снова его запомнили ;Если не ноль, значит
Адрес Маш-код Нетка Мнемоника
C0F8 ЗЕОЗ
COFA 326DC1
COFD ЗА6СС1
С100 113F00
С103 47
С104 2148D5
С107 А7
С108 ED52 С10А 19
С10В 10FD
C10D 43 С10Е 116ЕС1
CI 14 FEOO C110 2801
LD А,#03
LD (COUNT),А
LD A,(NUMBER)
LD DE,#D03F
LD В,A
LD HL,#D548
AND A
SBC HL,DE NEXT ADD HL,DE
D3NZ NEXT
ClJl 3A68C1 AGAIN LD A,(FLAG)
LD B,E LD DE,BUFFER
наш спрайт еще не весь "выехал" на зкран и при
нимать спрайт в буфер пока не надо. Выставляем число 3 в троичном
счетчике. Номер спрайта. Длина шаблона одного спрайта.
Создали счетчик. Адрес начала таблицы, в
которой размещаются спрайты (54600). Сброс флага переноса, чтобы он не
влиял на результат операции SBC. Выставление начального адреса для
первого спрайта
Возврат за отысканием адреса очередного спрайта.
Длина шаблона спрайта. Приняли адрес временного буфера для размещения спрайта
Проверка флага, связан ного с необходимостью повторного "прогона" спрайта
Проверка па ноль. Если ноль, то спрайт принимать не надо, идем в обход и обнуляем б) фер.
Адрес Маш.код Метка Мнемоника
C11A 23
С11В 13
С11С 10F3
C11E 3A6AC1
C121 FEOO
C123 C8
C124 3EOO
C126 3268C1
C129 C9
INC HL
INC DE
DJNZ AGAIN
LD A,(REPIT)
CP #00
RET Z
LD A, #00
LD (FLAG),A RET
С116 7Е LD A,(HL)
С119 12 BYPASS LD (DE),А
;Байт шаблона спрайта. ;Запомнили его в буфере
;Переход к очередному ;байту шаблона. .Переход к очередному ;байту
буфера. ;Если не все байты шабло ;на скопированы, то возврат
;Проверка необходиимости ;повтора.
;Если есть необходимость ;то выход, в
переменной ;FLAG остается единица. ;В противном случае обнуляем
переменную FLAG. ;Возврат в вызывающую ;процедуру,
Процедура RIGHT.
С12А А7 RIGHT AND А
С12В 0603 LD В,#03
C12D D5
C12E 1A LOOP-ЗА LD A,(DE)
RRA
LD (DE),A PUSH AF
;Сброс флага переноса. ;Начало внутреннего
;цикла. Установка ;параметра цикла. ;Сохранение регистра ;на время
работы подпро-;граммы.
;Взяли в аккумулятор ;байт иэ левого
вертикального столбца в шаблоне спрайта. .•Ротация вправо.
;Заменили байт в шаблоне ;Сохранили флаговый ре-
Адрес Маш-код Метка Мнемоника
С132 ЗЕ15
С134 83
С135 5F
С136 3001
С138 14
С139 F1
С13А 10F2
С13С D1
C13D ЗА64С1
С140 47
LD А,#15
ADD А,Е
LD Е,А
OR NC,LBL-7
INC D
C141 CB1E LOOP-4A RR (HL)
LBL-7 POP AF
DJNZ LOOP-ЗА POP DE
LD A, (WIDTH) LD B,A
;гистр на стеке. Важен ;флаг переноса. ; Сдвиг
на 21 байт для ;перехода к соседнему ;справа столбцу. .Указатель в
буфере ;спрайта переместили. ;Если не возникло пе ;реполнения, то
обход. ;Иначе наращиваем ;старший регистр, восстановили флаг С. ;Конец
цикла, восстановили указатель ;на буфер. ;Ширина окна. ;Ввели ее в
качестве ;счетчика.
;Ротация вправо байтов ;в окне.
;Переход в окне к соседнему знакоместу справа. ;Прокручиваем линию по ;всей ширине окна. ;Возврат в вызывающую ; процедуру
Процедура LEFT.
С147 А 7 LEFT
С148 D5
С149 0603 ;Сброс флага переноса ;Сохранение регистра ;на время работы подпро ;граммы.
;Начало внутреннего
Адрес Маш коп Метка мнемоника
C14F 7В
С150 D615
С152 5F
С153 3001
С155 15
С156 F1
С157 10F2
С159 DI
C15A 3A64C1
C15D 47
LD A,E
SUB #15
LD E,A
OR NC.LBL 8
DEC D
LBL-8 POP AF
D3NZ LOOP-3B
POP DE
LD A, (WIDTH)
LD B,A
С14В 1А LOOP-ЗВ LD А,(DE)
С14С 17 RLA
C14D 12 LD (DE),A
С14Е F5 PUSH AF
C15E CB16 LOOP-4B RL (HL) CI 60 2B DEC HL
:цикла. Установка параметра цикла ;Взяли в
аккумулятор ;байт из правого вертикального столбца в шаблоне спрайта.
;Ротация влево. ;Заменили байт в шаблоне.
.•Сохранили флаговый регистр на стеке.
Важен ;флаг переноса. ;Сдвиг назад на 21 байт ;для перехода к соседнему
;слева столбцу. ;Если не возникло двоичного займа, то обход. .Уменьшаем
старший байт восстановили флаг С. .Конец внутреннего цикла,
восстановили указатель ;на буфер. ;Ширина окна. ;Ввели ее в качестве
;счетчика.
.Ротация влево байтов :в окне.
;Переход к соседнему .знакоместу слева. ;Прогон на всю ширину .окна.
;Возврат в вызывающую ;процедуру.
ДВИЖЕНИЕ СПРАЙТА В ОКНЕ
Адрес Маш.код Метка Мнемоиика
DEFB #05 DEFB #00 DEFW #0000 DEFB #00
NOP
DEFB #00 DEFB #00 DEFB #00 DEFB #00
C16E 0000 . BUFFER DEFM #0000
.Ширина окна. ;Восьмеричный счетчик. ;Экранные координаты ;Флаг, указывающий на необходимость повтора ;"прогона" спрайта.
;Параметр повтора. Направление скроллинга Помер
спрайта ;Троичный счетчик для процедуры GETSPR. :Буфер для временного
;хранения шаблона ;спрайта.