бегущий строка
Как написать игру на ассемблере для ZX Spectrum — Издательский дом «Питер»
Книги
Издательство
Отдел сбыта
Проекты
English version
Главная
Новинки
Новости
Рейтинг продаж
Файлы/Download
Клуб Профессионал
Партнерская программа
Ваш кабинет
Если вы уже зарегистрированы, введите ваши данные:
Логин
Пароль
Регистрация | Вспомнить пароль
Библиотека: Евдокимов А. А. Капульцевич. Как написать игру на ассемблере для ZX Spectrum
ГЛАВА СЕДЬМАЯ,
в которой вы научитесь создавать все элементы игрового пространства
Как вы уже знаете, игровое пространство составляют перемещающиеся спрайты, которые появляются бегущий строка исчезают на экране во время игры, бегущий строка неподвижный или медленно перемещающийся пейзаж. В предыдущих главах мы частично показали, каким образом можно создавать спрайты, используя привычные символы UDG бегущий строка средства ассемблера. Однако такой способ пригоден лишь для небольших изображений, да бегущий строка то, если их общая площадь не превышает двух десятков знакомест. Теперь пора нам подробно познакомиться с общим случаем, когда размеры спрайтов могут быть практически любыми, бегущий строка их количество ограничено лишь сюжетом игры, вашей фантазией бегущий строка трудолюбием. Есть бегущий строка другая, не менее важная задача - создание таких процедур вывода спрайтов на экран бегущий строка рисования пейзажей, которые бы требовали на это минимального времени и, желательно, были не слишком громоздкими.
БЫСТРЫЙ ВЫВОД СПРАЙТОВ
Что бы ни появлялось на экране во время игры - спрайты или какие-либо тексты - каждое изображение состоит из отдельных символов. Таким образом, чтобы быстро выводить сложные картинки, нужно начать с самого простого - печати произвольного символа в текущую позицию экрана. Раньше мы поручали эту задачу процедуре RST 16, которая неплохо справлялась со своими обязанностями до тех пор, пока отдельные кадры изображения не слишком быстро сменяли друг друга. Безусловно, ее бегущий строка дальше вполне можно использовать в подобных ситуациях. Однако, когда речь заходит о создании динамических картинок, бегущий строка именно такие мы чаще всего наблюдаем после загрузки наиболее интересных игровых программ, она уже перестает нас удовлетворять. Изображения начинают временами пропадать и, конечно же, теряется естественное восприятие событий.
Во 2-й главе мы приводили пример небольшой программки на Бейсике, которая печатала букву A, бегущий строка сказали, что по такому принципу работает любая процедура вывода символов на экран. Теперь перепишем ее на ассемблере бегущий строка как основу используем для составления подпрограмм вывода спрайтов. До того, как этот фрагмент появится в программе, необходимо в регистровой паре DE задать адрес символа в наборе, в HL - рассчитанный начальный адрес знакоместа:
.........
LD B,8
MET1 LD A,(DE)
LD (HL),A
INC DE
INC H
DJNZ MET1
.........
Ниже приводится процедура PRSYM, которая, так же как бегущий строка RST 16, выводит на экран отдельные символы в текущее знакоместо экрана с учетом заданных атрибутов, но работает она приблизительно в 10 раз быстрее. Конечно же даром ничего не дается бегущий строка увеличение быстродействия достигается за счет урезания выполняемых ею функций. Например, с ее помощью невозможно выводить тексты на принтер, печатать символы UDG бегущий строка псевдографики, бегущий строка также ключевые слова Бейсика. Не «воспринимает» она бегущий строка управляющие коды. Тем не менее, PRSYM в тех или иных модификациях используется дальше в нескольких программах. Например, в одной из них показывается, как рисовать на экране лабиринты, различные орнаменты или рамки произвольной конфигурации.
Описание процедуры начнем с команды BIT, которая здесь встречается впервые бегущий строка выполняет проверку состояния отдельных битов. Значение бита отражает флаг нуля - если бит установлен, выполняется условие NZ, в противном случае - Z (т. е. если проверяемый бит равен нулю, то Z=1). Команда имеет формат BIT n,s, где n - номер бита, задаваемый числом от 0 (младший) до 7 (старший), бегущий строка s - операнд, которым может быть один из регистров общего назначения или (HL), (IX+d) бегущий строка (IY+d). Попутно стоит сказать о еще двух командах этой группы: SET n,s - установка бита с номером n бегущий строка RES n,s - сброс бита. В первом случае в бит n записывается единица, во втором - нуль. В этих командах операнды бегущий строка формат такие же, как бегущий строка в команде BIT, но флаги остаются без изменений.
PRSYM PUSH BC
PUSH DE
PUSH HL
LD L,A ;по коду символа вычисляем его адрес
LD H,0 ; в текущем наборе
ADD HL,HL
ADD HL,HL
ADD HL,HL
LD DE,(23606)
ADD HL,DE
LD DE,(23684) ;адрес текущей позиции печати
; в видеобуфере
EX DE,HL
PUSH HL
LD B,8
PRS1 LD A,(DE)
BIT 3,(IY+87) ;режим INVERSE 1
JR Z,PRS2
CPL ;если включен, инвертируем байт
PRS2 BIT 1,(IY+87) ;режим OVER 1
JR Z,PRS3
XOR (HL) ;если включен, объединяем
; с изображением на экране
PRS3 LD (HL),A
INC DE
INC H
DJNZ PRS1
POP HL
PUSH HL
LD A,H ;вычисляем адрес в области атрибутов
AND #18
RRCA
RRCA
RRCA
ADD A,#58
LD H,A
LD A,(23695)
LD (HL),A ;записываем байт атрибутов в видеобуфер
POP HL
INC L ;переходим к следующей позиции печати
JR NZ,PRS4 ;если 0, то это означает, что позиция
; печати перешла в следующую треть экрана
LD A,H ;в этом случае увеличиваем
ADD A,8 ; старший байт адреса на 8
LD H,A
CP #58
JR C,PRS4
LD H,#40 ;если выход из последней трети, то
; возвращаемся в начало видеобуфера
PRS4 LD (23684),HL
POP HL
POP DE
POP BC
RET
Используем сначала эту процедуру для вывода буквенной или цифровой информации. Конечно, можно представить себе ситуацию, когда печатается всего один символ, например, уровень игры, но все же значительно чаще приходится иметь дело с текстовыми строками или даже целыми страницами бегущий строка тут процедуры PRSYM явно недостаточно. Во-первых, необходимо уметь позиционировать курсор подобно тому, как это выполняет AT в Бейсике, во-вторых, желательно иметь возможность в любой момент переводить курсор на следующую строку, бегущий строка в-третьих, - вспомним еще несколько атрибутов печати, которые применяются в команде RST 16: INK, PAPER, BRIGHT, FLASH, INVERSE бегущий строка OVER. Для того чтобы вывод текстов на экран не вызывал особых проблем, необходима процедура, хорошо «понимающая» все управляющие коды, используемые при печати, бегущий строка настраивающая в соответствии с ними системные переменные, используемые подпрограммой PRSYM. Ниже приводится текст такой процедуры, которую мы назвали WRITE, с краткими комментариями к отдельным группам строк.
Прежде чем привести ее текст, объясним смысл вновь встретившейся здесь команды. Это инструкция EX (SP),HL, которая обменивает содержимое регистровой пары HL со значением, находящимся на вершине машинного стека: то, что было в HL, помещается на вершину стека, бегущий строка два байта со стека перемещаются в HL. Значение регистра SP при этом не изменяется. Обратите внимание на то, как в подпрограмме WRITE2 осуществляется переход по выбранному адресу: число заносится в стек командой EX (SP),HL, бегущий строка затем выполняется команда RET.
Другой момент, требующий пояснения, это процедура, расположенная в ПЗУ по адресу 8, благодаря чему ее можно вызывать командой RST. Она используется интерпретатором для выдачи различных сообщений бегущий строка с ее помощью можно в любой момент остановить практически любую программу в кодах при возникновении критической ошибки. Код сообщения, уменьшенный на единицу (например, -1 для 0 OK), записывается в директиве DEFB непосредственно за командой RST 8.
WRITE LD A,(HL) ;берем очередной символ из строки
INC HL
AND A
RET Z ;вывод символов до кода 0
CP " "
JR C,WRITE2 ;если управляющий код (< 32)
WRITE1 CALL PRSYM
JR WRITE
; Выбор из таблицы адреса перехода в зависимости от кода
WRITE2 PUSH HL
PUSH BC
LD HL,TABLE ;адрес таблицы
LD C,A ;сохраняем код в C
WRITE3 LD A,(HL) ;читаем код из таблицы
INC HL
AND A
JR Z,WRITE5 ;если встречен маркер конца таблицы
CP C
JR Z,WRITE4 ;если код найден
INC HL ;пропускаем 2 байта адреса
INC HL
JR WRITE3 ;проверяем следующий код
WRITE4 POP BC
LD A,(HL) ;берем из таблицы адрес перехода
INC HL
LD H,(HL) ;помещаем его в HL
LD L,A
EX (SP),HL ;восстанавливаем HL, бегущий строка адрес записываем
; на вершину стека
RET ;переходим по адресу с вершины стека
WRITE5 POP BC ;если код отсутствует в таблице,
POP HL ; то восстанавливаем регистры
LD A,"?" ; бегущий строка печатаем символ ?
JR WRITE1
; Перевод строки
PR_13 PUSH HL
LD HL,(23684) ;адрес текущей позиции печати
LD A,L
AND %11100000 ;возвращаемся к началу строки
ADD A,#20 ;переходим к следующей строке
LD L,A
JR NZ,PR13_1 ;если не перешли в следующую треть
LD A,H
ADD A,8 ;старший байт адреса увеличиваем на 8
LD H,A
CP #58 ;проверяем, был ли выход за пределы экрана
JR C,PR13_1
LD H,#40 ;переводим позицию печати в верхнюю
; строку экрана
PR13_1 LD (23684),HL ;возвращаем рассчитанный адрес
; позиции печати
POP HL
JR WRITE
; Цвет «чернил» INK
PR_16 LD A,(HL) ;читаем следующий байт из строки
AND %111 ;выделяем 3 младших бита (значения 0...7)
PUSH BC
LD B,%11111000 ;в регистре B - маска битов для INK
PR16_1 LD C,A
LD A,(IY+85) ;23695
AND B ;освобождаем биты предыдущего атрибута
OR C ; бегущий строка записываем на их место новое значение
LD (IY+85),A ;возвращаем байт атрибутов
PR16_2 POP BC
INC HL
JR WRITE
; Цвет «бумаги» PAPER
PR_17 LD A,(HL) ;с цветом PAPER аналогично INK
AND %111
RLCA ; только предварительно сдвигаем
RLCA ; биты на свое место
RLCA
PUSH BC
LD B,%11000111
JR PR16_1
; Мерцание FLASH
PR_18 LD A,(HL)
AND 1
PUSH BC
LD B,%01111111
PR18_1 RRCA
JR PR16_1
; Яркость BRIGHT
PR_19 LD A,(HL)
AND 1
PUSH BC
LD B,%10111111
RRCA
JR PR18_1
; Инверсия INVERSE (3-й бит в системной переменной P_FLAG)
PR_20 LD A,(HL)
AND 1
PUSH BC
LD B,%11110111
RLCA
RLCA
PR20_1 RLCA
LD C,A
LD A,(IY+87)
AND B
OR C
LD (IY+87),A
JR PR16_2
; Режим наложения OVER (1-й бит в системной переменной P_FLAG)
PR_21 LD A,(HL)
AND 1
PUSH BC
LD B,%11111101
JR PR20_1
; Позиционирование курсора AT
PR_22 LD A,(HL) ;берем номер строки
CP 24 ;если больше 24, то выход позиции
JR NC,OUTSCR ; печати за пределы экрана
INC HL
PUSH DE
PUSH HL
CALL 3742 ;вычисляем адрес начала строки
POP DE
LD A,(DE) ;берем номер столбца
CP 32 ;если больше 32, то выход позиции
JR NC,OUTSCR ; печати за пределы экрана
INC DE
ADD A,L
LD L,A
LD (23684),HL ;запоминаем адрес новой позиции
POP HL
EX DE,HL
JP WRITE
OUTSCR RST 8 ;сообщение Бейсика
DEFB 4 ; «Out of screen»
PRSYM .........
; Таблица переходов на процедуры для управляющих кодов
TABLE DEFB 13
DEFW PR_13
DEFB 16
DEFW PR_16
DEFB 17
DEFW PR_17
DEFB 18
DEFW PR_18
DEFB 19
DEFW PR_19
DEFB 20
DEFW PR_20
DEFB 21
DEFW PR_21
DEFB 22
DEFW PR_22
DEFB 0
Покончив с текстами, перейдем к описанию программы, которая выводит на экран спрайт произвольной конфигурации, но сначала стоит сказать несколько слов о том, что собой представляют спрайты с точки зрения программиста. Мы уже описывали работу со спрайтами бегущий строка вам известно, что в принципе - это блоки данных, организованные определенным образом. Надо сказать, что существует множество различных форматов спрайтов. Например, формат спрайтов, принятый в Laser Basic отличается от того, который используется в Beta Basic, бегущий строка тот, который хотим предложить мы, в свою очередь, не похож ни на первый, ни на второй, бегущий строка все они отличаются от того, который мы продемонстрировали в предыдущих главах. Главным критерием в выборе формата блока данных является способ вывода спрайта на экран. Представляемый нами способ, быть может, не самый оптимальный в плане быстродействия, но зато программа имеет минимальные размеры при максимальном количестве возможностей. Так, например, спрайт может частично или даже полностью выходить за пределы экрана, бегущий строка вывод может быть осуществлен по любому известному принципу объединения изображений (то есть с замещением либо по AND, OR или XOR). Для упрощения программы спрайт будет выводиться по символам, как бегущий строка в описанной ранее процедуре PUT.
Начнем с разработки формата спрайтов, который зависит от способа вывода графики, бегущий строка затем, привязываясь к формату, напишем соответствующую процедуру вывода спрайтов на экран (строго говоря, разработка формата спрайтов бегущий строка процедуры их вывода должны протекать параллельно, так как одно от другого неотделимо).
Блок данных, описывающий каждый спрайт, будет состоять из двух частей: заголовка, включающего в себя относительные координаты бегущий строка атрибуты для каждого знакоместа (эта часть будет напоминать формат спрайтов для процедуры PUT), бегущий строка данных о состоянии пикселей (по 8 байт на знакоместо - как в символьном наборе). Заголовок будет начинаться указанием общей площади спрайта, или иначе - количества знакомест, составляющих спрайт. Для этого достаточно одного байта, что позволит создавать спрайты площадью до 255 знакомест. Затем для описания каждого символа потребуется по 3 байта, как бегущий строка в процедуре PUT:
1-й байт - относительная вертикальная координата данного знакоместа в спрайте;
2-й байт - относительная горизонтальная координата данного знакоместа в спрайте;
3-й байт - суммарные атрибуты знакоместа.
Таким образом, можно составить примерно такой заголовок:
SPRITE DEFB 7
DEFB 0,2,15
DEFB 1,0,6, 1,1,6, 1,2,6, 1,3,6
DEFB 2,1,6, 2,2,6
Вторую часть блока данных составляют уже знакомые вам описания пикселей знакомест (по 8 байт на каждое), причем они должны быть перечислены в том порядке, в котором указаны в заголовке, например (всего должно быть 7 строк - по количеству символов, входящих в спрайт):
DEFB 33,39,62,255,0,127,127,127
DEFB 246,73,146,255,0,11,222,251
................................
DEFB 35,216,225,228,3,16,148,35
Теперь разберемся с числовыми параметрами, необходимыми для вывода спрайта. Перед обращением к процедуре вывода, которую мы назвали PTBL, в регистре B нужно задать верхнюю границу описывающего прямоугольника (ROW), в C - левую границу описывающего прямоугольника (COL), в HL - адрес блока данных спрайта (метка SPRITE), бегущий строка в аккумуляторе - код команды, определяющей способ вывода спрайтов, который в самом начале работы процедуры будет вставлен в основной цикл вывода бегущий строка тем самым вместо составления четырех похожих друг на друга подпрограмм можно пользоваться одной. Для обычного вывода с замещением предыдущего изображения нужно задать команду NOP - отсутствие операции, которая кодируется байтом 0; для осуществления вывода по принципу OR, AND или XOR необходимо вставить в процедуру команды OR (HL), AND (HL) или XOR (HL), имеющие коды #B6, #A6 бегущий строка #AE соответственно. Чтобы не держать в голове все эти коды, имеет смысл определить их как константы с помощью директивы EQU бегущий строка присвоить им удобочитаемые имена:
SPRPUT - вывод с уничтожением предыдущего изображения;
SPROR - вывод по принципу OR;
SPRAND - вывод по принципу AND;
SPRXOR - вывод по принципу XOR.
В данном примере вновь применена команда EX (SP),HL, но здесь вершину стека можно рассматривать в качестве временной переменной, бегущий строка такой прием может быть рассмотрен как один из способов борьбы с нехваткой регистров.
PTBL
SPRPUT EQU 0 ;код команды NOP
SPROR EQU #B6 ;код команды OR (HL)
SPRAND EQU #A6 ;код команды AND (HL)
SPRXOR EQU #AE ;код команды XOR (HL)
PUSH HL
LD (MODE),A ;устанавливаем способ объединения
; изображений
LD A,(HL) ;количество знакомест в спрайте
INC HL
PUSH HL ;умножаем на 3 (результат в HL)
LD L,A
LD H,0
LD E,L
LD D,H
ADD HL,HL
ADD HL,DE
POP DE
ADD HL,DE ;начало данных, описывающих пиксели
EX DE,HL
PTBL1 PUSH AF
PUSH BC
LD A,(HL) ;вертикальная координата в спрайте
INC HL
PUSH HL
ADD A,B
CP 24
JR NC,PTBL4 ;если знакоместо выходит за пределы экрана
PUSH DE
CALL 3742 ;получаем адрес строки экрана
POP DE
EX (SP),HL
LD A,(HL) ;горизонтальная координата в спрайте
EX (SP),HL
ADD A,C
CP 32
JR NC,PTBL4 ;если знакоместо выходит за пределы экрана
ADD A,L
LD L,A
LD B,8
PUSH HL ;сохраняем адрес экрана
PTBL2 LD A,(DE)
MODE NOP
LD (HL),A
INC DE
INC H
DJNZ PTBL2
POP BC ;восстанавливаем адрес экрана в BC
LD A,B ;определяем адрес атрибутов
AND #18
SRA A
SRA A
SRA A
ADD A,#58
LD B,A
POP HL ;восстанавливаем адрес данных
INC HL
LD A,(HL) ;переносим байт атрибутов в видеобуфер
DEC HL
LD (BC),A
PTBL3 POP BC
POP AF
INC HL
INC HL
DEC A
JR NZ,PTBL1
POP HL
RET
PTBL4 LD HL,8
ADD HL,DE
EX DE,HL
POP HL
JR PTBL3
Описывающийпрямоугольник
Рис. 7.1. Спрайт из игры FIST
Рассмотрим пример вывода спрайта произвольной конфигурации (рис. 7.1). Не правда ли, многие узнали в нем одного из персонажей игры FIST. Все дело в том, что этот спрайт как нельзя лучше демонстрирует эффективность предложенной нами процедуры PTBL, поскольку его форма заметно отличается от прямоугольной. Управляющая часть программы получилась довольно короткой:
ORG 60000
ENT $
LD A,48 ;INK 0: PAPER 6
LD (23693),A
XOR A ;BORDER 0
CALL 8859
CALL 3435
LD A,2
CALL 5633
LD B,10 ;ROW
LD C,15 ;COL
LD A,SPRPUT ;вывод с уничтожением предыдущего
; изображения
LD HL,SPR1 ;чтение адреса спрайта SPR1
CALL PTBL
RET
PTBL .........
; Заголовок спрайта
SPR1 DEFB 22
DEFB 0,3,48, 0,4,48, 1,3,48, 1,4,48, 2,2,48
DEFB 2,3,48, 2,4,48, 2,5,48, 2,6,48, 3,2,48
DEFB 3,3,48, 3,4,48, 4,0,48, 4,1,48, 4,2,48
DEFB 4,3,48, 4,4,48, 5,0,48, 5,1,48, 5,2,48
DEFB 5,3,48, 5,4,48
; Данные спрайта
DEFB 0,0,0,0,3,12,209,46
DEFB 0,0,0,0,192,32,224,240
DEFB 249,34,38,43,43,48,35,248
DEFB 16,112,56,8,16,48,16,240
DEFB 3,6,31,61,61,59,59,27
DEFB 254,255,255,255,255,255,255,255
DEFB 64,224,255,255,255,255,255,255
DEFB 0,0,255,192,224,243,252,240
DEFB 0,248,4,2,2,250,50,28
DEFB 31,7,5,6,7,15,15,31
DEFB 255,255,254,229,3,247,247,235
DEFB 240,0,0,0,252,254,254,254
DEFB 0,0,0,0,0,62,103,77
DEFB 0,0,0,0,0,0,249,255
DEFB 31,31,63,63,127,255,255,255
DEFB 235,219,219,219,252,224,193,131
DEFB 254,254,254,126,254,252,252,248
DEFB 65,67,71,69,34,30,0,0
DEFB 255,255,255,255,63,7,0,0
DEFB 255,254,252,248,240,224,0,0
DEFB 3,3,1,2,2,1,0,0
DEFB 248,248,152,198,1,255,0,0
Есть смысл немного прокомментировать приведенные выше числовые данные, которые полностью соответствуют описанному выше формату. В заголовке перечислены (например, для первой строки):
22 - общее количество знакомест в спрайте,
0 - координата Y первого выводимого на экран знакоместа, взятая относительно левого верхнего угла описывающего прямоугольника,
3 - координата X того же знакоместа,
48 - суммарные атрибуты знакоместа: PAPER 6, INK 0.
Далее идут тройки чисел, относящиеся к другим знакоместам спрайта бегущий строка в последовательности, указанной выше: координата Y, координата X, суммарные атрибуты.
СПРАЙТ-ГЕНЕРАТОР
Можно по разному создавать блоки данных для спрайтов, начиная с самого простого способа, когда изображение сначала рисуется на бумаге, бегущий строка затем выписываются его коды байт за байтом. Можно воспользоваться приведенной нами в четвертой главе программой, для которой сначала создается фонт (например, в Art Studio), соответствующий одному или сразу нескольким спрайтам, после чего коды все равно требуется записать бегущий строка только затем уж вводить в программу. Оба варианта требуют затрат большого труда бегущий строка времени бегущий строка оправдывают себя лишь в случаях небольших спрайтов (порядка 1 - 6 знакомест). Учитывая все это, мы сочли необходимым предложить программу, которая полностью исключает какие-либо записи, бегущий строка формируемые ею кодовые блоки можно сразу встраивать в создаваемые вами игры.
Программа состоит из двух частей - бейсиковской бегущий строка кодовой. Если вы работаете с магнитофоном, то программу на Бейсике можно исполнять сразу, если же с дисководом, то три строки текста следует заменить (какие именно, сказано ниже). Затем введите бегущий строка оттранслируйте ассемблерную часть, создав соответствующий кодовый файл. Теперь можно работать со спрайтами. После ввода бегущий строка старта программы на вашем экране появится меню. Если вы предварительно просмотрите текст программы, то легко обнаружите, какие функции она может выполнять, тем не менее коротко прокомментируем эти опции.
Load Screen - загрузка экранного файла
Create Sprite - создание спрайта
Save Sprite - сохранение спрайт-файла
New Sprite - удаление спрайтов из памяти для начала создания нового спрайт-файла
View Table - просмотр таблицы смещений спрайтов в спрайт-файле
Quit Program - выход из программы
Нажимая клавиши Q бегущий строка A, можно перемещать курсор в виде инвертированной полоски вверх или вниз по строчкам меню. Отметив курсором нужный пункт, нажмите клавишу M для выполнения функции.
Прежде всего необходимо загрузить экранный файл, для чего предназначен первый пункт меню Load Screen. Внизу экрана появится запрос Screen name:, на который нужно ввести имя загружаемой картинки со спрайтами. После загрузки экранного файла программа снова выйдет в меню.
После этого можно «вырезать» с картинки спрайты, выбрав следующий пункт Create Sprite. Окно с меню исчезнет с экрана бегущий строка останется только загруженная картинка бегущий строка маленький пунктирный квадратик. С помощью клавиш Q, A, O бегущий строка P поместите его в верхний левый угол выбранного спрайта бегущий строка нажмите клавишу M, чтобы зафиксировать местоположение квадратика на экране. Затем, управляя теми же клавишами, расширьте его до нужных размеров, чтобы спрайт полностью поместился внутри отмеченной пунктиром области бегущий строка еще раз нажмите клавишу M. Возврат в меню покажет, что спрайт успешно закодирован - можно создавать следующий. Если создано уже достаточно много спрайтов бегущий строка все они имеют значительные размеры, то памяти может не хватить. В этом случае программа выдаст сообщение Out of memory! Вы можете сохранить полученный спрайт-файл, вызвав опцию Save Sprite, бегущий строка начать создание следующего, предварительно очистив память, выбрав пункт New Sprite.
Перед сохранением спрайт-файла нужно будет ввести его имя, под которым он будет записан на внешний носитель, бегущий строка перед удалением спрайтов из памяти потребуется подтвердить свое намерение, нажав клавишу Y.
Последняя опция Quit Program в особых комментариях не нуждается, поэтому скажем только, что во избежание случайного выхода (а следовательно, бегущий строка потери данных) нужно будет также подтвердить или опровергнуть выбор.
Сообщим еще общие «эксплуатационные» характеристики спрайт-генератора: каждый вновь создаваемый спрайт может занимать площадь до 255 знакомест, если вам захочется чуть больше - описывающий прямоугольник все равно не позволит, сколько бы ни старались. Максимальное количество спрайтов для одного спрайт-файла - 22, после чего его необходимо сохранить. И последнее, создаются спрайты только прямоугольной формы.
Для того чтобы вам легче было разобраться в этой сервисной программе, приведем расшифровку используемых обозначений, бегущий строка также дадим краткое описание ее основной части - функции создания спрайта:
Массивы:
m$(6,13) - наименования опций меню
s(22) - смещения спрайтов относительно начала спрайт-файла
Переменные:
spr - количество созданных спрайтов
addr - адрес следующего спрайта
col, row - координаты окон бегущий строка спрайтов (переменная row используется также для определения позиции курсора меню)
len, hgt - размеры окон бегущий строка спрайтов
pap - цвет PAPER окон
k$ - символ нажатой клавиши
Константы:
scr - адрес «теневого» экрана
ad0 - адрес начала спрайт-файла
ramka, svscr, restor, clsv, setv, gtbl - адреса одноименных процедур
Опишем «центральную» подпрограмму ГЕНЕРАТОРА СПРАЙТОВ - подпрограмму создания спрайтов:
2010 - если создано 22 спрайта, сообщение о том, что спрайт-файл завершен. Необходимо его сохранить бегущий строка начать новый.
2020 - вывод экранной картинки.
2030 - определение начальных значений переменных «вырезаемого» спрайта.
2040 - вывод по заданному размеру бегущий строка в заданном месте экрана пунктирной рамки, отмечающей будущий спрайт.
2045..2090 - установка рамки в верхний левый угол «вырезаемого» спрайта.
2100 - удаление рамки бегущий строка звуковой сигнал после нажатия клавиши M.
2110 - вывод рамки.
2130..2170 - выбор желаемого размера спрайта.
2200 - кодирование спрайта.
2210 - если процедура gtbl возвращает ненулевое значение, то рассчитывается величина смещения спрайта от начала спрайт-файла, бегущий строка переменная addr указывает на конец спрайт-файла.
2220..2240 - выдается сообщение о нехватке памяти для создания спрайта заданных размеров. Можно сохранить спрайт-файл бегущий строка начать новый или попытаться создать спрайт меньших размеров.
10 POKE 23693,40: BORDER 5: CLS
20 DIM m$(6,13): FOR n=1 TO 6: READ m$(n): NEXT n
30 DIM s(22): LET spr=0
40 LET scr=30000: LET ad0=36912: LET addr=ad0
50 LET ramka=65000: LET svscr=65003: LET restor=65006:
LET clsv=65009: LET setv=65012: LET gtbl=65015
60 RANDOMIZE USR svscr
100 REM --- МЕНЮ ---
110 RANDOMIZE USR restor: LET row=6: LET col=8: LET len=15:
LET hgt=13: LET pap=7: GO SUB 8000
120 LET row=0
130 IF row<0 THEN LET row=5
135 IF row>5 THEN LET row=0
140 FOR n=0 TO 5: PRINT PAPER 7; BRIGHT 1;AT 7+n*2,9;m$(n+1):
NEXT n
150 PRINT INVERSE 1; BRIGHT 1;AT 7+row*2,9;m$(row+1)
160 PAUSE 0: LET k$=INKEY$
170 IF k$="a" OR k$="A" THEN BEEP .01,20: LET row=row+1:
GO TO 130
180 IF k$="q" OR k$="Q" THEN BEEP .01,20: LET row=row-1:
GO TO 130
190 IF k$<>"m" AND k$<>"M" THEN GO TO 150
200 BEEP .01,20: GO SUB (row+1)*1000
210 GO TO 100
1000 REM --- ЗАГРУЗКА ЭКРАННОЙ КАРТИНКИ ---
1010 INPUT "Screen name: "; LINE n$
1020 LOAD n$CODE 16384,6912
1030 RANDOMIZE USR svscr: RETURN
2000 REM --- СОЗДАНИЕ СПРАЙТОВ ---
2010 IF spr=22 THEN LET row=11: LET col=4: LET len=23: LET hgt=3:
LET pap=3: GO SUB 8000: PRINT AT row+1,col+1; PAPER pap;
BRIGHT 1;"Sprite-file complete!": BEEP 1,-20: PAUSE 0: RETURN
2020 RANDOMIZE USR restor
2030 LET spr=spr+1: LET row=12: LET col=15: LET len=1: LET hgt=1:
POKE 23303,len: POKE 23304,hgt
2040 POKE 23301,col: POKE 23302,row: RANDOMIZE USR ramka
2045 PAUSE 0: LET k$=INKEY$
2050 IF (k$="q" OR k$="Q") AND row>0 THEN
RANDOMIZE USR ramka: LET row=row-1: GO TO 2040
2060 IF (k$="a" OR k$="A") AND row<24-hgt THEN
RANDOMIZE USR ramka: LET row=row+1: GO TO 2040
2070 IF (k$="o" OR k$="O") AND col>0 THEN
RANDOMIZE USR ramka: LET col=col-1: GO TO 2040
2080 IF (k$="p" OR k$="P") AND col<32-len THEN
RANDOMIZE USR ramka: LET col=col+1: GO TO 2040
2090 IF k$<>"m" AND k$<>"M" THEN GO TO 2045
2100 RANDOMIZE USR ramka: BEEP .01,20
2110 POKE 23303,len: POKE 23304,hgt: RANDOMIZE USR ramka
2120 PAUSE 0: LET k$=INKEY$
2130 IF (k$="a" OR k$="A") AND hgt<24-row AND len*(hgt+1)<256
THEN RANDOMIZE USR ramka: LET hgt=hgt+1: GO TO 2110
2140 IF (k$="q" OR k$="Q") AND hgt>1 THEN
RANDOMIZE USR ramka: LET hgt=hgt-1: GO TO 2110
2150 IF (k$="o" OR k$="O") AND len>1 THEN RANDOMIZE USR ramka:
LET len=len-1: GO TO 2110
2160 IF (k$="p" OR k$="P") AND len<32-col AND (len+1)*hgt<256
THEN RANDOMIZE USR ramka: LET len=len+1: GO TO 2110
2170 IF k$<>"m" AND k$<>"M" THEN GO TO 2120
2200 BEEP .01,20: POKE 23300,hgt*len: RANDOMIZE addr:
LET ad=USR gtbl
2210 IF ad THEN LET s(spr)=addr-ad0: LET addr=ad: RETURN
2220 LET col=6: LET row=11: LET hgt=3: LET len=20: LET pap=2
2230 GO SUB 8000: PRINT AT row+1,col+3; PAPER pap;
BRIGHT 1;"Out of memory!"
2240 LET spr=spr-1: BEEP 1,-20: PAUSE 0: RETURN
3000 REM --- СОХРАНЕНИЕ СПРАЙТ-ФАЙЛА ---
3010 IF NOT spr THEN RETURN
3020 INPUT "Sprite name: "; LINE n$
3030 SAVE n$CODE ad0,addr-ad0
3040 RETURN
4000 REM --- УДАЛЕНИЕ СПРАЙТ-ФАЙЛА ИЗ ПАМЯТИ ---
4010 IF NOT spr THEN RETURN
4020 GO SUB 7000: IF k$<>"y" THEN RETURN
4030 LET spr=0: LET addr=ad0: RETURN
5000 REM --- ПРОСМОТР ТАБЛИЦЫ СМЕЩЕНИЙ СПРЙТОВ ---
5010 CLS : IF NOT spr THEN RETURN
5020 FOR n=1 TO spr: PRINT "Sprite No ";n,"Offset == ";s(n): NEXT n
5030 PAUSE 0: RETURN
6000 REM --- ВЫХОД ИЗ ПРОГРАММЫ ---
6010 GO SUB 7000: IF k$<>"y" THEN RETURN
6020 CLEAR : STOP
7000 REM --- ЗАПРОС ---
7010 LET row=11: LET col=5: LET len=21: LET hgt=3: LET pap=6:
GO SUB 8000
7020 PRINT AT row+1,col+1; PAPER pap; BRIGHT 1;
"Are you shure (Y/N)?"
7030 PAUSE 0: LET k$=INKEY$: IF k$="Y" THEN LET k$="y"
7040 BEEP .01,20: RETURN
8000 REM --- ОКНА ---
8010 POKE 23301,col: POKE 23302,row: POKE 23303,len: POKE 23304,hgt
8020 RANDOMIZE USR clsv: PRINT PAPER pap; BRIGHT 1;:
RANDOMIZE USR setv
8030 LET l=len*8-1: LET h=hgt*8-1
8040 PLOT col*8,175-row*8: DRAW l,0: DRAW 0,-h: DRAW -l,0: DRAW 0,h
8050 RETURN
9000 REM --- ДАННЫЕ МЕНЮ ---
9010 DATA "Load Screen"
9020 DATA "Create Sprite"
9030 DATA "Save Sprite"
9040 DATA "New Sprite"
9050 DATA "View Table"
9060 DATA "Quit Program"
9900 REM --- АВТОСТАРТ ПРОГРАММЫ ---
9910 POKE 23693,40: BORDER 5: CLEAR 29999
9920 LOAD "sptgen"CODE
9930 RUN
Если вы работаете в системе TR-DOS, то несколько строк этой программы следует заменить на приведенные ниже:
1020 RANDOMIZE USR 15619: REM : LOAD n$CODE 16384,6912
3030 RANDOMIZE USR 15619: REM : SAVE n$CODE ad0,addr-ad0
9920 RANDOMIZE USR 15619: REM : LOAD "sptgen"CODE
и только после этого использовать.
Некоторые процедуры, как вы заметили, написаны на ассемблере бегущий строка вызываются функцией USR. При использовании ряда подпрограмм в машинных кодах из Бейсика возникает проблема, как определить адреса обращения к ним. Можно, конечно, оттранслировать каждую из них отдельно, задав для каждой определенный начальный адрес или в одном исходном файле указать несколько директив ORG. Но при этом возникнут другие сложности, связанные с компоновкой программы. Можно также, оттранслировав весь пакет процедур как единое целое, просмотреть затем полученные коды с помощью дизассемблера бегущий строка найти точки входа в каждую подпрограмму. Но при этом, если потребуется внести в текст какие-либо изменения (а особенно часто это придется делать на этапе отладки), то всю работу по определению адресов придется повторять с начала. В связи с этим мы предлагаем вам наиболее простой способ, часто применяемый в подобных ситуациях: в начале ассемблерного текста нужно вставить ряд команд JP, передающих управление всем процедурам пакета, к которым имеется обращение из Бейсика (либо из другого языка). Зная, что команда JP в памяти занимает 3 байта, несложно вычислить адрес любой процедуры по ее «порядковому номеру». Впоследствии мы еще не раз воспользуемся этим методом, поэтому мы бегущий строка обратили на него ваше внимание.
Основная часть пакета - это подпрограмма GTBL, сохраняющая в памяти образ экрана в принятом для процедуры PTBL формате спрайтов. Подпрограмма OUT_BT также относится к ней. При вызове GTBL в переменной __SP сохраняется начальное состояние указателя стека SP. Делается это для корректного выхода в Бейсик в случае возникновения ошибки (Out of memory - нехватка памяти).
Подпрограмма RAMKA выводит на экран пунктирный прямоугольник, отмечающий границы создаваемого спрайта. Вывод производится по принципу XOR, поэтому при повторном обращении к процедуре прежний вид экрана полностью восстанавливается.
Подпрограмма SVSCR нужна для сохранения экранного изображения в памяти для последующего его восстановления процедурой RESTOR.
В пакет включены также две описанные ранее процедуры CLSV бегущий строка SETV для очистки окна экрана бегущий строка установки в нем постоянных атрибутов.
ORG 65000
ORIGIN EQU $ ;верхняя допустимая граница спрайт-файла
ADDR EQU 23670 ;текущий адрес в спрайт-файле
ATTR EQU 23695 ;значение атрибутов окна
SCREEN EQU 30000 ;адрес «теневого» экрана
N_SYM EQU 23300 ;рассчитанная в Бейсике площадь спрайта
COL EQU 23301 ;координаты спрайта
ROW EQU 23302
LEN EQU 23303 ;размеры спрайта
HGT EQU 23304
; 65000
JP RAMKA
; 65003
JP SVSCR
; 65006
JP RESTOR
; 65009
JP CLSV
; 65012
JP SETV
; 65015
GTBL CALL RESTOR ;восстанавливаем экранную картинку
LD (__SP),SP ;запоминаем состояние стека для
; возврата при возникновении ошибки
LD IX,(ADDR) ;адрес конца спрайт-файла
; Формирование заголовка
LD A,(N_SYM) ;количество знакомест
; в создаваемом спрайте
CALL OUT_BT ;записываем первый байт в спрайт-файл
LD A,(ROW) ;вычисляем адрес атрибутов
LD L,A
LD H,0
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
LD A,#58
ADD A,H
LD H,A
LD A,(COL)
ADD A,L
LD L,A
LD DE,(LEN)
LD BC,0
GTBL1 PUSH BC
PUSH DE
PUSH HL
GTBL2 LD A,B
CALL OUT_BT ;позиция по вертикали внутри спрайта
LD A,C
CALL OUT_BT ;позиция по горизонтали
LD A,(HL)
CALL OUT_BT ;байт атрибутов
INC HL
INC C
DEC E
JR NZ,GTBL2
POP HL
LD DE,32 ;переходим к следующей строке
ADD HL,DE
POP DE
POP BC
INC B
DEC D
JR NZ,GTBL1
; Данные состояния пикселей
LD A,(HGT)
LD B,A
LD A,(ROW)
GTBL3 PUSH AF
PUSH BC
CALL 3742 ;вычисляем адрес начального знакоместа
LD A,(COL)
ADD A,L
LD L,A
LD A,(LEN)
LD B,A
GTBL4 PUSH BC
PUSH HL
LD B,8 ;переписываем в спрайт-файл 8 байт
; знакоместа
GTBL5 LD A,(HL)
CALL OUT_BT
INC H
DJNZ GTBL5
POP HL
INC HL ;переходим к следующему знакоместу
POP BC
DJNZ GTBL4
POP BC
POP AF
INC A ;переходим к следующей строке
DJNZ GTBL3
PUSH IX ;возвращаем в Бейсик адрес
POP BC ; конца спрайт-файла
RET
OUT_BT PUSH BC ;запись в спрайт-файл байта из A
PUSH HL
; Проверка наличия свободной памяти
PUSH IX
POP HL
LD BC,ORIGIN ;адрес конца свободной памяти
; для спрайт-файла
AND A ;очистка флага CY перед вычитанием
; (если этого не сделать, результат будет неверен!)
SBC HL,BC ;если текущий адрес достиг ORIGIN,
JR NC,OUTRAM ; происходит выход в Бейсик
POP HL
POP BC
LD (IX),A ;записываем байт в спрайт-файл
INC IX ;увеличиваем адрес размещения кодов
RET
OUTRAM LD SP,(__SP) ;восстанавливаем значение стека
LD BC,0 ;возвращаем в Бейсик код ошибки
RET
__SP DEFW 0 ;переменная для сохранения указателя стека
; Рисование прямоугольной пунктирной рамки
RAMKA LD A,(ROW)
PUSH AF
CALL 3742 ;вычисляем адрес экрана
LD A,(COL)
ADD A,L
LD L,A
CALL HOR ;проводим верхнюю линию
CALL VERT1 ;рисуем боковые стороны в первой
; строке окна
LD A,(HGT)
DEC A
JR Z,RAMK2 ;обходим, если единственная строка
LD B,A ;иначе рисуем боковые стороны по всей
; высоте окна
POP AF
RAMK1 PUSH AF
CALL VERT ;заканчиваем предыдущую строку
POP AF
INC A ;переходим к следующей
PUSH AF
CALL 3742 ;вычисляем адрес экрана
LD A,(COL)
ADD A,L
LD L,A
CALL VERT ;ставим верхние точки
CALL VERT1 ;заканчиваем вертикальный пунктир
POP AF
DJNZ RAMK1 ;повторяем
PUSH AF
RAMK2 POP AF
; Горизонтальная пунктирная линия
HOR PUSH BC
PUSH HL
LD A,(LEN) ;рисуем пунктир по ширине окна
LD B,A
HOR1 LD A,%10011001 ;фактура пунктирной линии
XOR (HL) ;объединяем с экранным изображением
LD (HL),A ;возвращаем на экран
INC HL
DJNZ HOR1
POP HL
POP BC
RET
; Рисование двух точек для боковых сторон рамки
VERT PUSH HL
LD A,128 ;левая точка
XOR (HL)
LD (HL),A
LD A,(LEN) ;ищем адрес правой стороны окна
DEC A
ADD A,L
LD L,A
LD A,1 ;правая точка
XOR (HL)
LD (HL),A
POP HL
RET
; Боковые стороны рамки по высоте знакоместа
VERT1 INC H ;пропускаем 3 ряда пикселей
INC H
INC H
CALL VERT ;ставим точки на левой бегущий строка правой
; сторонах прямоугольника
INC H
CALL VERT ;повторяем для следующего ряда
INC H ;делаем следующий промежуток
INC H
INC H
RET
; Сохранение области видеобуфера в «теневом» экране
SVSCR LD HL,16384
LD DE,SCREEN
LD BC,6912
LDIR
RET
; Восстановление изображения на экране
RESTOR LD HL,SCREEN
LD DE,16384
LD BC,6912
LDIR
RET
; Подпрограмма очистки окна
CLSV .........
; Подпрограмма установки атрибутов в окне
SETV .........
МУЛЬТИПЛИКАЦИЯ
В большинстве компьютерных игр персонажи беспрерывно передвигаются по экрану, создавая неповторимые ситуации, чем собственно бегущий строка привлекают к себе внимание многочисленной армии почитателей ZX Spectrum. В пятой главе мы уже слегка затронули проблему движения изображений, прояснив с помощью нескольких примеров те принципы, которые лежат в основе любого перемещения по экрану, будь то тексты или спрайты. Теперь настало время внести в этот вопрос полную ясность, показав способы, наиболее часто используемые в игровых программах.
У вас может возникнуть вопрос, бегущий строка зачем, собственно, рассматривать несколько разных способов, не проще ли ограничиться одним, только очень хорошим, бегущий строка применять его во всех случаях компьютерной «жизни». Все дело в том, что возможны совершенно отличные друг от друга ситуации, определяемые конкретным замыслом. Скажем, для простых сюжетов нет смысла использовать сложные способы передвижения спрайтов, бегущий строка в насыщенных играх простые способы уже могут оказаться неэффективными.
Первый способ основан на скроллинге окон, бегущий строка если вы припомните программу, которая раздвигает в разные стороны створки железной решетки, то получите о нем полное представление. Тем не менее, мы вновь к нему возвращаемся, поскольку в нашем распоряжении появилась удобная процедура для вывода спрайтов. Перечислим действия, характерные для этого способа:
поместите на экран спрайт, например, с помощью процедуры PTBL, установив режим SPRPUT;
задайте окно, по размерам покрывающее этот спрайт бегущий строка выполните скроллинг при помощи одной из четырех рассмотренных выше процедур. Спрайт довольно резво устремится в нужную сторону, так что в программе необходимо предусмотреть небольшую задержку.
Рис. 7.2. Перемещение спрайта скроллингом окна
Сразу же виден бегущий строка недостаток этого способа, который состоит в том, что спрайт перемещается по экрану вместе с фоном, поскольку скроллинг захватывает все изображение в окне. Отсюда ясно, что применять такой метод можно лишь в тех случаях, когда фон как таковой отсутствует или, по крайней мере, мелкие детали не попадают в сдвигаемое окно. В качестве иллюстрации к сказанному приведем небольшую программку, которая плавно перемещает по экрану симпатичный паровозик, позаимствованный нами из спрайт-файла SPRITE2B пакета Laser Basic (рис. 7.2).
ORG 60000
ENT $
XOR A
CALL 8859
LD A,5
LD (23693),A
CALL 3435
LD A,2
CALL 5633
; Начальная установка регистров процедуры PTBL
LD B,10
LD C,0
LD A,SPRPUT
LD HL,PAROW
; Вывод на экран «паровозика»
CALL PTBL
; Задание параметров окна
LD HL,#A00 ;COL = 0, ROW = 10
LD (COL),HL
LD HL,#320 ;LEN = 32, HGT = 3
LD (LEN),HL
LD B,0 ;задание длины пробега «паровозика»
; (0 = 256 пикселей)
MOVE PUSH BC
CALL SCR_RT ;обращение к процедуре скроллинга вправо
POP BC
DJNZ MOVE
RET
; Подпрограмма скроллинга окна вправо
SCR_RT .........
; Подпрограмма вывода спрайта
PTBL .........
; Переменные к процедуре скроллинга
COL DEFB 0
ROW DEFB 0
LEN DEFB 0
HGT DEFB 0
; Заголовок данных для «паровозика»
PAROW DEFB 14,0,0,5,0,1,5,0,2,5,0,3,5
DEFB 1,0,5,1,1,5,1,2,5,1,3,5,1,4,5
DEFB 2,0,5,2,1,5,2,2,5,2,3,5,2,4,5
; Данные
DEFB 0,0,0,3,15,63,64,95
DEFB 0,0,0,255,255,254,1,255
DEFB 0,0,0,192,160,70,201,73
DEFB 0,0,0,0,30,33,26,18
DEFB 24,248,152,253,133,181,181,181
DEFB 33,39,62,255,0,127,127,127
DEFB 246,73,146,255,0,254,252,251
DEFB 230,83,134,189,133,133,173,214
DEFB 0,192,96,160,160,160,160,96
DEFB 181,133,253,0,255,38,20,15
DEFB 127,0,255,0,255,83,138,7
DEFB 244,11,247,0,255,41,69,131
DEFB 35,216,228,3,249,148,35,192
DEFB 192,32,216,176,96,192,128,0
Второй способ не многим сложнее первого. Он основан на многократном выводе спрайта на экран. Если на каждом шаге изменять на единицу одну из координат, то спрайт будет двигаться параллельно соответствующей границе экрана, если же менять сразу обе, то он начнет перемещаться по диагонали. Основное требование к спрайту - он должен иметь по краям пустое пространство шириной в одно знакоместо, иначе изображение, помещенное на экран на предыдущем шаге, не будет полностью затираться следующим выводимым спрайтом бегущий строка по экрану потянется не предусмотренный программистом след. Таким образом, если пустые места сделаны вокруг всего спрайта, то его можно спокойно передвигать в любом направлении, если же заранее известно, что он будет перемещаться вправо бегущий строка никуда больше (как в примере ниже), то достаточно оставить пустую полоску шириной в одно знакоместо только слева.
К сожалению, этот способ перемещения спрайта тоже не лишен недостатка, видного невооруженным глазом: вместе с изображением, действительно подлежащим удалению, спрайт как ластик сотрет вообще весь фон позади себя. Справиться с этим можно точно так же, как мы рекомендовали выше, - выводить спрайт на сплошной фон, лишенный сложного пейзажа, что приемлемо для ограниченного числа игровых сюжетов. В качестве иллюстрации приведем программу, которая передвигает по экрану слева направо маленького динозавра, перебравшегося к нам из игры LITTLE PUFF:
ORG 60000
ENT $
XOR A
CALL 8859
LD A,7
LD (23693),A
CALL 3435
LD A,2
CALL 5633
; Основная часть программы
LD C,-4
MOVE LD B,10
LD A,SPRPUT
LD HL,DIN
PUSH BC
CALL PTBL
LD BC,10
CALL 7997
POP BC
INC C
LD A,C
CP 32
JP M,MOVE ;если координата меньше 32 (с учетом знака)
RET
; Подпрограмма вывода спрайта
PTBL .........
; Заголовок данных для «динозавра»
DIN DEFB 16,0,0,4,0,1,4,0,2,4,0,3,4
DEFB 1,0,4,1,1,4,1,2,4,1,3,4
DEFB 2,0,4,2,1,4,2,2,4,2,3,4
DEFB 3,0,4,3,1,4,3,2,4,3,3,4
; Данные:
DEFB 0,0,0,0,0,0,0,0
DEFB 0,0,0,0,0,0,0,0
DEFB 0,0,0,0,0,70,117,42
DEFB 0,0,0,0,0,64,160,64
DEFB 0,0,0,0,0,0,0,0
DEFB 0,0,2,6,11,21,46,31
DEFB 78,72,110,52,123,111,96,31
DEFB 192,128,219,173,71,254,127,0
DEFB 0,0,0,0,0,0,0,0
DEFB 53,100,85,181,20,4,0,0
DEFB 205,188,63,119,103,231,55,185
DEFB 248,0,0,192,224,240,208,224
DEFB 0,0,0,0,0,0,0,0
DEFB 0,0,0,0,0,0,1,0
DEFB 28,57,67,167,156,191,157,0
DEFB 24,120,184,48,38,140,96,0
DEFB 0,0,0,0,0,0,0,0
Программа содержит всего один цикл бегущий строка настолько проста, что в дополнительных комментариях не нуждается.
Третий способ использует вывод спрайтов на экран по принципу XOR, который заложен в процедуре PTBL (как, впрочем, бегущий строка другие). Применение принципа XOR для объединения изображений позволяет легко справиться с проблемой восстановления фона при перемещении спрайтов. Перечислим вначале все операции, которые должна выполнить программа:
спрайт помещается на экран процедурой PTBL, в режиме XOR;
через некоторое время (должен же спрайт немного побыть на экране) вторично выполняется процедура PTBL для того же спрайта, опять же по принципу XOR, при этом он стирается;
координаты спрайта (или одна из них) изменяются бегущий строка все повторяется сначала, при этом спрайт появляется на экране уже в другом месте.
Проделывая все это многократно, можно получить неплохой эффект мультипликации с сохранением фона.
Продемонстрируем этот способ на примере программы, которая в действии выглядит следующим образом. По дороге с ружьем на изготовку двигается солдат, медленно, но верно приближаясь к стенке из белого кирпича. Можно легко заметить, что движение состоит из двух фаз, каждой из которых, очевидно, должен соответствовать один спрайт: первый - ноги вместе бегущий строка ружье чуть-чуть приподнято бегущий строка второй - ноги расставлены в шаге, бегущий строка ружье при этом опускается немного вниз. Когда солдат проходит мимо стенки, их картинки начинают смешиваться по принципу XOR, что мы бегущий строка наблюдаем на экране - появляется какое-то хаотическое изображение, как будто человек продирается сквозь стену, бегущий строка не идет мимо нее. Однако после того как стенка оказывается позади солдата, мы обнаруживаем, что оба изображения полностью восстановились.
ORG 60000
ENT $
LD A,4
LD (23693),A
XOR A
CALL 8859
CALL 3435
LD A,2
CALL 5633
; Рисование пейзажа, состоящего из дороги бегущий строка стены
CALL GRUNT
; Вывод первой фазы спрайта «солдат» в режиме XOR
LD B,9 ;задаем координату Y
LD C,-3 ;начальное значение координаты X
LOOP LD A,SPRXOR ;устанавливаем режим вывода
LD HL,SOLD1 ;задаем адрес спрайта 1 фазы
PUSH HL
PUSH BC
CALL PTBL
LD BC,20 ;задержка спрайта на экране
CALL 7997
POP BC
POP HL
; Повторный вывод первой фазы спрайта в режиме XOR
LD A,SPRXOR
PUSH HL
PUSH BC
CALL PTBL
POP BC
POP HL
INC C ;увеличиваем координату X
; Вывод второй фазы спрайта «солдат» в режиме XOR
LD A,SPRXOR
LD HL,SOLD2 ;задаем адрес спрайта 2 фазы
PUSH HL
PUSH BC
CALL PTBL
LD BC,20
CALL 7997
POP BC
POP HL
; Повторный вывод второй фазы спрайта в режиме XOR
LD A,SPRXOR
PUSH HL
PUSH BC
CALL PTBL
POP BC
POP HL
INC C ;увеличиваем координату X
LD A,C ;количество шагов солдата
CP 32 ;проверка условия конца «дороги»
JP M,LOOP
RET
; Подпрограмма рисования пейзажа
GRUNT EXX
PUSH HL
LD BC,#4700 ;начало горизонтальной линии (B=71, C=0)
CALL 8933
; Рисование «дорожки»
LD DE,#101
LD BC,250
CALL 9402
; Рисование «стены»
LD BC,#915 ;B = 9, C = 21
STEN PUSH BC
LD A,SPRPUT ;устанавливаем режим вывода
LD HL,STENA ;задаем адрес спрайта «стена»
CALL PTBL
POP BC
INC B
LD A,B
CP 13
JR C,STEN
POP HL
EXX
RET
PTBL .........
; Заголовок данных первой фазы спрайта «солдат»
SOLD1 DEFB 10
DEFB 0,0,7, 0,1,7, 1,0,7, 1,1,7
DEFB 2,0,7, 2,1,7, 2,2,7
DEFB 3,0,7, 3,1,7, 3,2,7
; Данные первой фазы спрайта «солдат»
DEFB 1,4,13,27,91,35,28,3
DEFB 128,32,112,184,182,140,56,192
DEFB 12,16,19,15,15,7,3,27
DEFB 8,32,12,156,192,152,172,192
DEFB 60,63,114,45,31,47,112,123
DEFB 250,7,0,183,160,44,192,56
DEFB 0,0,2,255,96,224,0,0
DEFB 51,7,1,6,12,19,30,15
DEFB 220,220,216,33,27,11,135,134
DEFB 0,0,0,128,64,192,128,0
; Заголовок данных второй фазы спрайта «солдат»
SOLD2 DEFB 9
DEFB 0,0,7, 0,1,7, 1,0,7, 1,1,7
DEFB 2,0,7, 2,1,7, 2,2,7
DEFB 3,0,7, 3,1,7
; Данные второй фазы спрайта
DEFB 3,8,26,55,183,71,56,7
DEFB 0,64,224,112,108,24,112,128
DEFB 24,32,38,31,31,15,7,55
DEFB 16,64,24,56,128,48,104,128
DEFB 121,254,239,200,178,127,62,204
DEFB 244,14,251,0,239,65,91,0
DEFB 0,0,0,8,252,128,128,0
DEFB 243,111,15,0,6,6,1,15
DEFB 184,184,184,0,48,214,173,239
; Заголовок спрайта «стена»
STENA DEFB 2
DEFB 0,0,7, 0,1,7
; Данные спрайта «стена»
DEFB 0,223,223,223,0,253,253,253
DEFB 0,223,223,223,0,253,253,253
Четвертый способ основан на принципе записи части экранного изображения в буферную область памяти с последующим его возвратом на экран. Сначала поясним суть этого способа, бегущий строка затем приведем небольшую программу, которая его иллюстрирует. В программе ГЕНЕРАТОР СПРАЙТОВ для сохранения образа экрана в памяти использовалась процедура GTBL бегущий строка чтобы не писать еще одну подпрограмму, применим ее же для пересылки в буфер фрагмента экранного изображения. Вставляя эту процедуру в программу, следует предварительно внести в нее небольшие изменения:
убрать первые четыре строки (до CALL OUT_BT);
все команды CALL OUT_BT заменить на
LD (IX),A
INC IX
в самом конце процедуры GTBL (непосредственно перед инструкцией RET) убрать команды PUSH IX бегущий строка POP BC;
внутренняя подпрограмма OUT_BT также не нужна, поэтому ее можно опустить.
В остальном все остается без изменений. Поскольку экранное изображение сохраняется в памяти, нужно позаботиться о выделении для этих целей некоторого рабочего буфера. Чтобы буфер не перекрыл занятую программой память, следует знать не только адрес его начала (который, кстати, понадобится для возврата полученного процедурой GTBL изображения), но бегущий строка его размер. Вычислить его можно исходя из принятого нами формата спрайтов: количество знакомест (N_SYM) плюс заголовок (N_SYMґ3) плюс данные (N_SYMґ8). Итого получится N_SYMґ11+1. Для небольших спрайтов вполне можно включить буфер в саму программу, воспользовавшись директивой ассемблера
BUFFER DEFS N_SYM*11+1
Добавим, что при таком способе задания буфера размер его может быть больше рассчитанного, но ни в коем случае не меньше, иначе сохраняемые коды уничтожат часть программы! Кроме этого, надо сказать, что DEFS имеет смысл использовать только для сохранения небольших участков экрана, бегущий строка при работе с большими изображениями (или когда одновременно сохраняются много окон) лучше выделить для этих целей некоторый участок памяти вне программы, чтобы сократить размер исполняемого модуля.
Для восстановления изображения нужно воспользоваться процедурой PTBL, задав в качестве адреса спрайта метку BUFFER или абсолютный адрес буфера, если он находится вне программы (хотя в этом случае его удобнее задать как константу).
Перечислим основные этапы реализации описываемого способа передвижения спрайта:
процедурой GTBL забираем в буфер часть экранного изображения в форме прямоугольного окна;
в это же место процедурой PTBL (в режиме SPRPUT) выводим спрайт;
делаем небольшую задержку;
ранее сохраненное окно с изображением части экрана переносим процедурой PTBL (в режиме SPRPUT) обратно на экран бегущий строка в то же самое место;
изменяем координаты спрайта (либо одну из них, как в примере) бегущий строка повторяем перечисленные выше действия.
При составлении программы игры необходимо следить за тем, чтобы спрайт не выходил за пределы экрана, по крайней мере влево бегущий строка вверх, так как этого не допускает процедура GTBL.
Эффективность способа продемонстрируем с помощью приведенной ниже программы, которая передвигает по экрану человечка из игры EXPRESS. Он пробегает мимо кустов, закрывая их собой по очереди, однако за его спиной кусты вновь появляются. Добежав до лежащего на дороге камня, человечек спотыкается бегущий строка падает, на этом действие микромультфильма заканчивается (но вы можете попытаться его продолжить).
ORG 60000
ENT $
N_SYM EQU 6 ;задаем количество знакомест окна
LD A,6
LD (разделы
холодильный централь
газонокосилка dolmar
пежо 407
магнитный решетка
спецобувь
слим лифт
продажа кофе
витрина подогреваемый
госпиталь мэш
колодец канализационный пластиковый
телематические служба
peg perego venezia
герб вышивка
врач акушер гинеколог
gislaved отзыв
сенсорный экран устройство
гнб
краска двухкомпонентный
билет большой
враждебный поглощение
узи сделать
renu multiplus 355мл
планирование день
вакансия красноярск
лидо пекарня
измеритель температры
купить аудиоплееры
детский мир
рассылка адрес
продажа кофе
девелоперская компания
100 девчонка одна лифт
бегущий строка