ПЕЧАТЬ СПРАЙТОВ
(КООРДИНАТЫ ПЕЧАТИ
ЗАДАНЫ В ПИКСЕЛЯХ)
Да, эта тема требует особого
внимания, так как многочислен-
ные публикации до сих пор не
пролили на нее свет. К подобным
процедурам надобно относится
крайне осторожно, и здесь не мо-
жет быть однозначного совета или
примера. Я предложу лишь свои
соображения на эту тему.
Давайте посмотрим, в чем же
заключается эта сложность. Во-
первых, процедуры печати спрай-
тов по пикселям крайне медли-
тельны, и тут помочь может лишь
талант программиста, его опыт.
Во-вторых, каждая процедура ин-
дивидуальна, здесь нет однознач-
ного способа, который бы удов-
летворял всем требованиям - все
зависит от размеров спрайта. Все
эти сложности вообще-то относят-
ся лишь к одному элементу прог-
раммы - печати спрайта по пиксе-
лям по координате X, поскольку
по Y это делается элементарно.
Сегодня я предложу Вам два
различных способа печати - пер-
вый печатает спрайты размером от
1 до 3 знакомест в длину (высо-
та значения не имеет), при та-
кой печати дополнительной памя-
ти не используется; второй спо-
соб печати позволяет печатать
спрайты практически любого раз-
мера, но при подобном подходе
нужен будет буфер, размеры кото-
рого прямо пропорциональны раз-
мерам спрайта (вообще-то памяти
понадобится чуть больше).
Итак, предлагаю Вашему вни-
манию первый способ, он основан
на том, что свободных регистро-
вых пар хватает для того, чтобы
буфер организовать при помощи
их. Поскольку количество регис-
тров небольшое, то и размеры
спрайтов, которые можно напеча-
тать таким способом, тоже огра-
ничены (ограничены только в дли-
ну, высота спрайтов значения не
имеет). Ну, а теперь сама прог-
рамма, она предназначена для пе-
чати спрайтов размером 2 знако-
места в длину. Данные для печа-
ти готовятся уже рассмотренными
нами способами: ADRSPR - адрес
спрайта в памяти, LENHGT - дли-
на, высота спрайта. Добавляет-
ся еще одна переменная, которая
хранит координаты печати: CRDS -
Y, CRDS+1 - X.
140.
SETSPR LD DE,(CRDS) ;Берем координаты печати.
CALL ADRPIX ;Высчитываем по ним адрес в экране.
LD A,D ;Получаем номер бита в байте. В послед-
;ствии при помощи этого числа будет ор-
;ганизован счетчик.
AND 7
EX AF,AF' ;Чтобы не расходовать регистры, мы ме-
;няем A на альтернативный.
LD IX,(ADRSPR) ;В IX организуем указатель на данные
;спрайта.
LD A,(LENHGT+1);В A помещаем высоту спрайта.
LD C,A ;Организуем счетчик высоты.
SETSPR1 LD B,(IX+0) ;Помещаем в B первый байт спрайта.
LD E,(IX+1) ;В E помещаем второй байт спрайта.
EX AF,AF' ;Регистр A указывает на то, сколько на-
;до сдвинуть.
LD D,A
EX AF,AF'
LD A,D
LD D,0
AND A ;Проверяем A на ноль.
JR Z,SETSPR3 ;Если в A был 0, то сдвигать не надо.
SETSPR2 SRL B ;Перемещаем спрайт до нужного нам пик-
;селя.
RR E
RR D
DEC A ;Уменьшаем счетчик сдвигов.
JR NZ,SETSPR2 ;Если в A не 0, продолжаем сдвигать.
SETSPR3 PUSH HL ;Сохраняем временно HL.
LD A,(HL) ;Накладываем первый байт на экран.
OR B
LD (HL),A
INC L ;Переходим к следующему байту.
LD A,L ;Проверяем, не вышли ли за правый край
;экрана.
AND #1F
JR Z,SETSPR4 ;Если вышли, то далее накладывать не
;надо.
LD A,(HL) ;Если еще не вышли за край, то на-
;кладываем второй байт спрайта.
OR E
LD (HL),A
INC L
LD A,L ;Вновь проверяем на выход за экран.
AND #1F
JR Z,SETSPR4
LD A,(HL) ;Накладываем третий байт, если он попа-
;дает в пределы экрана.
OR D
LD (HL),A
SETSPR4 POP HL ;Восстанавливаем HL.
CALL DOWN ;Переходим к следующей пиксельной линии
;экрана снизу.
LD A,H ;Проверяем, не вылезла ли нижняя гра-
;ница спрайта за нижний край экрана.
CP #58
RET NC ;Если вышел,то печатать далее не надо и
;выходим.
INC IX ;Переходим к новым данным спрайта.
INC IX
DEC C ;Уменьшаем счетчик высоты.
JR NZ,SETSPR1 ;Если спрайт еще не напечатан, продол-
;жаем.
RET
---------------------------------------
3(C) 1993 Инфорком, (Прикладная графика)
---------------------------------------
ADRPIX LD A,E ;Высчитываем адрес в экране. Коор-
;динаты заданы в пикселях - E-Y, D-X.
AND A
RRA
SCF
RRA
AND A
RRA
XOR E
AND #F8
XOR E
LD H,A
LD A,D
RLCA
RLCA
RLCA
XOR E
AND #C7
XOR E
RLCA
RLCA
LD L,A
RET
ADRSPR DEFW 0 ;Хранит адрес данных спрайта.
LENHGT DEFW 0 ;Хранит длину и высоту спрайта.
CRDS DEFW 0 ;Координаты печати спрайта.
2
Программа получилась сравни-
тельно быстрой, но и у нее есть
резерв к совершенствованию. Если
использовать альтернативные ре-
гистры, то размер спрайта можно
увеличить.
Теперь рассмотрим, как же на-
печатать этой программой маску,
здесь не достаточно изменить OR
на AND. Во-первых, в регистр D
вместо 0 надо занести 255;
во-вторых, несколько изменятся
команды сдвига. Команда SRL B
помещает в 7 бит всегда 0, но
при печати маски туда должна по-
мещаться 1. Таких команд нет
(Если быть точным, то такие ко-
манды есть, просто они являются
недокументированными. Но такие
команды есть только для сдвига
влево.), и нам придется выпол-
нять их эмуляцию:
SETSPR2 SCF
RR B
RR E
RR D
DEC A
JR NZ,SETSPR2
В данном случае мы принуди-
тельно включали флаг C (флаг пе-
реноса), а команда RR B поме-
щает его в 7 бит регистра B.
Почему мы вынуждены были вы-
полнять все эти действия? Все
очень просто: если вспомнить
действие команды AND, то Вы уви-
дите, что на экране очищаются те
места, где в маске биты были
выключены, поэтому вместо 0 мы
заносим 255 (11111111 = 255),
дабы не получить эффект, кото-
рый можно наблюдать при прямом
копировании спрайта на экран.
Да, точка с координатами 0,0 на-
ходится в верхнем левом углу эк-
рана, а не как в бейсике, обра-
тите внимание.
Видимо, при печати спрайта с
маской вам придется подбирать
формат спрайта и маски такими,
чтобы обеспечить наивысшую ско-
рость печати.
Теперь давайте перейдем ко
второму методу печати. Вначале я
написал, что размер буфера пря-
мо пропорционален размеру спрай-
та, но в последний момент меня
осенила удачная мысль, и у меня
получилось напечатать спрайт с
наименьшими потерями, при таком
подходе на спрайт размером в эк-
ран понадобится буфер длиной 33
байта. Вот видите, всегда стоит
посидеть и подумать, никогда не
стоит зацикливаться на одной
идее. Вашему вниманию будет
предложен "новый" вариант прог-
раммы печати с использованием
буфера. Данные для печати гото-
вятся аналогично предыдущей про-
цедуре.
Скорость у этой процедуры
сравнительно нормальная. Прог-
рамма описана как набор проце-
дур, но я бы порекомендовал рас-
крыть эти процедуры, так как это
увеличит скорость печати. Печа-
тал я спрайт размером 2 знако-
места в длину.
140.
SETSPR LD DE,(CRDS) ;Берем координаты печати.
CALL ADRPIX ;Вычисляем по ним адрес в экране.
LD A,D ;Берем номер бита в байте. Впоследст-
;вии с помощью него мы организуем счет-
;чик.
AND 7
EX AF,AF' ;Заменяем A на альтернативный.
LD IX,(ADRSPR) ;В IX адрес данных спрайта.
LD A,(LENHGT+1);В A помещаем высоту спрайта.
LD C,A ;В C организуем счетчик высоты.
SETSPR1 PUSH BC ;Сохраняем счетчик.
PUSH HL ;Сохраняем адрес в экране.
CALL SPRBUF ;Переносим текущую линию спрайта в бу-
;фер.
EX AF,AF' ;Проверяем бит на 0, если ноль, то дви-
;гать буфер не надо.
LD B,A
EX AF,AF'
DEC B
INC B
JR Z,SETSPR2
LD C,B ;В C организуем счетчик сдвигов.
CALL ROLBUF ;Двигаем буфер.
SETSPR2 CALL PRNBUF ;Печатаем буфер.
POP HL
POP BC
CALL DOWN ;Переход к следующей пиксельной линии
;экрана снизу.
LD A,H ;Проверяем на выход за нижний край эк-
;рана.
CP #58
RET NC ;Выход, если вышли за край экрана.
DEC C
JR NZ,SETSPR1 ;Если в C не 0, продолжаем печатать.
RET
SPRBUF LD DE,BUFER ;В DE адрес буфера в памяти.
LD A,(LENHGT) ;Организуем счетчик в длину.
LD B,A
SPRBUF1 LD A,(IX+0) ;Копируем данные в буфер.
LD (DE),A
INC IX
INC DE
DJNZ SPRBUF1
XOR A ;Раньше мы обнуляли D, здесь мы обну-
;ляем дополнительный байт (буфер
;больше длины спрайта на 1 байт).
LD (DE),A
RET
ROLBUF EX DE,HL ;Для увеличения скорости мы адрес бу-
;фера заносим в HL, а данные из HL вре-
;менно переносим в DE.
ROLBUF1 LD HL,BUFER
LD A,(LENHGT) ;Организуем счетчик длины.
LD B,A
INC B ;Поскольку буфер больше длины спрайта
;на 1 байт, то и счетчик увеличиваем на
;1.
AND A ;Обнуляем флаг C.
ROLBUF2 RR (HL) ;Сдвигаем буфер.
INC HL
DJNZ ROLBUF2
DEC C
JR NZ,ROLBUF1
EX DE,HL ;Восстанавливаем значение HL.
RET
PRNBUF LD DE,BUFER ;В DE адрес буфера.
LD A,(LENHGT) ;Организуем счетчик длины спрайта.
INC A ;Вновь его увеличиваем на 1.
LD B,A
PRNBUF1 LD A,(DE) ;Накладываем спрайт на экран.
OR (HL)
LD (HL),A
INC DE
INC L
LD A,L ;Проверка на выход за правую границу
;экрана
AND #1F
RET Z ;Если вышли за границу, прекращаем пе-
;чать.
DJNZ PRNBUF1
RET
ADRSPR DEFW 0 ;Хранит адрес данных спрайта.
LENHGT DEFW 0 ;Хранит длину и высоту спрайта.
CRDS DEFW 0 ;Хранит координаты печати.
BUFER DEFB 0,0,0 ;Это буфер. В данном случае всего 3
;байта, так как мы печатали спрайт
;размером 2 знакоместа в длину.
2
На этом процедура заканчи-
вается. Заостряю Ваше внимание
на том, что размер буфера равен
длине (длина не в том смысле,
что размер всего спрайта, а име-
ется в виду размер спрайта в
длину) спрайта плюс 1 байт. Что-
бы напечатать этим способом мас-
ку, Вам надо будет последний
байт буфера не обнулять, а зано-
сить туда 255, а команду AND A в
процедуре сдвига спрайта заме-
нить на SCF.
Про атрибуты спрайтов я наме-
ренно не упоминал, тут вам са-
мим придется думать-гадать, пос-
кольку тут и так называемый клэ-
шинг, и прочие трудности.
Могу упомянуть и еще об од-
ном способе печати спрайтов по
пикселям, который использовался
в старых программах западных
программистов. Суть его заклю-
чается в том, что на одно движе-
ние спрайтов Вы рисуете 8 спрай-
тов с той только разницей, что
фигурка в спрайте каждый раз
сдвигается на 1 пиксель. Ну, а
при печати выбирается нужный
спрайт.
Еще одна статья подошла к
своему финалу.