Printed Amstrad Addict magazine announced, check it out here!

Main Menu

Hardware scrolling: problem with sprites/tiles

Started by AugustoRuiz, 10:57, 12 March 09

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.


Hello all!
I'm having a bit of a problem with the discontinuity that appears when you hardware scroll the CPC screen. I'm developing a CPC side scroller shoot'em up with some guys at RetroWorks (which is formed by some former CEZ GS members).
I can draw sprites and get/restore backgrounds while scrolling the screen, but when I'm painting the sprite at the last character I'm having problems. I think that my routine to calculate the memory address is not working correctly for that case.

I'm using two tables to precalculate memory addresses of the leftmost and rightmost pixels for each Y coordinate. The routine to precalculate them is working correctly. The rightmost pixel table is used to know where should I paint a new column of pixels every time I do a scroll, and it's working ok (mainly because everything is painted correctly when I scroll the screen for a long, long time). The leftmost pixel table is used to calculate the memory address of a sprite. I perform a lookup based on the Y coordinate, add to that the X coordinate (taking into account when I have passed from 7FF to 800 to correct the value).

This is what I'm using:

; H -> X coord
; L -> Y coord
  LD C,H      ;; store H coordinate for later

  ld H,0      ;; H used to hold X coordinate, need to zero this out
         ;; because we want HL to contain the Y coordinate

  ADD HL, HL      ;; each element of the look-up table is 2 bytes
                   ;; convert y position to a byte offset from the start
                   ;; of the look up table
  ADD HL, DE      ;; add start of lookup table to get address of element
                   ;; in lookup table

  LD A, (HL)
  LD H,(HL)
  LD L, A      ;; read element from lookup table (memory address of the start
               ;; of the line defined by the y coordinate)

  ;; hl has the start of current line. Let's check the 4th byte:
  LD A, H
  AND 7                   ;; A holds the 0,1,2 bits before adding X coord.
  LD D, A                ;; D holds the 0,1,2 bits before adding X coord.

  LD B, 0
  ADD HL, BC             ;; add on X byte coordinate

  LD A, H
  AND 7                  ;; A holds the 0,1,2 bits after adding X coord.

  XOR D                   ;; If we have passed a discontinuity, XOR will return 7 (111b)
  CP 7

  LD A, H 
  SUB 8              ;; Go back 0x0800 bytes.
  LD H, A

  ;; HL = final memory address

The thing is that when I have to paint a sprite which part of it is before the end of the scanline and part of it is past the end of the scanline, it's not being painted correctly.

Any hints?


I had similar problem as i am working on a similar project.To solve it i removed table and i computed like this :

for 11 first bits of HL : y/8 * line_width + x/pixel_per_byte
for bits 11,12,13 : y mod 8
for bits 14,15 : block (00/40/80/C0)

When you increment, it's like you have cycle on first 11 bits (if you understand french this is a topic that gave me a valuable help )

For tiles , solution is simplier than using table because tiles are 8 pixels high.
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !


fano, could you please elaborate a bit more on this? I mean, explain a little more about:
what do you mean by block for bits 14/15? Something like this?

address 00 = bits 00
address 40 = bits 01
address 80 = bits 10
address C0 = bits 11

line_width... in bytes or in pixels? Or in Horizontal Chars (Register 01 of CRTC)
I need the rightmost table, but for sprites, the leftmost table, if such a calculus works, I can ignore it, and will save some cycles updating it for each scroll increment...


For block this is fine.For line_width, i mean in bytes.

It could be optimized more but this is how i compute address for projectiles (1*1 pixel mode 0) in my project (uses SSCR so don't care about SCROLL_pixOffset)

;get xpos in (PROJ_xPos) and convert in byte/pixel offset
    ld A,(SCROLL_pixOffset)
    add A,(HL)        ;sub pix offset to x
    or A             ;clean carry
    rra              ;divide per 2, parity bit in carry
    ld E,A          ;store in E
    ld A,%01010101
    jr c,not_pair_pixel   
    rla            ;shift on left (carry is supposed to be NULL)
    ex AF,AF'        ;keep pixel in AF'

    xor A
    ld D,A

    push DE            ;save DE

;get ypos in (PROJ_yPos) and convert to line address

    inc L         ;decimal of PROJ_xPos   +2
    inc L         ;PROJ_yPos        +3
    ld A,(HL)   
    ld IYL,A      ;temp store 2nop
;compute char address
    and #F8
    ld L,A    ;already *8
    ld H,0
;adr=char * 96
    add HL,HL ;*2=16
    push HL   ;save on stack
    add HL,HL ;*2=32
    pop DE      ;get *16 in DE
    add HL,DE ;+16=48
    add HL,HL ;*2=96

    pop DE
    add HL,DE    ;add to x offset

    ld DE,(SCROLL_scrOffset)
    add HL,DE    ;so we get offset from real screen

    ld A,IYL   

    and 7        ;get line on char and fix wrapping bug
    add A
    add A
    add A

    res 3,H
    add H

    ;and #3F    ;add if screen_adr is not #C0
    or  screen_adr    ;start of the screen high
    ld H,A
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !


As I am using overscan (102 bytes of width) I'm going to precalculate the y/8 * line_width part. Shouldn't be a big table, but I'll save some precious time ;)

Thank you very much!


I don't think it is incompatible w/ tables but that was more simple w/out
I think i'll use them when optimising ( plz save our little nops :D).
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !


fano... x means World coordinate x, not screen coordinate x, isn't it?


hum... i'd say local coordinates in opposition w/ global coordinates


relative coordinates to camera pos like this : pos.x = obj.x - cam.x

but what is the interest to use global/world coords in a shmup ?

I add scroll offset (CRTC r12/13 offset *2) to be more clear :

for 11 first bits of HL (cyclic) : (y/8 * line_width + x/pixel_per_byte) + (CRTC_offset *2)
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !


Finally, I managed to make it!! Thank you very much, fano :)


this is great, good luck for your project  ;)
"NOP" is the perfect program : short , fast and (known) bug free

Follow Easter Egg products on Facebook !

Powered by SMFPacks Menu Editor Mod