ZX Forum
#04
19 ноября 1997 |
|
Технология спрайтов - часть 9: печать спрайтов (координаты заданы в пикселях).
ПЕЧАТЬ СПРАЙТОВ (КООРДИНАТЫ ПЕЧАТИ ЗАДАНЫ В ПИКСЕЛЯХ) Да, эта тема требует особого внимания, так как многочислен- ные публикации до сих пор не пролили на нее свет. К подобным процедурам надобно относится крайне осторожно, и здесь не мо- жет быть однозначного совета или примера. Я предложу лишь свои соображения на эту тему. Давайте посмотрим, в чем же заключается эта сложность. Во- первых, процедуры печати спрай- тов по пикселям крайне медли- тельны, и тут помочь может лишь талант программиста, его опыт. Во-вторых, каждая процедура ин- дивидуальна, здесь нет однознач- ного способа, который бы удов- летворял всем требованиям - все зависит от размеров спрайта. Все эти сложности вообще-то относят- ся лишь к одному элементу прог- раммы - печати спрайта по пиксе- лям по координате 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 пиксель. Ну, а при печати выбирается нужный спрайт. Еще одна статья подошла к своему финалу.
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября