СТРЕЛОЧКА БЕЗ СТРЕЛОЧНИКА...
Наверное многие, запуская X-REVERSY, или
FONT EDITOR, или тот же ASPECT видели
данное средство управления програмным
продуктом. И ,наверняка, попытки скодить
стрелочку не привели к желаемому: при
перемещении стрелочка моргала,дергалась,а
при попытке сделать ее же, но через
прерывания, изображение , скорее всего,
пропадало вовсе.
У меня тоже были похожие проблемы, но их
удалось преодолеть. Во-первых, надо
избавиться от кучи команд RRCA/RLCA , а
делается очень просто: вместо того чтобы
двигать изображение стрелки во время
вывода,надо сдвинуть его до вывода, и
положть в память (всего 8 изображений),
и не надо вычислять адрес вывода на
экране при помощи процедуры 8880 или ей
подобных - заполните таблицу...
А вот и код программы :
ORG 30000
CALL ZAPTAB ;заполняем таблицу адресов
CALL ZAPSTR ; делаем 8 изображений
; стрелки и маски для
;стрелки
CALL OUTMAR ;выводим стрелочку
LD HL, INTERR ; ставим свой обработчик
;прерываний
CALL IMON
MMMM EI ;ждем
HALT
LD A,(HOLDING+1) ;пока не будет нажата
AND A ;кнопка FIRE на KEMPSTONе или
JR NZ,MMMM ;SINCLAIRe или SPACE на
RET ;клаве,опосля чего уходим...
;Процедура обработки прерываний
INTERR DI ;на всякий пожарный
PUSH HL ;энто надо сохранить ...
PUSH DE
PUSH BC
PUSH AF
EXX
PUSH HL
PUSH BC
PUSH DE
EX AF,AF'
PUSH AF
PUSH IX
PUSH IY ;... на память
HOLDING LD A,2 ;а надо ли что-нить
AND A ;выводить на экран ?
JR Z,UPR ;нет !!!
CALL ZATIR ;затираем изображение стрелки
DEC A ;затереть и больше не ходить ?
JP Z,FIRE1 ;да !!!
XOR A ;сбросим флажок нажатия клавиши
LD (FLG),A
CALL KBDJOY ;проверим управление
RRCA ;если надо двигаем стрелку
PUSH AF
CALL C,RIGHT
POP AF
RRCA
PUSH AF
CALL C,LEFT
POP AF
RRCA
PUSH AF
CALL C,DOWN
POP AF
RRCA
PUSH AF
CALL C,UP
POP AF
RRCA
JR C,FIRE ;огонек - пойдем прикурим..
LD A,(FLG) ;кнопка не нажималась ?
AND A
JR NZ,UPR1 ;печально,но факт
INC A ;тогда шаг равен единице
LD (RAZ),A
UPR1 CALL OUTMAR ;выводим стрелочку
UPR POP IY ;все восстановим
POP IX
POP AF
EX AF,AF'
POP DE
POP BC
POP HL
EXX
POP AF
POP BC
POP DE
POP HL
EI
RET ;и пойдем себе ...
;огонек нажат,однако
FIRE LD A,1 ;затрем изображение и
FIRE1 LD (HOLDING+1),A ;перейдем на
JP UPR ;холостой ход
;двигемся вправо
RIGHT LD A,(POSX) ;координата по X
LD C,A
LD A,(RAZ) ;шаг стрелочки
ADD A,C
RET C ;за экраном (255+n=n-1 CY=1)
LD (POSX),A
MET LD A,1 ;нажата кнопка !
LD (FLG),A
LD A,(RAZ) ;быстрее ехать нельзя ?
CP 13
RET NC ;нельзя !
INC A ;разгоняемся
LD (RAZ),A
RET
;двигаемся влево
LEFT LD A,(POSX)
LD BC,(RAZ)
CP C ;координата меньше шага ?
RET C ;значит левее нельзя
SUB C ;двигаемся влево
LD (POSX),A
JP MET
;двигаемся вверх
UP LD A,(POSY)
LD BC,(RAZ)
CP C ;Выше Y=0 только ПЗУ
RET C
SUB C
LD (POSY),A
JP MET
;двигаемся вниз
DOWN LD A,(POSY)
LD BC,(RAZ)
ADD A,C
CP 191 ;Ниже Y=191 нам не надо
RET NC
LD (POSY),A
JP MET
;процедура установки прерываний
;на вход - HL адрес процедуры
;обработки прерываний
;портит : HL,BC,DE,AF
IMON
DI
LD A,24
LD (65535),A
LD A,195
LD (65524),A
LD (65525),HL
LD HL,#FE00
LD DE,#FE01
LD BC,256
LD A,H
LD (HL),#FF
LDIR
DI
LD I,A
IM 2
EI
RET
;вывод стрелочки
;с адреса TABLE должна быть таблица
;адресов вывода
;с адреса BUFFER должно быть пустое
;пространство длиной не менее 32 байт
; с адреса STR0 должны находится данные
;для стрелочки т.е. 8 спрайтов стрелочки
; и маски причем в таком виде :
;байт маски,байт стрелочки
;длина стрелочки 2 байта (длина маски
;тоже 2 байта) высота 16 пикселей,
;т.е. с STR0 должно быть 512 байт.
OUTMAR LD BC,(POSX) ;берем позицию вывода
LD (ZTPOSX),BC ;кладем ее в процедуру
;затирания
LD E,B
LD D,0
LD IX,TABLE ;находим начальный адрес
ADD IX,DE ;вывода в таблице
ADD IX,DE
LD (ZATIR+2),IX ;кладем его в процедуру
LD IY,BUFFER ;затирания,в IY - буфер
;в который будет сохранена часть
;экрана попавшая под стрелку
LD A,C ;вычисляем спрайт для вывода
AND 7
LD B,A
OUTMX LD HL,STR0
AND A
JR Z,OUTM2
LD DE,64
OUTM1 ADD HL,DE
DJNZ OUTM1
OUTM2 LD B,#10
SRL C ;в C - колонка
SRL C
SRL C
LD A,C
INC A
AND #1F ;у конца экрана
JR Z,OUTM7 ;да !!!
OUTM4 EX DE,HL
LD A,(IX)
CP #FF ;что ниже экрана - не выводим
RET Z ; ...
ADD A,C ;адрес вывода на экран
LD L,A
LD H,(IX+1)
INC IX
INC IX
PUSH BC
EX DE,HL
LD B,(HL) ;берем маску
INC HL
LD C,(HL) ;берем данные
INC HL
LD A,(DE)
LD (IY),A
INC IY
AND B ;накладываем
OR C
LD (DE),A ;выводим
INC DE
LD A,(DE)
LD (IY),A
LD B,(HL)
INC HL
LD C,(HL)
AND B
OR C
LD (DE),A
INC IY
OUTM6 INC HL
POP BC
DJNZ OUTM4
RET
OUTM7 EX DE,HL ;то же самое,только
LD A,(IX) ;выводится один байт вместо
CP #FF ;двух
RET Z
ADD A,C
LD L,A
LD H,(IX+1)
INC IX
INC IX
PUSH BC
EX DE,HL
LD B,(HL)
INC HL
LD C,(HL)
INC HL
INC HL
INC HL
LD A,(DE)
LD (IY),A
INC IY
AND B
OR C
LD (DE),A
POP BC
DJNZ OUTM7
RET
;процедура,восстанавливающая изображение
;за стрелкой
ZATIR LD IX,#4000 ;здесь будет другое
LD HL,BUFFER
LD B,#10
LD A,(ZTPOSX)
SRL A
SRL A
SRL A
LD C,A
LD A,C
INC A
AND #1F
JR Z,ZATIR3
ZATIR1 LD A,(IX)
CP #FF
RET Z
ADD A,C
LD E,A
LD D,(IX+1)
LDI
LDI
INC BC
INC BC
INC IX
INC IX
DJNZ ZATIR1
RET
ZATIR3 LD A,(IX)
CP #FF
RET Z
ADD A,C
LD E,A
LD D,(IX+1)
LDI
INC BC
INC IX
INC IX
DJNZ ZATIR3
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
DEC C
LD A,E
RET Z ;если 0 то это конец ...
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
;процедура,изготовляющая 8 спрайтов для
;стрелочки,по STR0 должен находиться
;спрайт в вышеописанном формате
ZAPSTR LD IX,STR0
ZAPSTRX PUSH IX
LD HL,STR0
LD DE,64
LD C,8
ADD HL,DE
PUSH HL
POP IY
ZAPST2 POP IX
PUSH IY
LD B,#10
ZAPST1 CALL ZAPBYT
INC IX
INC IY
LD A,(IX)
AND A
CALL ZAPBY1
INC IX
INC IX
INC IX
INC IY
INC IY
INC IY
DJNZ ZAPST1
DEC C
JR NZ,ZAPST2
POP IX
RET
ZAPBYT LD A,(IX)
SCF
ZAPBY1 RRA
LD (IY),A
LD A,(IX+2)
RRA
LD (IY+2),A
RET
;заполняет таблицу адресов с адреса
;TABLE
ZAPTAB LD IX,TABLE
LD HL,#4000
CALL ZAPADR
LD HL,#4800
CALL ZAPADR
LD HL,#5000
CALL ZAPADR
LD (IX),#FF
LD (IX+1),#FF
LD (IX+2),#FF
RET
ZAPADR LD DE,#20
LD C,8
ZAPAD2 PUSH HL
LD B,8
ZAPAD1 LD (IX),L
LD (IX+1),H
INC IX
INC IX
INC H
DJNZ ZAPAD1
POP HL
ADD HL,DE
DEC C
JR NZ,ZAPAD2
RET
;данные для опроса клавиатуры :
;порт мл.байт,порт ст.байт,маска,вес
DKEY DEFB #FE,#FB,1,8,#FE,#FD,1,4,#FE,#DF
DEFB 2,2
DEFB #FE,#DF,1,1,#FE,#7F,1,16
DEFB #FE,#EF,16,2,#FE,#EF,8,1,#FE,#EF,4,4
DEFB #FE,#EF,2,8,#FE,#EF,1,16
DEFB 0
;буфер для куска экрана
BUFFER DEFS 32
;данные для стрелки
STR0 DEFB 159,0,255,0,135,32,255,0,131,48
DEFB 255,0
DEFB 129,56,255,0,128,60,255,0,128,62,255
DEFB 0
DEFB 128,63,255,0,128,56,255,0,193,36,255
DEFB 0
DEFB 240,4,255,0,248,2,255,0,252,2,255,0
DEFB 252,0,255,0,255,0,255,0,255,0,255,0
DEFB 255,0,255,0
DEFS 480
;переменные стрелки
ZTPOSX DEFB 0
ZTPOSY DEFB 0
FLG DEFB 0
RAZ DEFB 1
POSX DEFB 32
POSY DEFB 32
;таблица адресов
TABLE
Теперь о том, почему у меня процедура
вывода стрелки фактически состоит из двух
процедур: дело в том, что быстрее
проверить один раз в начале, а не 16 раз
во время вывода. Кстати, то, что в
вышеприведенном примере стрелочка была
реализована через прерывания, вовсе не
значит,что это так и должно быть: делать
стрелочку через прерывания имеет смысл
тогда, когда на экран выводится
динамическое изображение (вроде надписи
ASPECT).Ну вот,пока и все ,до встречи !
(C) Trusov Ilya