ZX Forum #04
19 ноября 1997

Технология спрайтов - часть 9: печать спрайтов (координаты заданы в пикселях).

<b>Технология спрайтов</b> - часть 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 пиксель.  Ну, а
при  печати  выбирается   нужный
спрайт.
   Еще  одна  статья  подошла  к
своему финалу.



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

Help - Описание оболочки электронного издания "ZX-FORUM 4".

Секреты успешного дизайна - глава для книги "Дизайн Ваших программ"

Экранные эффекты - Бегущая строка из R-Type.

Экранные эффекты - гашения экрана из Zynaps.

Экранные эффекты - "сворачивание" экрана из Comando Tracer.

Экранные эффекты - плавное "затухание" экрана из Сommando Tracer.

Экранные эффекты - модификация символьного набора для получения оригинального стилизованного шрифта из игры Rockstar.

Экранные эффекты - "выбегающая строка" из игры Rockstar.

Экранные эффекты - "наливающийся" экран из игры Rockstar.

Экранные эффекты - сложный многоступенчатый эффект из игры Bubbler.

Новые 40 лучших процедур - скроллинг экрана, слияние двух картинок, инвертирование экрана, поворот символов, замена атрибутов, заливка замкнутого контура, вычисление адресов в экране, копирование части экрана и т.д.

Технология спрайтов - часть 1: введение.

Технология спрайтов - часть 2: охота на спрайты (поиск и выдирание).

Технология спрайтов - часть 3: форматы спрайтов.

Технология спрайтов - часть 4: форматы спрайтов с маской.

Технология спрайтов - часть 5: структура спрайтовых блоков (как уживаются в памяти спрайт и маска, какие данные помогают нам оперативно находить адрес спрайта в памяти и многое другое.)

Технология спрайтов - часть 6: подготовка данных к печати.

Технология спрайтов - часть 8: печать спрайтов (координаты заданы в знакоместах).

Технология спрайтов - часть 9: печать спрайтов (координаты заданы в пикселях).

Технология спрайтов - часть 10: обзор программ для работы со спрайтами и графикой.

Мир звуков Спектрума - глава 1: Физика звука.

Мир звуков Спектрума - глава 2: Оператор BEEP, Создание эффектов на BEEPе, Создание музыки на BEEPе.

Мир звуков Спектрума - глава 3: Как получается звук (устройство BEEP'ра и способы звукоизвлечения).

Мир звуков Спектрума - глава 4: Программирование звука на ассемблере.

Мир звуков Спектрума - глава 4.1: Программирование звуковых эффектов - Тон, Шум, Комплексы эффектов.

Мир звуков Спектрума - глава 4.2: Программирование звуковых эффектов - Управление громкостью.

Мир звуков Спектрума - глава 4.3: Программирование звуковых эффектов - Управление тембром.

Мир звуков Спектрума - глава 4.4: Программирование звуковых эффектов - Программирование музыки.

Мир звуков Спектрума - глава 4.5: Программирование звуковых эффектов - Многоголосые мелодии (полифония).

Мир звуков Спектрума - глава 4.6: Обработка внешних сигналов - оцифровка.

Мир звуков Спектрума - глава 4.7: Обработка внешних сигналов - Реверберация.

Мир звуков Спектрума - глава 4.8: Синтезирование речи.

Мир звуков Спектрума - глава 4.9: воспроизведение звука на прерываниях.

Мир звуков Спектрума - глава 5: Оператор PLAY для музыкального сопроцессора AY- 3-8910 (AY-3-8912).

Мир звуков Спектрума - глава 5.1: Создание эффектов оператором PLAY.

Мир звуков Спектрума - глава 5.2: Создание музыки на PLAYе.

Мир звуков Спектрума - глава 6.1: описание регистров музыкального сопроцессора AY- 3-8910 (AY-3-8912).

Мир звуков Спектрума - глава 6.2: Программирование эффектов и музыки под музыкальный сопроцессор AY- 3-8910 (AY-3-8912).

Мир звуков Спектрума - глава 7: Обзор программного обеспечения ZX-Spectrum для создания звуков и музыки.

Мир звуков Спектрума - глава 7.1: Редактор звуковых эффектов SUPER SOUND.

Мир звуков Спектрума - глава 7.2: Музыкальный редактор Wham the Music Box.

Мир звуков Спектрума - приложения 1, 2: листинги звуковых эффектов SUPER SOUND'а, советы по использованию ассемблера.


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

Похожие статьи:
Ария - Сборник лучших песен Самой крутой рок-группы 'АРИЯ' (часть вторая).
12 тайных книг - RPG основанная на сказаниях и былях Древней Руси.
Развлечения - ответы на головоломки.
Hовости - от LDIR'а.

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