Рисуем спрайт двух персонажей в сборке Z80

Следуя « Первые шаги в языке ассемблера Z80», я пытаюсь переместить спрайт с двумя старшими символами на ассемблере.

                  ORG 30000         ; Origin

LASTK       EQU 23560         ; last key press (system variable)

PRINT       EQU 8252          ; This means the label PRINT equates to 8252.


            XOR a             ; quick way to load accumulator with zero.
            LD A, 2           ; set print channel to screen

            CALL 5633         ; Open channel two (ie, write to screen)
            LD HL, GFX        ; set up UDGs
            LD (23675), HL    ; where the UDG characters are stored.
            CALL 3503         ; clear the screen. CLS


MAINLP      CALL PRTPLAY      ; print player sprite
            
            HALT              ; Slow it down three times
            HALT
            HALT

            LD BC, $FEFE      ; load port address into BC, scan for right ("X")
            IN A, (C)         ; load port data into A
            AND %0000100      ; looking for X
            JR Z, GORIGHT     ; if Z is press, go right

            JR MAINLP         ; loop back to continue scanning


GORIGHT     LD A, (PLAYER+2)  ; if player is at right edge, don't continue
            CP 31
            JR Z, MAINLP      ; Jump Relative Zero
            CALL UNDRAW
            LD A, (PLAYER+2)  ; get player's X coordinate
            INC A             ; add 1
            LD (PLAYER+2), A
            JR MAINLP


PRTPLAY     LD DE, PLAYER           ; print player graphic
            LD BC, EOPLAYR-PLAYER
            CALL PRINT
            RET


UNDRAW      LD A, " "            ; change graphic to empty space
            LD (PLAYER+3), A     ; store it
            CALL PRTPLAY         ; undraw graphic from screen
            LD A, 144            ; change graphic back to normal
            LD (PLAYER+3), A     ; store it


            RET ; return to basic!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

            ; Player x, y 
PLAYER      DEFB 22, 12, 15, 144 ; print at Y, X, char 144 UDG (A)
            DEFB 22, 13, 15, 145 ; print at Y+1, X, char 145 UDG (B)
            EOPLAYR EQU $

            ; Graphics UDG Character
GFX         DEFB 6, 62, 124, 52, 62, 60, 24, 60
            DEFB 126, 126, 247, 251, 60, 118, 110, 119
            

Спрайт Manic Miner нарисован нормально. Однако, когда «x» нажимается для перехода вправо, перемещается только верхняя половина. Это означает, что либо отрисовка не работает, либо нижний символ не увеличивается. Я очень новичок в ассемблере и пытался понять, где я ошибся. Я подозреваю, что это то место, где DEFB явно указано быть на 144 и 145, но отрисовка только на 144. Однако это должно быть покрыто LD BC, EOPLAYR-PLAYER. Смущенный.

1 ответ

Итак, вы попытались самостоятельно расширить пример из книги... отлично, так вы больше всего научитесь.

Ваше подозрение отчасти верно, т.PRTPLAYпечатает все байты.

Таким образом, он печатает первый управляющий код AT, помещающий курсор в (x,12), затем он печатает символ UDG «A» 144, затем другой управляющий код AT, помещающий курсор в (x, 13), и символ UDG «B» 145.

The UNDRAWизменяет только верхний символ 144 на пробел, поэтому он печатает пробел поверх спрайта и снова печатает UDG «B» поверх нижнего, оставляя спрайт видимым.

Чтобы исправить это (таким же обыденным способом, как работает оригинал):

      UNDRAW      LD A, " "            ; change graphic to empty space
            LD (PLAYER+3), A     ; replace UDG A 144
            LD (PLAYER+7), A     ; replace UDG B 145
            CALL PRTPLAY         ; undraw graphic from screen
            LD A, 144            ; change graphic back to normal
            LD (PLAYER+3), A     ; store it
            LD A, 145
            LD (PLAYER+7), A
            RET                  ; return to caller

И аналогичным образом подпрограмма исправления координаты X управляющего кода AT теперь должна исправлять два места, поскольку в вашей строке печати есть два управляющих кода AT:

      GORIGHT     LD A, (PLAYER+2)  ; if player is at right edge, don't continue
            CP 31
            JR Z, MAINLP      ; Jump Relative Zero
            CALL UNDRAW
            LD A, (PLAYER+2)  ; get player's X coordinate
            INC A             ; add 1
            LD (PLAYER+2), A  ; update X position of upper char 144
            LD (PLAYER+6), A  ; update X position of lower char 145
            JR MAINLP

Вы можете захотеть пройти этот вид учебника, вызывая ПЗУ, используя подпрограммы BASIC для графики как можно быстрее, и искать более продвинутые учебники, рисующие непосредственно в видео ОЗУ без ПЗУ, так как этот пример очень медленный с точки зрения производительности (начало бы задыхается, если вы попытаетесь анимировать еще несколько спрайтов, подобных этому, в то время как с оптимизированной сборкой вы можете перемещать около 20+ спрайтов 8x16 за один кадр), и становится очень громоздким, если вы хотите делать более крупные спрайты, и внезапно вам приходится исправлять многие элементы управления AT кодов и много gfx-символов (144145), плюс это становится дополнительной головной болью, когда нужно отсечение по краям спрайта (а печатать нужно только часть символов, а не все).

Я имею в виду, что вы все равно должны попытаться понять, что и как делает учебник, в целом это достойный учебник, и вы можете применить свои навыки сборки Z80 на нем, но с точки зрения демо-сценера, делающего демонстрации ZX в течение многих лет (и нацеленного на высокопроизводительные полноэкранные трюки gfx) - этот код хорош только для того, чтобы научиться не писать код ZX. :)

Также может быть несколько проще следовать этому руководству, если вы знакомы с ZX BASIC и тем, какPRINTработает на бейсике. Если вы совершенно не знакомы с ZX BASIC и только изучаете сборку Z80, то такие процедуры печати, вероятно, еще более запутаны, чем запись кода непосредственно в видеопамять без процедур ПЗУ.

Другие вопросы по тегам