Aspect #07
07 марта 1998

Программирование - Стрелочка.

<b>Программирование</b> - Стрелочка.
       СТРЕЛОЧКА БЕЗ СТРЕЛОЧНИКА...

 Наверное многие, запуская 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











Другие статьи номера:

BBS-Лист - Список Vicomm-совместимых BBS.

Доработки Sorpa - Индикатор для сигнализации драйвера дисковода. Тумблер для переключения дисководов.

Конкурс - Конкурс на лучшую эмблему/логотип для FunTop'98.

Начнем с азов - Электрическая сеть и закон Ома.

Новинка - О новинках ПО: игра Margo.

Новости - Закрытие гейта SPbZXNet <=> Internet. Новая модемная газета SPbZXWeek.

От авторов - Целый месяц ни слуху, ни духу...

Праздник - С весной вас, люди!!!

Про Life - Компьютер - мужчина хороший...

Программирование - Стрелочка.

Хит-парад - 10-ка лучших игр.

Юмор - Распределение вредоносных программ.


Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Как это было в Ленинграде - 2011 год. Настоящий ZX Spectrum
Шелезяка - Приставка к телефону: усилитель сигнала телефонной линии.
Улыбнитесь - Специaльнo для гpядущегo СисОпникa.
Чугуний - Турбо для Байта.
Что нового - О новинках в Минске: Insanity #2, C-Week #19, Born Dead #0B.

В этот день...   21 ноября