ZXNet эхоконференция «code.zx»


тема: статья о выводе спрайтов(из неопубликованого :)



от: Alexander Kucher
кому: All
дата: 18 Sep 2000
Привет All! === Цитирую файл SPRITE.TX === (c) Stels Hello всем, кто решил заглянуть в этот раздел нашего журнала ! Данная статья расчитана на более-менее подготовленого читателя, хотя можно конечно и не вникать во все тонкости этого дела. Редко перед каким программистом не воз- никала проблема вывода спрайта с точ- ностью до пиксела. Причем если перед- вигать спрайт по вертикали довольно легко, то с движением по горизонтали уже возникают довольно существенные труд- ности. Эту проблему можно решить нес- колькими способами, которые зависят от конкретной ситуации. Hапример можно построить в памяти восемь сдвинутых друг относительно друга спрайтов, этот способ позволяет получить высокую скорость вывода спрайтов, но имеет свои недостатки. Самое главное, что каждый спрайт занимает в 8 раз больше памяти, а следовательно его можно применять лишь при небольшом количестве спрайтов. Второй способ это сдвигать каждый выводимый байт спрайта вправо на 0..7 позиций, что занимает довольно много времени, но зато высвобождает больше памяти. Третий способ, это способ немного напоминающий второй, но работающий значительно быстрее. Hедостаток этого способа в том, что сама процедура вывода занимает намного больше места, чем в двух первых случаях, и поэтому не рекомендуется его применять если вы не испытываете недостатка в памяти или вам не требуется большое быстродействие. Также скажу, что этот способ вывода спрайтов с небольшими изменениями позаимствован мною из игры Вячеслава Медноногова "Черный Ворон". Теперь о некоторых ограничениях: -нельзя выводить спрайты, выходящие за границы экрана. -т.к. процедура использует стек, то нужно или специальным образом изменить обработчик прерываний, или вообще их запретить. В противном случае спрайт будет затираться мусором. Фактически нам предстоит написать 8 почти одинаковых процедур вывода, каждая из которых будет выводить на экран спрайт со сдвигом относительно знакоместа на 0..7 пикселей. Сначала пишем процедуру, которая выводит один вертикальный столбец спрайта со сдвигом 0 , т.е без сдвига. Входные данные для всех восьми процедур будут такие: HL - Адрес в экране. B - Высота спрайта в пикселах. SP - Адрес выводимого столбца спрайта, увеличеный на 2. DE - Первые два байта спрайта. (D - спрайт,E - маска). Put0 ld a,(hl) or e xor d ld (hl),a pop de ;берем следующие байты ;спрайта и маски. djnz Put0_ jp Exit ;Выход если нарисовали ;весь столбец. Put0_ inc h ;Вычисляем адрес ld a,h ;следующей строки and 7 ;в экране. jp nz,Put0 ld a,l add a,#20 ld l,a jr c,Put0 ld a,h sub 8 ld h,a jr Put0 Остальные семь процедур отличаются друг от друга только первой частью, хотя конечно некоторые заметят,что вычисление следующего адреса строки можно было-бы оформить в виде процедуры и вызывать через CALL ,однако это существенно снизило бы скорость работы. Теперь напишем вторую часть процедуры, которая выводит этот-же столбец спрайта, но уже со сдвигом вправо на 1 бит. Входные параметры те-же. Put1 ld a,e rrca ;сдвигаем вправо маску ld c,a ;сохраняем and #7F ;отбрасываем бит, ;кот.вылез слева or (hl) ld (hl),a ld a,c and #80 ;переносим бит на inc l ;знакоместо правее or (hl) ld (hl),a ;повторяем те-же операции ld a,d ;для изображения rrca ld c,a and #80 xor (hl) ld (hl),a ld a,c and #7F dec l xor (hl) ld (hl),a pop de djnz Put1_ jp Exit Put1_ inc h ;Вычисляем адрес ld a,h ;следующей строки and 7 ;в экране. jp nz,Put1 ld a,l add a,#20 ld l,a jr c,Put1 ld a,h sub 8 ld h,a jr Put1 В процедуре Put2 выполняем те-же опера- ции, но только сдвигаем на два бита, и переносим эти-же два бита на знакоместо правее. Однако следует заметить, что в процедуре Put5 мы сдвигаем байт не на 5 битов, а всего лишь на 3, но влево что даст тот-же результат, но будет работать быстрее. В процедуре Put6 на два бита вправо, а в процедуре Put7 на 1. Теперь осталось лишь написать управля- ющую часть процедуры. ;Hа входе процедуры: ;HL-Адрес спрайта ;DE-Координаты на экране (Y,X) ;B-Высота спрайта в пикселах ;C-Длина спрайта в знакоместах PutSpr push bc push hl call ScrPut ex de,hl pop hl pop bc PutSpr0 push bc push de call Line0 pop de inc e pop bc dec c jr nz,PutSpr0 ret ;Вход: DE-Y(0..191),X(0..255) ;Выход:HL-Адрес в экране ; Переключает на нужную процедуру ScrPut call Scr ex de,hl ld bc,PutTable ld h,0 ld l,a add hl,hl add hl,bc ld a,(hl) ;Берем адрес процед. inc hl ld h,(hl) ld l,a ld (Jump0+1),hl ;переключаем ;на вывод этой процедурой ex de,hl ret ;Таблица процедур PutTable dw Put0,Put1,Put2,Put3 dw Put4,Put5,Put6,Put7 ;Вх.:DE-Y(0..191),X(0..255) ;Выход:HL-Адрес в экране ; A-(0..7) на сколько нужно сдвинуть ; спрайт вправо. Scr ld a,e and 7 push af srl e srl e srl e ld a,d rrca rrca rrca and #18 ld h,a ld a,d and 7 add a,h ld b,a ld a,#40 add a,b ld h,a ld a,d rla rla and #E0 or e ld l,a pop af ret ;Рисует один вертикальный столбец ;HL-адрес спрайта ;DE-адрес вывода в экране ;B-высота спрайта Line0 push bc ld c,(hl) inc hl ld b,(hl) inc hl ld (Line1+1),hl ld h,b ld l,c ex de,hl pop bc ld (Exit0+1),sp Line1 ld sp,0 Jump0 jp 0 ;Переход на процедуру Exit ld hl,0 add hl,sp dec hl dec hl ;адрес следующего ;столбца спрайта Exit0 ld sp,0 ;восстановить стек ret О формате самих спрайтов вы можете узнать внимательно изучив структуру процедуры. Данные спрайта располагаются в следу- ющей последовательности: Сверху вниз, слева направо чередуются байты маски и спрайта, причем первый байт - маска. ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ Организация прерываний ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ Внимательно изучив процедуры, некоторые из вас вероятно заметят, что процедура Line0 написана очень заворочено, ведь ее можно упростить в несколько раз: Line0 Line1 ld sp,0 dec sp dec sp pop de Jump0 jp 0 Hа самом деле такая навороченость нужна для правильной работы прерываний, ведь при вызове прерывания часть спрайта затирается адресом возврата и чтобы восстановить спрайт, в DE нужно иметь испорченые два байта спрайта, которые мы по окончанию обработки возвращаем на место. Однако т.к. мы сначала устанав- ливаем стек, а только потом читаем DE, то при приходе прерывания в этот момент в DE не окажется испорченых данных. Теперь привожу процедуру обработки прерываний: Inter ld (SP__+1),sp ld sp,Stack ;Временный стек push af,bc,de,hl,ix,iy exx ex af,af' push af,bc,de,hl ;Ваш обработчик pop hl,de,bc,af ex af,af' exx pop iy,ix ;Сдесь мы узнаем находится ли ;сейчас стек на спрайте SP__ ld hl,0 ld de,#6000 ;Hижняя граница ;спрайтов sbc hl,de jr c,Normal ld hl,(SP__+1) ld e,(hl) inc hl ld d,(hl) ld (Jump+1),de pop hl,de,bc,af ld sp,(SP__+1) inc sp inc sp push de ei Jump jp 0 ;Если стек ниже спрайтов Normal pop hl,de,bc,af ld sp,(SP__+1) ei ret Следует также отметить, что спрайты должны располагаться выше границы спрайтов, а стек ниже этой границы. Вы конечно-же можете установить свое значение границы. В приложении вы найдете все исходники. === Конец цитаты === С уважением, Alexander 18 сентября 2000 года




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

Похожие статьи:
Головоломки - Букеты, Раставьте знаки, Косвенные данные.
От авторов - об игре "Any Tank"...
Оттяг - Terminator 3.5 или Ссаный день 2.
Реклама - Реклама и объявления ...
Кaк дoбрaтьcя дo пaти Дзeржинcкa - Party бyдeт прoвoдитьcя в пomeщeнии Дзeржинcкoгo Пeдaгoгичecкoгo Кoллeджa (aктoвый зaл, 250 кв. m.)...

В этот день...   8 мая