бегущий строка
Как написать игру на ассемблере для ZX Spectrum — Издательский дом «Питер»
Книги
Издательство
Отдел сбыта
Проекты
English version
Главная
Новинки
Новости
Рейтинг продаж
Файлы/Download
Клуб Профессионал
Партнерская программа
Ваш кабинет
Если вы уже зарегистрированы, введите ваши данные:
Логин
Пароль
Регистрация | Вспомнить пароль
Библиотека: Евдокимов А. А. Капульцевич. Как написать игру на ассемблере для ZX Spectrum
ГЛАВА СЕДЬМАЯ,в которой вы научитесь создавать все элементы игрового пространстваКак вы уже знаете, игровое пространство составляют перемещающиеся спрайты, которые появляются бегущий строка исчезают на экране во время игры, бегущий строка неподвижный или медленно перемещающийся пейзаж. В предыдущих главах мы частично показали, каким образом можно создавать спрайты, используя привычные символы UDG бегущий строка средства ассемблера. Однако такой способ пригоден лишь для небольших изображений, да бегущий строка то, если их общая площадь не превышает двух десятков знакомест. Теперь пора нам подробно познакомиться с общим случаем, когда размеры спрайтов могут быть практически любыми, бегущий строка их количество ограничено лишь сюжетом игры, вашей фантазией бегущий строка трудолюбием. Есть бегущий строка другая, не менее важная задача - создание таких процедур вывода спрайтов на экран бегущий строка рисования пейзажей, которые бы требовали на это минимального времени и, желательно, были не слишком громоздкими.БЫСТРЫЙ ВЫВОД СПРАЙТОВЧто бы ни появлялось на экране во время игры - спрайты или какие-либо тексты - каждое изображение состоит из отдельных символов. Таким образом, чтобы быстро выводить сложные картинки, нужно начать с самого простого - печати произвольного символа в текущую позицию экрана. Раньше мы поручали эту задачу процедуре RST 16, которая неплохо справлялась со своими обязанностями до тех пор, пока отдельные кадры изображения не слишком быстро сменяли друг друга. Безусловно, ее бегущий строка дальше вполне можно использовать в подобных ситуациях. Однако, когда речь заходит о создании динамических картинок, бегущий строка именно такие мы чаще всего наблюдаем после загрузки наиболее интересных игровых программ, она уже перестает нас удовлетворять. Изображения начинают временами пропадать и, конечно же, теряется естественное восприятие событий.Во 2-й главе мы приводили пример небольшой программки на Бейсике, которая печатала букву A, бегущий строка сказали, что по такому принципу работает любая процедура вывода символов на экран. Теперь перепишем ее на ассемблере бегущий строка как основу используем для составления подпрограмм вывода спрайтов. До того, как этот фрагмент появится в программе, необходимо в регистровой паре DE задать адрес символа в наборе, в HL - рассчитанный начальный адрес знакоместа:.........LD B,8MET1 LD A,(DE)LD (HL),AINC DEINC HDJNZ 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 BCPUSH DEPUSH HLLD L,A ;по коду символа вычисляем его адресLD H,0 ; в текущем набореADD HL,HLADD HL,HLADD HL,HLLD DE,(23606)ADD HL,DELD DE,(23684) ;адрес текущей позиции печати; в видеобуфереEX DE,HLPUSH HLLD B,8PRS1 LD A,(DE)BIT 3,(IY+87) ;режим INVERSE 1JR Z,PRS2CPL ;если включен, инвертируем байтPRS2 BIT 1,(IY+87) ;режим OVER 1JR Z,PRS3XOR (HL) ;если включен, объединяем; с изображением на экранеPRS3 LD (HL),AINC DEINC HDJNZ PRS1POP HLPUSH HLLD A,H ;вычисляем адрес в области атрибутовAND #18RRCARRCARRCAADD A,#58LD H,ALD A,(23695)LD (HL),A ;записываем байт атрибутов в видеобуферPOP HLINC L ;переходим к следующей позиции печатиJR NZ,PRS4 ;если 0, то это означает, что позиция; печати перешла в следующую треть экранаLD A,H ;в этом случае увеличиваемADD A,8 ; старший байт адреса на 8LD H,ACP #58JR C,PRS4LD H,#40 ;если выход из последней трети, то; возвращаемся в начало видеобуфераPRS4 LD (23684),HLPOP HLPOP DEPOP BCRETИспользуем сначала эту процедуру для вывода буквенной или цифровой информации. Конечно, можно представить себе ситуацию, когда печатается всего один символ, например, уровень игры, но все же значительно чаще приходится иметь дело с текстовыми строками или даже целыми страницами бегущий строка тут процедуры 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 HLAND ARET Z ;вывод символов до кода 0CP " "JR C,WRITE2 ;если управляющий код (< 32)WRITE1 CALL PRSYMJR WRITE; Выбор из таблицы адреса перехода в зависимости от кодаWRITE2 PUSH HLPUSH BCLD HL,TABLE ;адрес таблицыLD C,A ;сохраняем код в CWRITE3 LD A,(HL) ;читаем код из таблицыINC HLAND AJR Z,WRITE5 ;если встречен маркер конца таблицыCP CJR Z,WRITE4 ;если код найденINC HL ;пропускаем 2 байта адресаINC HLJR WRITE3 ;проверяем следующий кодWRITE4 POP BCLD A,(HL) ;берем из таблицы адрес переходаINC HLLD H,(HL) ;помещаем его в HLLD L,AEX (SP),HL ;восстанавливаем HL, бегущий строка адрес записываем; на вершину стекаRET ;переходим по адресу с вершины стекаWRITE5 POP BC ;если код отсутствует в таблице,POP HL ; то восстанавливаем регистрыLD A,"?" ; бегущий строка печатаем символ ?JR WRITE1; Перевод строкиPR_13 PUSH HLLD HL,(23684) ;адрес текущей позиции печатиLD A,LAND %11100000 ;возвращаемся к началу строкиADD A,#20 ;переходим к следующей строкеLD L,AJR NZ,PR13_1 ;если не перешли в следующую третьLD A,HADD A,8 ;старший байт адреса увеличиваем на 8LD H,ACP #58 ;проверяем, был ли выход за пределы экранаJR C,PR13_1LD H,#40 ;переводим позицию печати в верхнюю; строку экранаPR13_1 LD (23684),HL ;возвращаем рассчитанный адрес; позиции печатиPOP HLJR WRITE; Цвет «чернил» INKPR_16 LD A,(HL) ;читаем следующий байт из строкиAND %111 ;выделяем 3 младших бита (значения 0...7)PUSH BCLD B,%11111000 ;в регистре B - маска битов для INKPR16_1 LD C,ALD A,(IY+85) ;23695AND B ;освобождаем биты предыдущего атрибутаOR C ; бегущий строка записываем на их место новое значениеLD (IY+85),A ;возвращаем байт атрибутовPR16_2 POP BCINC HLJR WRITE; Цвет «бумаги» PAPERPR_17 LD A,(HL) ;с цветом PAPER аналогично INKAND %111RLCA ; только предварительно сдвигаемRLCA ; биты на свое местоRLCAPUSH BCLD B,%11000111JR PR16_1; Мерцание FLASHPR_18 LD A,(HL)AND 1PUSH BCLD B,%01111111PR18_1 RRCAJR PR16_1; Яркость BRIGHTPR_19 LD A,(HL)AND 1PUSH BCLD B,%10111111RRCAJR PR18_1; Инверсия INVERSE (3-й бит в системной переменной P_FLAG)PR_20 LD A,(HL)AND 1PUSH BCLD B,%11110111RLCARLCAPR20_1 RLCALD C,ALD A,(IY+87)AND BOR CLD (IY+87),AJR PR16_2; Режим наложения OVER (1-й бит в системной переменной P_FLAG)PR_21 LD A,(HL)AND 1PUSH BCLD B,%11111101JR PR20_1; Позиционирование курсора ATPR_22 LD A,(HL) ;берем номер строкиCP 24 ;если больше 24, то выход позицииJR NC,OUTSCR ; печати за пределы экранаINC HLPUSH DEPUSH HLCALL 3742 ;вычисляем адрес начала строкиPOP DELD A,(DE) ;берем номер столбцаCP 32 ;если больше 32, то выход позицииJR NC,OUTSCR ; печати за пределы экранаINC DEADD A,LLD L,ALD (23684),HL ;запоминаем адрес новой позицииPOP HLEX DE,HLJP WRITEOUTSCR RST 8 ;сообщение БейсикаDEFB 4 ; «Out of screen»PRSYM .........; Таблица переходов на процедуры для управляющих кодовTABLE DEFB 13DEFW PR_13DEFB 16DEFW PR_16DEFB 17DEFW PR_17DEFB 18DEFW PR_18DEFB 19DEFW PR_19DEFB 20DEFW PR_20DEFB 21DEFW PR_21DEFB 22DEFW PR_22DEFB 0Покончив с текстами, перейдем к описанию программы, которая выводит на экран спрайт произвольной конфигурации, но сначала стоит сказать несколько слов о том, что собой представляют спрайты с точки зрения программиста. Мы уже описывали работу со спрайтами бегущий строка вам известно, что в принципе - это блоки данных, организованные определенным образом. Надо сказать, что существует множество различных форматов спрайтов. Например, формат спрайтов, принятый в Laser Basic отличается от того, который используется в Beta Basic, бегущий строка тот, который хотим предложить мы, в свою очередь, не похож ни на первый, ни на второй, бегущий строка все они отличаются от того, который мы продемонстрировали в предыдущих главах. Главным критерием в выборе формата блока данных является способ вывода спрайта на экран. Представляемый нами способ, быть может, не самый оптимальный в плане быстродействия, но зато программа имеет минимальные размеры при максимальном количестве возможностей. Так, например, спрайт может частично или даже полностью выходить за пределы экрана, бегущий строка вывод может быть осуществлен по любому известному принципу объединения изображений (то есть с замещением либо по AND, OR или XOR). Для упрощения программы спрайт будет выводиться по символам, как бегущий строка в описанной ранее процедуре PUT.Начнем с разработки формата спрайтов, который зависит от способа вывода графики, бегущий строка затем, привязываясь к формату, напишем соответствующую процедуру вывода спрайтов на экран (строго говоря, разработка формата спрайтов бегущий строка процедуры их вывода должны протекать параллельно, так как одно от другого неотделимо).Блок данных, описывающий каждый спрайт, будет состоять из двух частей: заголовка, включающего в себя относительные координаты бегущий строка атрибуты для каждого знакоместа (эта часть будет напоминать формат спрайтов для процедуры PUT), бегущий строка данных о состоянии пикселей (по 8 байт на знакоместо - как в символьном наборе). Заголовок будет начинаться указанием общей площади спрайта, или иначе - количества знакомест, составляющих спрайт. Для этого достаточно одного байта, что позволит создавать спрайты площадью до 255 знакомест. Затем для описания каждого символа потребуется по 3 байта, как бегущий строка в процедуре PUT:1-й байт - относительная вертикальная координата данного знакоместа в спрайте;2-й байт - относительная горизонтальная координата данного знакоместа в спрайте;3-й байт - суммарные атрибуты знакоместа.Таким образом, можно составить примерно такой заголовок:SPRITE DEFB 7DEFB 0,2,15DEFB 1,0,6, 1,1,6, 1,2,6, 1,3,6DEFB 2,1,6, 2,2,6Вторую часть блока данных составляют уже знакомые вам описания пикселей знакомест (по 8 байт на каждое), причем они должны быть перечислены в том порядке, в котором указаны в заголовке, например (всего должно быть 7 строк - по количеству символов, входящих в спрайт):DEFB 33,39,62,255,0,127,127,127DEFB 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, но здесь вершину стека можно рассматривать в качестве временной переменной, бегущий строка такой прием может быть рассмотрен как один из способов борьбы с нехваткой регистров.PTBLSPRPUT EQU 0 ;код команды NOPSPROR EQU #B6 ;код команды OR (HL)SPRAND EQU #A6 ;код команды AND (HL)SPRXOR EQU #AE ;код команды XOR (HL)PUSH HLLD (MODE),A ;устанавливаем способ объединения; изображенийLD A,(HL) ;количество знакомест в спрайтеINC HLPUSH HL ;умножаем на 3 (результат в HL)LD L,ALD H,0LD E,LLD D,HADD HL,HLADD HL,DEPOP DEADD HL,DE ;начало данных, описывающих пикселиEX DE,HLPTBL1 PUSH AFPUSH BCLD A,(HL) ;вертикальная координата в спрайтеINC HLPUSH HLADD A,BCP 24JR NC,PTBL4 ;если знакоместо выходит за пределы экранаPUSH DECALL 3742 ;получаем адрес строки экранаPOP DEEX (SP),HLLD A,(HL) ;горизонтальная координата в спрайтеEX (SP),HLADD A,CCP 32JR NC,PTBL4 ;если знакоместо выходит за пределы экранаADD A,LLD L,ALD B,8PUSH HL ;сохраняем адрес экранаPTBL2 LD A,(DE)MODE NOPLD (HL),AINC DEINC HDJNZ PTBL2POP BC ;восстанавливаем адрес экрана в BCLD A,B ;определяем адрес атрибутовAND #18SRA ASRA ASRA AADD A,#58LD B,APOP HL ;восстанавливаем адрес данныхINC HLLD A,(HL) ;переносим байт атрибутов в видеобуферDEC HLLD (BC),APTBL3 POP BCPOP AFINC HLINC HLDEC AJR NZ,PTBL1POP HLRETPTBL4 LD HL,8ADD HL,DEEX DE,HLPOP HLJR PTBL3ОписывающийпрямоугольникРис. 7.1. Спрайт из игры FISTРассмотрим пример вывода спрайта произвольной конфигурации (рис. 7.1). Не правда ли, многие узнали в нем одного из персонажей игры FIST. Все дело в том, что этот спрайт как нельзя лучше демонстрирует эффективность предложенной нами процедуры PTBL, поскольку его форма заметно отличается от прямоугольной. Управляющая часть программы получилась довольно короткой:ORG 60000ENT $LD A,48 ;INK 0: PAPER 6LD (23693),AXOR A ;BORDER 0CALL 8859CALL 3435LD A,2CALL 5633LD B,10 ;ROWLD C,15 ;COLLD A,SPRPUT ;вывод с уничтожением предыдущего; изображенияLD HL,SPR1 ;чтение адреса спрайта SPR1CALL PTBLRETPTBL .........; Заголовок спрайтаSPR1 DEFB 22DEFB 0,3,48, 0,4,48, 1,3,48, 1,4,48, 2,2,48DEFB 2,3,48, 2,4,48, 2,5,48, 2,6,48, 3,2,48DEFB 3,3,48, 3,4,48, 4,0,48, 4,1,48, 4,2,48DEFB 4,3,48, 4,4,48, 5,0,48, 5,1,48, 5,2,48DEFB 5,3,48, 5,4,48; Данные спрайтаDEFB 0,0,0,0,3,12,209,46DEFB 0,0,0,0,192,32,224,240DEFB 249,34,38,43,43,48,35,248DEFB 16,112,56,8,16,48,16,240DEFB 3,6,31,61,61,59,59,27DEFB 254,255,255,255,255,255,255,255DEFB 64,224,255,255,255,255,255,255DEFB 0,0,255,192,224,243,252,240DEFB 0,248,4,2,2,250,50,28DEFB 31,7,5,6,7,15,15,31DEFB 255,255,254,229,3,247,247,235DEFB 240,0,0,0,252,254,254,254DEFB 0,0,0,0,0,62,103,77DEFB 0,0,0,0,0,0,249,255DEFB 31,31,63,63,127,255,255,255DEFB 235,219,219,219,252,224,193,131DEFB 254,254,254,126,254,252,252,248DEFB 65,67,71,69,34,30,0,0DEFB 255,255,255,255,63,7,0,0DEFB 255,254,252,248,240,224,0,0DEFB 3,3,1,2,2,1,0,0DEFB 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: CLS20 DIM m$(6,13): FOR n=1 TO 6: READ m$(n): NEXT n30 DIM s(22): LET spr=040 LET scr=30000: LET ad0=36912: LET addr=ad050 LET ramka=65000: LET svscr=65003: LET restor=65006: LET clsv=65009: LET setv=65012: LET gtbl=6501560 RANDOMIZE USR svscr100 REM --- МЕНЮ ---110 RANDOMIZE USR restor: LET row=6: LET col=8: LET len=15: LET hgt=13: LET pap=7: GO SUB 8000120 LET row=0130 IF row<0 THEN LET row=5135 IF row>5 THEN LET row=0140 FOR n=0 TO 5: PRINT PAPER 7; BRIGHT 1;AT 7+n*2,9;m$(n+1):NEXT n150 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 130180 IF k$="q" OR k$="Q" THEN BEEP .01,20: LET row=row-1:GO TO 130190 IF k$<>"m" AND k$<>"M" THEN GO TO 150200 BEEP .01,20: GO SUB (row+1)*1000210 GO TO 1001000 REM --- ЗАГРУЗКА ЭКРАННОЙ КАРТИНКИ ---1010 INPUT "Screen name: "; LINE n$1020 LOAD n$CODE 16384,69121030 RANDOMIZE USR svscr: RETURN2000 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: RETURN2020 RANDOMIZE USR restor2030 LET spr=spr+1: LET row=12: LET col=15: LET len=1: LET hgt=1:POKE 23303,len: POKE 23304,hgt2040 POKE 23301,col: POKE 23302,row: RANDOMIZE USR ramka2045 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 20402060 IF (k$="a" OR k$="A") AND row<24-hgt THEN RANDOMIZE USR ramka: LET row=row+1: GO TO 20402070 IF (k$="o" OR k$="O") AND col>0 THEN RANDOMIZE USR ramka: LET col=col-1: GO TO 20402080 IF (k$="p" OR k$="P") AND col<32-len THEN RANDOMIZE USR ramka: LET col=col+1: GO TO 20402090 IF k$<>"m" AND k$<>"M" THEN GO TO 20452100 RANDOMIZE USR ramka: BEEP .01,202110 POKE 23303,len: POKE 23304,hgt: RANDOMIZE USR ramka2120 PAUSE 0: LET k$=INKEY$2130 IF (k$="a" OR k$="A") AND hgt<24-row AND len*(hgt+1)<256THEN RANDOMIZE USR ramka: LET hgt=hgt+1: GO TO 21102140 IF (k$="q" OR k$="Q") AND hgt>1 THEN RANDOMIZE USR ramka: LET hgt=hgt-1: GO TO 21102150 IF (k$="o" OR k$="O") AND len>1 THEN RANDOMIZE USR ramka:LET len=len-1: GO TO 21102160 IF (k$="p" OR k$="P") AND len<32-col AND (len+1)*hgt<256THEN RANDOMIZE USR ramka: LET len=len+1: GO TO 21102170 IF k$<>"m" AND k$<>"M" THEN GO TO 21202200 BEEP .01,20: POKE 23300,hgt*len: RANDOMIZE addr:LET ad=USR gtbl2210 IF ad THEN LET s(spr)=addr-ad0: LET addr=ad: RETURN2220 LET col=6: LET row=11: LET hgt=3: LET len=20: LET pap=22230 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: RETURN3000 REM --- СОХРАНЕНИЕ СПРАЙТ-ФАЙЛА ---3010 IF NOT spr THEN RETURN3020 INPUT "Sprite name: "; LINE n$3030 SAVE n$CODE ad0,addr-ad03040 RETURN4000 REM --- УДАЛЕНИЕ СПРАЙТ-ФАЙЛА ИЗ ПАМЯТИ ---4010 IF NOT spr THEN RETURN4020 GO SUB 7000: IF k$<>"y" THEN RETURN4030 LET spr=0: LET addr=ad0: RETURN5000 REM --- ПРОСМОТР ТАБЛИЦЫ СМЕЩЕНИЙ СПРЙТОВ ---5010 CLS : IF NOT spr THEN RETURN5020 FOR n=1 TO spr: PRINT "Sprite No ";n,"Offset == ";s(n): NEXT n5030 PAUSE 0: RETURN6000 REM --- ВЫХОД ИЗ ПРОГРАММЫ ---6010 GO SUB 7000: IF k$<>"y" THEN RETURN6020 CLEAR : STOP7000 REM --- ЗАПРОС ---7010 LET row=11: LET col=5: LET len=21: LET hgt=3: LET pap=6: GO SUB 80007020 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: RETURN8000 REM --- ОКНА ---8010 POKE 23301,col: POKE 23302,row: POKE 23303,len: POKE 23304,hgt8020 RANDOMIZE USR clsv: PRINT PAPER pap; BRIGHT 1;:RANDOMIZE USR setv8030 LET l=len*8-1: LET h=hgt*8-18040 PLOT col*8,175-row*8: DRAW l,0: DRAW 0,-h: DRAW -l,0: DRAW 0,h8050 RETURN9000 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 299999920 LOAD "sptgen"CODE9930 RUNЕсли вы работаете в системе TR-DOS, то несколько строк этой программы следует заменить на приведенные ниже:1020 RANDOMIZE USR 15619: REM : LOAD n$CODE 16384,69123030 RANDOMIZE USR 15619: REM : SAVE n$CODE ad0,addr-ad09920 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 65000ORIGIN EQU $ ;верхняя допустимая граница спрайт-файлаADDR EQU 23670 ;текущий адрес в спрайт-файлеATTR EQU 23695 ;значение атрибутов окнаSCREEN EQU 30000 ;адрес «теневого» экранаN_SYM EQU 23300 ;рассчитанная в Бейсике площадь спрайтаCOL EQU 23301 ;координаты спрайтаROW EQU 23302LEN EQU 23303 ;размеры спрайтаHGT EQU 23304; 65000JP RAMKA; 65003JP SVSCR; 65006JP RESTOR; 65009JP CLSV; 65012JP SETV; 65015GTBL CALL RESTOR ;восстанавливаем экранную картинкуLD (__SP),SP ;запоминаем состояние стека для; возврата при возникновении ошибкиLD IX,(ADDR) ;адрес конца спрайт-файла; Формирование заголовкаLD A,(N_SYM) ;количество знакомест; в создаваемом спрайтеCALL OUT_BT ;записываем первый байт в спрайт-файлLD A,(ROW) ;вычисляем адрес атрибутовLD L,ALD H,0ADD HL,HLADD HL,HLADD HL,HLADD HL,HLADD HL,HLLD A,#58ADD A,HLD H,ALD A,(COL)ADD A,LLD L,ALD DE,(LEN)LD BC,0GTBL1 PUSH BCPUSH DEPUSH HLGTBL2 LD A,BCALL OUT_BT ;позиция по вертикали внутри спрайтаLD A,CCALL OUT_BT ;позиция по горизонталиLD A,(HL)CALL OUT_BT ;байт атрибутовINC HLINC CDEC EJR NZ,GTBL2POP HLLD DE,32 ;переходим к следующей строкеADD HL,DEPOP DEPOP BCINC BDEC DJR NZ,GTBL1; Данные состояния пикселейLD A,(HGT)LD B,ALD A,(ROW)GTBL3 PUSH AFPUSH BCCALL 3742 ;вычисляем адрес начального знакоместаLD A,(COL)ADD A,LLD L,ALD A,(LEN)LD B,AGTBL4 PUSH BCPUSH HLLD B,8 ;переписываем в спрайт-файл 8 байт; знакоместаGTBL5 LD A,(HL)CALL OUT_BTINC HDJNZ GTBL5POP HLINC HL ;переходим к следующему знакоместуPOP BCDJNZ GTBL4POP BCPOP AFINC A ;переходим к следующей строкеDJNZ GTBL3PUSH IX ;возвращаем в Бейсик адресPOP BC ; конца спрайт-файлаRETOUT_BT PUSH BC ;запись в спрайт-файл байта из APUSH HL; Проверка наличия свободной памятиPUSH IXPOP HLLD BC,ORIGIN ;адрес конца свободной памяти; для спрайт-файлаAND A ;очистка флага CY перед вычитанием; (если этого не сделать, результат будет неверен!)SBC HL,BC ;если текущий адрес достиг ORIGIN,JR NC,OUTRAM ; происходит выход в БейсикPOP HLPOP BCLD (IX),A ;записываем байт в спрайт-файлINC IX ;увеличиваем адрес размещения кодовRETOUTRAM LD SP,(__SP) ;восстанавливаем значение стекаLD BC,0 ;возвращаем в Бейсик код ошибкиRET__SP DEFW 0 ;переменная для сохранения указателя стека; Рисование прямоугольной пунктирной рамкиRAMKA LD A,(ROW)PUSH AFCALL 3742 ;вычисляем адрес экранаLD A,(COL)ADD A,LLD L,ACALL HOR ;проводим верхнюю линиюCALL VERT1 ;рисуем боковые стороны в первой; строке окнаLD A,(HGT)DEC AJR Z,RAMK2 ;обходим, если единственная строкаLD B,A ;иначе рисуем боковые стороны по всей; высоте окнаPOP AFRAMK1 PUSH AFCALL VERT ;заканчиваем предыдущую строкуPOP AFINC A ;переходим к следующейPUSH AFCALL 3742 ;вычисляем адрес экранаLD A,(COL)ADD A,LLD L,ACALL VERT ;ставим верхние точкиCALL VERT1 ;заканчиваем вертикальный пунктирPOP AFDJNZ RAMK1 ;повторяемPUSH AFRAMK2 POP AF; Горизонтальная пунктирная линияHOR PUSH BCPUSH HLLD A,(LEN) ;рисуем пунктир по ширине окнаLD B,AHOR1 LD A,%10011001 ;фактура пунктирной линииXOR (HL) ;объединяем с экранным изображениемLD (HL),A ;возвращаем на экранINC HLDJNZ HOR1POP HLPOP BCRET; Рисование двух точек для боковых сторон рамкиVERT PUSH HLLD A,128 ;левая точкаXOR (HL)LD (HL),ALD A,(LEN) ;ищем адрес правой стороны окнаDEC AADD A,LLD L,ALD A,1 ;правая точкаXOR (HL)LD (HL),APOP HLRET; Боковые стороны рамки по высоте знакоместаVERT1 INC H ;пропускаем 3 ряда пикселейINC HINC HCALL VERT ;ставим точки на левой бегущий строка правой; сторонах прямоугольникаINC HCALL VERT ;повторяем для следующего рядаINC H ;делаем следующий промежутокINC HINC HRET; Сохранение области видеобуфера в «теневом» экранеSVSCR LD HL,16384LD DE,SCREENLD BC,6912LDIRRET; Восстановление изображения на экранеRESTOR LD HL,SCREENLD DE,16384LD BC,6912LDIRRET; Подпрограмма очистки окнаCLSV .........; Подпрограмма установки атрибутов в окнеSETV .........МУЛЬТИПЛИКАЦИЯВ большинстве компьютерных игр персонажи беспрерывно передвигаются по экрану, создавая неповторимые ситуации, чем собственно бегущий строка привлекают к себе внимание многочисленной армии почитателей ZX Spectrum. В пятой главе мы уже слегка затронули проблему движения изображений, прояснив с помощью нескольких примеров те принципы, которые лежат в основе любого перемещения по экрану, будь то тексты или спрайты. Теперь настало время внести в этот вопрос полную ясность, показав способы, наиболее часто используемые в игровых программах.У вас может возникнуть вопрос, бегущий строка зачем, собственно, рассматривать несколько разных способов, не проще ли ограничиться одним, только очень хорошим, бегущий строка применять его во всех случаях компьютерной «жизни». Все дело в том, что возможны совершенно отличные друг от друга ситуации, определяемые конкретным замыслом. Скажем, для простых сюжетов нет смысла использовать сложные способы передвижения спрайтов, бегущий строка в насыщенных играх простые способы уже могут оказаться неэффективными.Первый способ основан на скроллинге окон, бегущий строка если вы припомните программу, которая раздвигает в разные стороны створки железной решетки, то получите о нем полное представление. Тем не менее, мы вновь к нему возвращаемся, поскольку в нашем распоряжении появилась удобная процедура для вывода спрайтов. Перечислим действия, характерные для этого способа:поместите на экран спрайт, например, с помощью процедуры PTBL, установив режим SPRPUT;задайте окно, по размерам покрывающее этот спрайт бегущий строка выполните скроллинг при помощи одной из четырех рассмотренных выше процедур. Спрайт довольно резво устремится в нужную сторону, так что в программе необходимо предусмотреть небольшую задержку.Рис. 7.2. Перемещение спрайта скроллингом окнаСразу же виден бегущий строка недостаток этого способа, который состоит в том, что спрайт перемещается по экрану вместе с фоном, поскольку скроллинг захватывает все изображение в окне. Отсюда ясно, что применять такой метод можно лишь в тех случаях, когда фон как таковой отсутствует или, по крайней мере, мелкие детали не попадают в сдвигаемое окно. В качестве иллюстрации к сказанному приведем небольшую программку, которая плавно перемещает по экрану симпатичный паровозик, позаимствованный нами из спрайт-файла SPRITE2B пакета Laser Basic (рис. 7.2).ORG 60000ENT $XOR ACALL 8859LD A,5LD (23693),ACALL 3435LD A,2CALL 5633; Начальная установка регистров процедуры PTBLLD B,10LD C,0LD A,SPRPUTLD HL,PAROW; Вывод на экран «паровозика»CALL PTBL; Задание параметров окнаLD HL,#A00 ;COL = 0, ROW = 10LD (COL),HLLD HL,#320 ;LEN = 32, HGT = 3LD (LEN),HLLD B,0 ;задание длины пробега «паровозика»; (0 = 256 пикселей)MOVE PUSH BCCALL SCR_RT ;обращение к процедуре скроллинга вправоPOP BCDJNZ MOVERET; Подпрограмма скроллинга окна вправоSCR_RT .........; Подпрограмма вывода спрайтаPTBL .........; Переменные к процедуре скроллингаCOL DEFB 0ROW DEFB 0LEN DEFB 0HGT DEFB 0; Заголовок данных для «паровозика»PAROW DEFB 14,0,0,5,0,1,5,0,2,5,0,3,5DEFB 1,0,5,1,1,5,1,2,5,1,3,5,1,4,5DEFB 2,0,5,2,1,5,2,2,5,2,3,5,2,4,5; ДанныеDEFB 0,0,0,3,15,63,64,95DEFB 0,0,0,255,255,254,1,255DEFB 0,0,0,192,160,70,201,73DEFB 0,0,0,0,30,33,26,18DEFB 24,248,152,253,133,181,181,181DEFB 33,39,62,255,0,127,127,127DEFB 246,73,146,255,0,254,252,251DEFB 230,83,134,189,133,133,173,214DEFB 0,192,96,160,160,160,160,96DEFB 181,133,253,0,255,38,20,15DEFB 127,0,255,0,255,83,138,7DEFB 244,11,247,0,255,41,69,131DEFB 35,216,228,3,249,148,35,192DEFB 192,32,216,176,96,192,128,0Второй способ не многим сложнее первого. Он основан на многократном выводе спрайта на экран. Если на каждом шаге изменять на единицу одну из координат, то спрайт будет двигаться параллельно соответствующей границе экрана, если же менять сразу обе, то он начнет перемещаться по диагонали. Основное требование к спрайту - он должен иметь по краям пустое пространство шириной в одно знакоместо, иначе изображение, помещенное на экран на предыдущем шаге, не будет полностью затираться следующим выводимым спрайтом бегущий строка по экрану потянется не предусмотренный программистом след. Таким образом, если пустые места сделаны вокруг всего спрайта, то его можно спокойно передвигать в любом направлении, если же заранее известно, что он будет перемещаться вправо бегущий строка никуда больше (как в примере ниже), то достаточно оставить пустую полоску шириной в одно знакоместо только слева.К сожалению, этот способ перемещения спрайта тоже не лишен недостатка, видного невооруженным глазом: вместе с изображением, действительно подлежащим удалению, спрайт как ластик сотрет вообще весь фон позади себя. Справиться с этим можно точно так же, как мы рекомендовали выше, - выводить спрайт на сплошной фон, лишенный сложного пейзажа, что приемлемо для ограниченного числа игровых сюжетов. В качестве иллюстрации приведем программу, которая передвигает по экрану слева направо маленького динозавра, перебравшегося к нам из игры LITTLE PUFF:ORG 60000ENT $XOR ACALL 8859LD A,7LD (23693),ACALL 3435LD A,2CALL 5633; Основная часть программыLD C,-4MOVE LD B,10LD A,SPRPUTLD HL,DINPUSH BCCALL PTBLLD BC,10CALL 7997POP BCINC CLD A,CCP 32JP M,MOVE ;если координата меньше 32 (с учетом знака)RET; Подпрограмма вывода спрайтаPTBL .........; Заголовок данных для «динозавра»DIN DEFB 16,0,0,4,0,1,4,0,2,4,0,3,4DEFB 1,0,4,1,1,4,1,2,4,1,3,4DEFB 2,0,4,2,1,4,2,2,4,2,3,4DEFB 3,0,4,3,1,4,3,2,4,3,3,4; Данные:DEFB 0,0,0,0,0,0,0,0DEFB 0,0,0,0,0,0,0,0DEFB 0,0,0,0,0,70,117,42DEFB 0,0,0,0,0,64,160,64DEFB 0,0,0,0,0,0,0,0DEFB 0,0,2,6,11,21,46,31DEFB 78,72,110,52,123,111,96,31DEFB 192,128,219,173,71,254,127,0DEFB 0,0,0,0,0,0,0,0DEFB 53,100,85,181,20,4,0,0DEFB 205,188,63,119,103,231,55,185DEFB 248,0,0,192,224,240,208,224DEFB 0,0,0,0,0,0,0,0DEFB 0,0,0,0,0,0,1,0DEFB 28,57,67,167,156,191,157,0DEFB 24,120,184,48,38,140,96,0DEFB 0,0,0,0,0,0,0,0Программа содержит всего один цикл бегущий строка настолько проста, что в дополнительных комментариях не нуждается.Третий способ использует вывод спрайтов на экран по принципу XOR, который заложен в процедуре PTBL (как, впрочем, бегущий строка другие). Применение принципа XOR для объединения изображений позволяет легко справиться с проблемой восстановления фона при перемещении спрайтов. Перечислим вначале все операции, которые должна выполнить программа:спрайт помещается на экран процедурой PTBL, в режиме XOR;через некоторое время (должен же спрайт немного побыть на экране) вторично выполняется процедура PTBL для того же спрайта, опять же по принципу XOR, при этом он стирается;координаты спрайта (или одна из них) изменяются бегущий строка все повторяется сначала, при этом спрайт появляется на экране уже в другом месте.Проделывая все это многократно, можно получить неплохой эффект мультипликации с сохранением фона.Продемонстрируем этот способ на примере программы, которая в действии выглядит следующим образом. По дороге с ружьем на изготовку двигается солдат, медленно, но верно приближаясь к стенке из белого кирпича. Можно легко заметить, что движение состоит из двух фаз, каждой из которых, очевидно, должен соответствовать один спрайт: первый - ноги вместе бегущий строка ружье чуть-чуть приподнято бегущий строка второй - ноги расставлены в шаге, бегущий строка ружье при этом опускается немного вниз. Когда солдат проходит мимо стенки, их картинки начинают смешиваться по принципу XOR, что мы бегущий строка наблюдаем на экране - появляется какое-то хаотическое изображение, как будто человек продирается сквозь стену, бегущий строка не идет мимо нее. Однако после того как стенка оказывается позади солдата, мы обнаруживаем, что оба изображения полностью восстановились.ORG 60000ENT $LD A,4LD (23693),AXOR ACALL 8859CALL 3435LD A,2CALL 5633; Рисование пейзажа, состоящего из дороги бегущий строка стеныCALL GRUNT; Вывод первой фазы спрайта «солдат» в режиме XORLD B,9 ;задаем координату YLD C,-3 ;начальное значение координаты XLOOP LD A,SPRXOR ;устанавливаем режим выводаLD HL,SOLD1 ;задаем адрес спрайта 1 фазыPUSH HLPUSH BCCALL PTBLLD BC,20 ;задержка спрайта на экранеCALL 7997POP BCPOP HL; Повторный вывод первой фазы спрайта в режиме XORLD A,SPRXORPUSH HLPUSH BCCALL PTBLPOP BCPOP HLINC C ;увеличиваем координату X; Вывод второй фазы спрайта «солдат» в режиме XORLD A,SPRXORLD HL,SOLD2 ;задаем адрес спрайта 2 фазыPUSH HLPUSH BCCALL PTBLLD BC,20CALL 7997POP BCPOP HL; Повторный вывод второй фазы спрайта в режиме XORLD A,SPRXORPUSH HLPUSH BCCALL PTBLPOP BCPOP HLINC C ;увеличиваем координату XLD A,C ;количество шагов солдатаCP 32 ;проверка условия конца «дороги»JP M,LOOPRET; Подпрограмма рисования пейзажаGRUNT EXXPUSH HLLD BC,#4700 ;начало горизонтальной линии (B=71, C=0)CALL 8933; Рисование «дорожки»LD DE,#101LD BC,250CALL 9402; Рисование «стены»LD BC,#915 ;B = 9, C = 21STEN PUSH BCLD A,SPRPUT ;устанавливаем режим выводаLD HL,STENA ;задаем адрес спрайта «стена»CALL PTBLPOP BCINC BLD A,BCP 13JR C,STENPOP HLEXXRETPTBL .........; Заголовок данных первой фазы спрайта «солдат»SOLD1 DEFB 10DEFB 0,0,7, 0,1,7, 1,0,7, 1,1,7DEFB 2,0,7, 2,1,7, 2,2,7DEFB 3,0,7, 3,1,7, 3,2,7; Данные первой фазы спрайта «солдат»DEFB 1,4,13,27,91,35,28,3DEFB 128,32,112,184,182,140,56,192DEFB 12,16,19,15,15,7,3,27DEFB 8,32,12,156,192,152,172,192DEFB 60,63,114,45,31,47,112,123DEFB 250,7,0,183,160,44,192,56DEFB 0,0,2,255,96,224,0,0DEFB 51,7,1,6,12,19,30,15DEFB 220,220,216,33,27,11,135,134DEFB 0,0,0,128,64,192,128,0; Заголовок данных второй фазы спрайта «солдат»SOLD2 DEFB 9DEFB 0,0,7, 0,1,7, 1,0,7, 1,1,7DEFB 2,0,7, 2,1,7, 2,2,7DEFB 3,0,7, 3,1,7; Данные второй фазы спрайтаDEFB 3,8,26,55,183,71,56,7DEFB 0,64,224,112,108,24,112,128DEFB 24,32,38,31,31,15,7,55DEFB 16,64,24,56,128,48,104,128DEFB 121,254,239,200,178,127,62,204DEFB 244,14,251,0,239,65,91,0DEFB 0,0,0,8,252,128,128,0DEFB 243,111,15,0,6,6,1,15DEFB 184,184,184,0,48,214,173,239; Заголовок спрайта «стена»STENA DEFB 2DEFB 0,0,7, 0,1,7; Данные спрайта «стена»DEFB 0,223,223,223,0,253,253,253DEFB 0,223,223,223,0,253,253,253Четвертый способ основан на принципе записи части экранного изображения в буферную область памяти с последующим его возвратом на экран. Сначала поясним суть этого способа, бегущий строка затем приведем небольшую программу, которая его иллюстрирует. В программе ГЕНЕРАТОР СПРАЙТОВ для сохранения образа экрана в памяти использовалась процедура GTBL бегущий строка чтобы не писать еще одну подпрограмму, применим ее же для пересылки в буфер фрагмента экранного изображения. Вставляя эту процедуру в программу, следует предварительно внести в нее небольшие изменения:убрать первые четыре строки (до CALL OUT_BT);все команды CALL OUT_BT заменить наLD (IX),AINC 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 60000ENT $N_SYM EQU 6 ;задаем количество знакомест окнаLD A,6LD (разделы
продажа кофе
вихревой теплогенераторы
катетер
зеркало багуа
sharp ar-m205
обзвон
краска ржавчина
плазменный панель настенный
степ-аэробика
управление иваново
1000 холодильник
купить электроэнцефалограф
альтернативный медицина
управление архангельск
профиль salamander
кайт пилотажный
поставка холодильный камера
knauf гипсокартон
организация похорон
ожирение
кожгалантерея
регестрация пбоюл
inerta краска
фарфор
куллер 478
пассажирский лифт
купить k800i
купить ломтерезку
корпоративный обслуживание
охота лис
проходить осмотр гинеколог
искать фотограф
силуэт слименд лифт
ваза 2112
промышленый альпинизм
пошив корпоративный костюм
вилатерм
нард онлайн
спб доставка
корпоративный хранилище данный спирли
kyiv apartaments service
купить пароварка
трехфазный электросчетчик
зеркало багуа
измеритель петля фаза нуль
вытяжка
тестоокруглитель ленточный
переводческий бюро
лак краска
разогреть вчерашний обед
стеклянный перегородка
билет russia music awards
урок охота
кострома коммерческий
дермато-венеролог
купить ниппель
бегущий строка