Вывод изображения из «теневого» экрана
Рисунок 7.4. Вывод изображения из «теневого» экрана
Поясним, как это достигается. В блоке данных, описывающих пейзаж (в программе он обозначен меткой D_LAND), указывается положение каждого дома (или другого объекта) на трассе, протяженность дома, его «удаленность» от дороги и адрес другого блока, задающего его внешний вид. Программа просматривает данные пейзажа и, исходя из положения автомобиля (он всегда выводится в центре окна), выбирает только те дома, которые целиком или частично попадают в окно экрана, то есть если правый угол дома не выходит за левую границу и левый - за правую, а остальные пропускает. После этого начинается вывод объектов в «теневой» экран: сначала дома, затем рисуется дальний тротуар, автомобиль, ближний тротуар и, наконец, фонари. Как только построение закончено, окно «теневого» экрана переносится в физический видеобуфер и тем самым изображение становится видимым.
Так как объем книги не безграничен, в программе заданы только два типа зданий, а протяженность пейзажа измеряется 200 знакомест. Но вы можете дополнить графику, составив из имеющихся спрайтов другие дома. Попробуйте увеличить пробег автомобиля, введите новые спрайты, изображающие деревья, решетки ограды, арки, попытайтесь создать загородный пейзаж. Для этого вам нужно будет только расширить блоки данных, формат которых подробно описан в тексте программы. Не бойтесь экспериментировать, и результат, уверены, порадует вас.
Несмотря на относительную сложность программы, в ней не встретится неизвестных доселе команд. Единственное нововведение - это процедура ПЗУ, находящаяся по адресу 8020, которая служит для проверки нажатия клавиши Break (Caps Shift/Space). Подпрограмма не требует никаких входных параметров и сообщает о том, что Break нажата установкой на выходе флага переноса. В противном случае выполняется условие NC.
До того, как мы приведем текст программы, обращаем ваше внимание, что вызывается она только из Бейсика, так как ассемблер GENS пользуется своим собственным внутренним стеком и поскольку он может оказаться в любом месте (все зависит от адреса загрузки GENS), то в результате «теневой» экран может перекрыть стек, а что из этого следует, догадаться нетрудно.
ORG 60000 ; Адрес «теневого» (или виртуального) экрана = #8000 V_OFFS EQU #40 ;старший байт смещения адреса ; «теневого» экрана относительно ; начального адреса физического экрана LD A,69 LD (23693),A XOR A CALL 8859 CALL 3435 LD A,2 CALL 5633 ;здесь необходима только для правильного ; вывода атрибутов основного экрана ; Инициализация переменных MAIN LD A,2 LD (X_LAMP),A LD HL,0 LD (X_LAND),HL CALL FRAME ;рамка вокруг окна MAIN1 CALL CLS_V ;очистка «теневого» экрана ; Формирование игрового поля в «теневом» экране CALL LAND ;вывод заднего плана (дома) CALL LINE1 ;рисование дальнего тротуара CALL PUTCAR ;автомобиль CALL LINE2 ;ближний тротуар CALL LAMPS ;фонари ; ---------------- CALL PUTVRT ;вывод окна виртуального экрана ; на физический CALL 8020 ;проверка нажатия клавиши Break
RET NC ;выход из программы, если нажата LD HL,(X_LAND) ;изменение координаты автомобиля INC HL LD (X_LAND),HL LD DE,200 ;если пройдено расстояние AND A ; меньше 200 знакомест, SBC HL,DE JR NZ,MAIN1 ; то движение продолжается LD BC,100 ;иначе - пауза 2 сек. CALL 7997 JR MAIN ; и переход к началу пути ; Рисование горизонтальных линий белого цвета, изображающих тротуары LINE1 LD L,#40 LD H,#4A+V_OFFS JR LINE3 LINE2 LD L,#60 LD H,#4C+V_OFFS LINE3 PUSH HL ;адрес экрана здесь не рассчитывется, ; а задается в явном числовом виде LD D,H LD E,L INC DE LD (HL),255 ;сплошная линия (если изменить число, ; получится пунктирная) LD BC,31 LDIR ;проводим линию POP HL LD A,H ;расчет адреса атрибутов SUB V_OFFS AND #18 RRCA RRCA RRCA ADD A,#58+V_OFFS LD H,A LD D,H LD E,L INC DE LD (HL),7 ;INK 7, PAPER 0 LD BC,31 LDIR RET ; Вывод автомобиля в виртуальный экран PUTCAR LD BC,#90E ;координаты фиксированы (B = 9, C = 14) LD HL,SPR7 ;маска LD A,SPRAND ;по принципу AND CALL PTBL LD HL,SPR6 ;автомобиль LD A,SPROR ;по принципу OR JP PTBL ; Рисование в виртуальном экране дорожных фонарей LAMPS LD HL,X_LAMP LD C,(HL) ;горизонтальная координата самого левого ; на экране фонаря LD B,7 ;вертикальная координата фиксирована PUSH HL LAMPS1 LD HL,SPR9 ;маска LD A,SPRAND CALL PTBL LD HL,SPR8 ;фонарь LD A,SPROR CALL PTBL LD A,20 ;следующий через 20 знакомест ADD A,C LD C,A CP 28 JR C,LAMPS1 ;закончить вывод? POP HL DEC (HL) ;уменьшение координаты на 2 DEC (HL) RET P ;выход, если начальная координата ; не отрицательна LD (HL),18 ;иначе задаем начальную координату RET X_LAMP DEFB 0 ; Подпрограмма очистки виртуального экрана CLS_V LD H,#40+V_OFFS LD L,0 LD D,H LD E,L INC DE LD (HL),0 LD BC,6144 LDIR ; Атрибуты LD (HL),1 ;INK 1, PAPER 0 LD BC,767 LDIR RET ; Формирование изображения здания, скомбинированного из нескольких ; спрайтов (адрес соответствующего блока данных в паре HL) PUT_B LD A,(HL) ;количество блоков в доме INC HL PUT_B1 PUSH AF PUSH BC LD A,(HL) ;горизонтальная координата блока INC HL ADD A,C CP 2 ;проверка выхода за пределы окна JR C,PUT_B3 CP 29 JR NC,PUT_B3 LD C,A LD A,(HL) ;вертикальная координата блока INC HL ADD A,B ;проверка выхода за пределы окна JP M,PUT_B4 LD B,A LD E,(HL) ;адрес спрайта, изображающего блок INC HL LD D,(HL) INC HL PUSH HL EX DE,HL LD A,SPRPUT CALL PTBL ;выводим спрайт в «теневой» экран POP HL PUT_B2 POP BC POP AF DEC A JR NZ,PUT_B1 ;следующий блок RET PUT_B3 INC HL ;обход, если блок выходит за пределы окна PUT_B4 INC HL INC HL JR PUT_B2 ; Вывод помещающейся в окно части пейзажа X_LAND DEFW 0 ;координата автомобиля на трассе LAND LD HL,D_LAND ;блок данных, описывающих ; местоположение и внешний вид домов LAND1 LD BC,(X_LAND) LD E,(HL) ;горизонтальная координата дома на трассе INC HL LD D,(HL) INC HL LD A,D OR E RET Z ;0 - маркер конца блока данных LD A,(HL) ;протяженность дома в знакоместах INC HL PUSH HL PUSH DE EX DE,HL ;вычисляем координату дальнего конца дома ADD A,L LD L,A LD A,H ADC A,0 LD H,A INC HL AND A SBC HL,BC ;сравниваем с текущим положением ; автомобиля POP DE JR C,LAND3 ;если дом выходит за левый край окна LD HL,28 ADD HL,BC SBC HL,DE JR C,LAND3 ;если дом выходит за правый край окна EX DE,HL SBC HL,BC ;вычисление экранной координаты дома LD C,L POP HL LD B,(HL) ;вертикальная экранная координата дома INC HL LD E,(HL) ;адрес блока данных, описывающих дом INC HL LD D,(HL) PUSH HL EX DE,HL CALL PUT_B ;вывод изображения дома в «теневой» экран POP HL LAND2 INC HL JR LAND1 ;следующий дом LAND3 POP HL ;обход, если изображение дома не ; попадает в окно экрана INC HL INC HL JR LAND2 ; ВНИМАНИЕ! В процедуре PTBL есть изменения! PTBL SPRPUT EQU 0 SPROR EQU #B6 SPRAND EQU #A6 SPRXOR EQU #AE PUSH HL LD (MODE),A LD A,(HL) INC HL PUSH 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 ; +++ Добавление +++ LD A,V_OFFS ADD A,H LD H,A ; +++ 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 LD A,B AND #18 SRA A SRA A SRA A ; +++ Изменение: вместо ADD A,#58 +++ ADD A,#58+V_OFFS ; +++ 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 ; Вывод окна «теневого» экрана на физический PUTVRT LD A,8 ;отступ сверху (в пикселях) LD B,12*8 ;высота окна (в пикселях) PUT_V1 PUSH AF PUSH BC LD C,4*8 ;отступ слева (в пикселях) CALL 8880 ;адрес физического экрана LD D,H ;сохраняем в DE LD E,L LD A,V_OFFS ADD A,H ;в HL - соответствующий адрес LD H,A ; «теневого» экрана LD BC,24 ;ширина окна - 24 знакоместа LDIR POP BC POP AF INC A ;следующий ряд пикселей DJNZ PUT_V1 ; Перенос атрибутов LD DE,#5824 ;адрес верхнего левого угла окна LD L,E ; в области атрибутов LD A,D ADD A,V_OFFS ;вычисляем соответствующий адрес LD H,A ; в «теневом» экране LD B,12 PUT_V2 PUSH BC LD BC,24 LDIR ;переносим 24 байта (по ширине окна) LD BC,8 ;переходим к следующей ADD HL,BC ; строке экрана (32-24 = 8) EX DE,HL ADD HL,BC EX DE,HL POP BC DJNZ PUT_V2 RET ; Рисование рамки вокруг окна ; (подпрограммы LABS1 и PRINT описаны в предыдущем разделе) FRAME LD IX,DFRAME ;Данные для построения рамки
; Блоки дома: ; Окно 1 (с рамой) SPR1 DEFB 4 DEFB 0,0,65, 0,1,65, 1,0,65, 1,1,65 DEFB 255,193,193,193,255,193,193,193 DEFB 255,7,7,7,7,7,7,7 DEFB 193,193,193,255,255,255,255,255 DEFB 7,7,7,255,255,255,255,255 ; Окно 2 (без рамы) SPR2 DEFB 4 DEFB 0,0,65, 0,1,65, 1,0,65, 1,1,65 DEFB 255,252,252,252,252,252,252,252 DEFB 255,63,63,63,63,63,63,63 DEFB 252,252,252,255,255,255,255,255 DEFB 63,63,63,255,255,255,255,255 ; Окно с балконом SPR3 DEFB 4 DEFB 0,0,65, 0,1,65, 1,0,65, 1,1,65 DEFB 255,193,193,193,193,193,193,193 DEFB 255,7,7,7,7,7,7,7 DEFB 191,182,182,182,182,182,128,255 DEFB 251,219,219,219,219,219,3,255 ; Духовые окна на крыше дома SPR4 DEFB 4 DEFB 0,0,65, 0,1,65, 1,0,65, 1,1,65 DEFB 0,0,255,255,254,254,254,254 DEFB 0,0,255,255,127,127,127,127 DEFB 255,255,255,255,153,153,255,255 DEFB 255,255,255,255,153,153,255,255 ; Подвальные окна SPR5 DEFB 2 DEFB 0,0,65, 0,1,65 DEFB 255,255,255,255,240,255,255,255 DEFB 255,255,255,255,15,255,255,255 ; Автомобиль SPR6 DEFB 10 DEFB 0,0,66, 0,1,66, 0,2,66, 0,3,66, 0,4,66 DEFB 1,0,66, 1,1,66, 1,2,66, 1,3,66, 1,4,66 DEFB 0,15,24,48,56,62,63,57 DEFB 0,255,48,48,56,60,255,249 DEFB 0,255,48,48,56,60,255,249 DEFB 0,255,48,48,56,60,255,243 DEFB 0,192,96,32,32,48,248,248 DEFB 63,63,62,29,1,0,0,0 DEFB 255,255,239,183,240,224,0,0 DEFB 255,255,255,255,0,0,0,0 DEFB 255,255,247,237,15,7,0,0 DEFB 248,252,124,184,128,0,0,0 ; Маска для спрайта «автомобиль» SPR7 DEFB 10 DEFB 0,0,66, 0,1,66, 0,2,66, 0,3,66, 0,4,66 DEFB 1,0,66, 1,1,66, 1,2,66, 1,3,66, 1,4,66 DEFB 224,192,128,131,128,128,128,128 DEFB 0,0,0,135,129,0,0,0 DEFB 0,0,0,135,129,0,0,0 DEFB 0,0,0,135,129,0,0,0 DEFB 31,15,15,15,135,3,3,3 DEFB 128,128,128,128,192,252,254,255 DEFB 0,0,0,0,0,7,15,255 DEFB 0,0,0,0,0,255,255,255 DEFB 0,0,0,0,0,224,240,255 DEFB 1,1,1,1,3,63,127,255 ; Фонарный столб SPR8 DEFB 7 DEFB 0,0,70, 0,1,70, 0,2,70, 1,1,70 DEFB 2,1,70, 3,1,70, 4,1,70 DEFB 0,0,127,64,63,0,0,0 DEFB 0,0,239,146,17,16,16,16 DEFB 0,0,252,4,248,0,0,0 DEFB 16,16,16,16,16,16,16,16 DEFB 16,16,16,16,16,16,16,16 DEFB 16,16,16,56,56,56,56,56 DEFB 56,56,56,56,56,56,56,56 ; Маска для спрайта «фонарный столб» SPR9 DEFB 7 DEFB 0,0,70, 0,1,70, 0,2,70, 1,1,70 DEFB 2,1,70, 3,1,70, 4,1,70 DEFB 255,0,0,0,0,128,255,255 DEFB 255,0,0,0,0,68,199,199 DEFB 255,1,1,1,1,3,255,255 DEFB 199,199,199,199,199,199,199,199 DEFB 199,199,199,199,199,199,199,199 DEFB 199,199,131,131,131,131,131,131 DEFB 131,131,131,131,131,131,131,131 ; Данные для формирования зданий: ; 1-й байт - количество блоков в доме ; Далее следуют данные для каждого блока ; 1-й байт: горизонтальная координата блока в доме относительно ; верхнего левого угла изображения ; 2-й байт: вертикальная координата блока в доме ; 3-й и 4-й байты: адрес спрайта блока D_BLD1 DEFB 25 DEFW #000,SPR4,#002,SPR4,#004,SPR4,#006,SPR4,#008,SPR4 DEFW #200,SPR3,#202,SPR2,#204,SPR1,#206,SPR2,#208,SPR3 DEFW #400,SPR3,#402,SPR2,#404,SPR1,#406,SPR2,#408,SPR3 DEFW #600,SPR1,#602,SPR2,#604,SPR1,#606,SPR1,#608,SPR1 DEFW #800,SPR5,#802,SPR5,#804,SPR5,#806,SPR5,#808,SPR5 D_BLD2 DEFB 15 DEFW #000,SPR3,#002,SPR1,#004,SPR2 DEFW #200,SPR3,#202,SPR1,#204,SPR2 DEFW #400,SPR3,#402,SPR1,#404,SPR2 DEFW #600,SPR1,#602,SPR1,#604,SPR2 DEFW #800,SPR5,#802,SPR5,#804,SPR5 ; Данные для формирования пейзажа: ; 1-й и 2-й байты (слово): горизонтальная координата дома ; 3-й байт: протяженность дома в знакоместах ; 4-й байт: вертикальная координата дома ; 5-й и 6-й байты (слово): адрес данных для формирования дома D_LAND DEFW 1,#10A,D_BLD1,14,#FE0A,D_BLD1,25,#FE0A,D_BLD1 DEFW 39,#106,D_BLD2,46,#10A,D_BLD1,63,6,D_BLD2 DEFW 70,10,D_BLD1,90,#10A,D_BLD1,101,10,D_BLD1 DEFW 112,#FF0A,D_BLD1,123,#FE0A,D_BLD1,138,#106,D_BLD2 DEFW 145,#FE06,D_BLD2,152,#FF06,D_BLD2,159,6,D_BLD2 DEFW 166,#106,D_BLD2,178,#FE0A,D_BLD1,190,#FE06,D_BLD1 DEFW 0 ; Данные рамки вокруг окна (формат описан в предыдущем разделе) DFRAME DEFB 0,3,0,0, 1,4,0,24, 2,28,0,0 DEFB 3,3,1,12@#80, 3,28,1,12@128 DEFB 5,3,13,0, 1,4,13,24, 4,28,13,0 DEFB -1 ; Элементы рамки D_SYMB DEFB 127,213,159,191,253,182,248,181 DEFB 255,85,255,255,85,170,0,255 DEFB 254,83,249,245,121,181,121,181 DEFB 249,181,249,181,249,181,249,181 DEFB 249,117,249,245,81,169,3,254 DEFB 249,189,255,191,213,170,192,127