Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Fourspriter: Sprite Engine from the Mojon Twins
#1
As I promissed, here I am with an adaptation for the Mojon Twins "Fourspriter". Well, in fact I promissed just the opposite (skip this one and post the other sprite routine I'm working in), but I think this one is more suited to a basic enviroment and the other one is just great for a crap game (see my game Colour Clash of the Titans in the CSSCGC 2010 thread within the WoS games forum) but not so good if you plan to do a polished game.

The engine itself comes in assembler, and all you have to do is POKE the right adresses to configure and move your sprites (up to 4). All I have done is adding 3 subroutines to make easier the poking part, and 4 labes so you can call the different subroutines of the engine via gosub.

Here goes the code you have to include in your library folder (I called it fourspriter.bas):

Code:
SUB fsprite (n as uByte, a as uByte, b as uByte, c as uByte, d as uByte)  'Initialite Sprite: n (sprite number 0-3);a,b,c,d (UDG number 0-20,99 means the sprite won't be printed)
POKE @fourspriter+48*n,a
POKE @fourspriter+1+48*n,b
POKE @fourspriter+2+48*n,c
POKE @fourspriter+3+48*n,d
END sub

SUB fspritecoord (n as uByte, x as uByte, y as uByte)   'Set sprite coords: n (sprite number);x,y (vertical,horizontal coords)
POKE @fourspriter+4+48*n,x
POKE @fourspriter+5+48*n,y
POKE @fourspriter+6+48*n,x
POKE @fourspriter+7+48*n,y
END SUB

SUB fspriteattr (n as uByte, attra as uByte, attrb as uByte, attrc as uByte, attrd as uByte) 'Set sprite attrs: n (sprite number);a,b,c,d (UDG attrs)
POKE @fourspriter+40+48*n,attra
POKE @fourspriter+41+48*n,attrb
POKE @fourspriter+42+48*n,attrc
POKE @fourspriter+43+48*n,attrd
END SUB


fourspriter:
ASM

;; 16x16 Sprites moving a character each frame

;; Copyleft 2009 The Mojon Twins.
;; Pergreñado por na_th_an

;; Uses UDGs (it reads the address from the system variables).

;; It moves up to 4 sprites, preserving the backgrounds.



datap:                                ; each block is 40 bytes long.

;; Sprite 1

udgs1:        defb    0, 0, 0, 0        ; Four UDGs of the first sprite.
x_pos1:        defb    0                ; X position in chars.
y_pos1:        defb    0                ; Y position in chars.
cx_pos1:    defb    0                ; Previous X position in chars.
cy_pos1:    defb     0                ; Previous Y position in chars.
buffer1:    defb    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0            ; Gfx buffer.
attrs1:        defb    7, 7, 7, 7        ; Sprite ATTRs
buffatrs1:    defb    0,0,0, 0            ; Attr's buffer

;; Sprite 2

udgs2:        defb    0, 0, 0, 0        ;
x_pos2:        defb    0                ;
y_pos2:        defb    0                ;
cx_pos2:    defb    0                ;
cy_pos2:    defb     0                ;
buffer2:    defb    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0            ;
attrs2:        defb    7, 7, 7, 7        ;
buffatrs2:    defb    0,0,0, 0            ;

;; Sprite 3

udgs3:        defb    0, 0, 0, 0        ;
x_pos3:        defb    0                ;
y_pos3:        defb    0                ;
cx_pos3:    defb    0                ;
cy_pos3:    defb     0                ;
buffer3:    defb    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0            ;
attrs3:        defb    7, 7, 7, 7        ;
buffatrs3:    defb    0,0,0, 0            ;

;; Sprite 4

udgs4:        defb    0, 0, 0, 0        ;
x_pos4:        defb    0                ;
y_pos4:        defb    0                ;
cx_pos4:    defb    0                ;
cy_pos4:    defb     0                ;
buffer4:    defb    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0            ;
attrs4:        defb    7, 7, 7, 7        ;
buffatrs4:    defb    0,0,0, 0            ;

;; General use coordinates

xpos:        defb     0
ypos:        defb     0
cxpos:        defb    0
cypos:        defb     0

;; Sprite control is done writing a certain number
;; in the Sprite's first UDG
;; If the first UDG is 99, it won't be printed

;;
;; Routine to save the background to the buffer
end asm
initsprites:
asm
init_sprites:                        

; pointer = datap
; for (i = 0; i < 4; i ++) {
;    X = *(pointer + 4);                                    // A
;    Y = *(pointer + 5);
;    scr_address = get_scr_address (X, Y);                    // B
;     for (j = 0; j < 8; j ++) {
;       *(pointer + 8 + j) = *scraddress;
;       scraddress += 256;
;    }
;    scr_address = get_scr_address (X+1, Y);                // C
;     for (j = 0; j < 8; j ++) {
;       *(pointer + 16 + j) = *scraddress;
;       scraddress += 256;
;    }
;    scr_address = get_scr_address (X, Y+1);                // D
;     for (j = 0; j < 8; j ++) {
;       *(pointer + 24 + j) = *scraddress;
;       scraddress += 256;
;    }
;    scr_address = get_scr_address (X+1, Y+1);                // E
;     for (j = 0; j < 8; j ++) {
;       *(pointer + 32 + j) = *scraddress;
;       scraddress += 256;
;    }
;    pointer = pointer + 40;
; }

            ld         de, datap        ;

            ld        b,    4            ;
i4chars:    push    bc
            
            ;;
            ld        a,    (de)
            cp        99
            jr        z,    nxt1

            ;; A

            inc        de
            inc        de
            inc        de
            inc        de

            ;
            ld        a,    (de)
            ld        hl,    xpos
            ld        (hl), a
            
            inc     de
            
            ;
            ld        a,    (de)
            ld        hl, ypos
            ld        (hl), a
            
            inc     de
            inc     de
            inc     de
            
            ;; B
            
            ;
            call    copia_char
            
            ; xpos++
            ld        hl, xpos
            inc        (hl)
            
            ;; C
            
            ;
            call     copia_char

            ; xpos --
            ld        hl, xpos
            ld        a, (hl)
            dec        a
            ld        (hl), a
            
            ; ypos ++
            ld        hl, ypos
            inc        (hl)
            
            ;; D
            
            ;
            call     copia_char

            ; xpos++
            ld        hl, xpos
            inc        (hl)
            
            ;; E
            
            ;
            call    copia_char
            

            ;; Now we point to the ATTR buffer,adding 4:
            inc        de
            inc        de
            inc        de
            inc        de
            
            ;;
            
            ; xpos --
            ld        hl, xpos
            ld        a, (hl)
            dec        a
            ld        (hl), a
            
            ; ypos --
            ld        hl, ypos
            ld        a, (hl)
            dec        a
            ld        (hl), a
                    
            ;
            call    get_attr_address
            
            ;
            ld        l,     c
            ld        h,     b
            ld        bc, 31
            ld        a,    (hl)
            ld        (de), a            ; Primer carácter
            inc        hl
            inc        de
            ld        a,     (hl)    
            ld        (de), a            ; Segundo carácter
            add        hl,    bc
            inc        de
            ld        a,    (hl)
            ld        (de), a            ; Tercer carácter
            inc        hl
            inc        de
            ld        a,     (hl)
            ld        (de), a            ; Cuarto carácter
            inc        de                

            ; Fin del bucle
            
nxt1:        pop        bc
            djnz     i4chars
            
            ret
            
copia_char:
            call    get_scr_address    ;
            ld        l,     c
            ld        h,     b            ;
            
            ld        a,    (hl)
            ld        (de), a
            inc        h
            inc        de
            ld        a,    (hl)
            ld        (de), a
            inc        h
            inc        de
            ld        a,    (hl)
            ld        (de), a
            inc        h
            inc        de
            ld        a,    (hl)
            ld        (de), a
            inc        h
            inc        de
            ld        a,    (hl)
            ld        (de), a
            inc        h
            inc        de
            ld        a,    (hl)
            ld        (de), a
            inc        h
            inc        de
            ld        a,    (hl)
            ld        (de), a
            inc        h
            inc        de
            ld        a,    (hl)
            ld        (de), a
            inc        h
            inc        de
            
            ret
            
;; Routine to move the sprites:

end asm
updatesprite:
asm
update_sprites:
    halt
    
    call borra_sprites                ; Erase the sprites
    call init_sprites               ; Save background
    call draw_sprites                ; print sprites
    call update_coordinates            ; update coordinates :)
    
    ret

;; Routine to erase the sprites:
end asm
borrasprites:
asm
borra_sprites:

; pointer = datap
; for (i = 0; i < 4; i ++) {
;     CX = *(pointer + 6)
;     CY = *(pointer + 7)
;    scr_address = get_scr_address (CX, CY);
;    for (j = 0; j < 8; j ++) {
;        *scr_address = *(pointer + 8 + j);
;        scr_address += 256;
;    }
;    scr_address = get_scr_address (CX+1, CY);
;    for (j = 0; j < 8; j ++) {
;        *scr_address = *(pointer + 16 + j);
;        scr_address += 256;
;    }
;    scr_address = get_scr_address (CX, CY+1);
;    for (j = 0; j < 8; j ++) {
;        *scr_address = *(pointer + 24 + j);
;        scr_address += 256;
;    }
;    scr_address = get_scr_address (CX+1, CY+1);
;    for (j = 0; j < 8; j ++) {
;        *scr_address = *(pointer + 32 + j);
;        scr_address += 256;
;    }
;    pointer += 40;
; }

            ld         de, datap        ;
            ld        b,    4            ;
i4chars2:    push    bc
            
            ;;
            ld        a,    (de)
            cp        99
            jr        z,    nxt2

            ;; A

            inc        de
            inc        de
            inc        de
            inc        de
            inc        de
            inc        de
            
            ; Obtenemos xpos = CX
            ld        a,    (de)
            ld        hl,    xpos
            ld        (hl), a
            
            inc     de
            
            ; Obtenemos ypos = CY
            ld        a,    (de)
            ld        hl, ypos
            ld        (hl), a
            
            inc     de
            
            ;; B
            
            ; Pintamos el primer char
            call    borra_char
                        
            ; xpos++
            ld        hl, xpos
            inc        (hl)
            
            ;; C
            
            ; Pintamos el segundo char
            call    borra_char

            ; xpos --
            ld        hl, xpos
            ld        a, (hl)
            dec        a
            ld        (hl), a
            
            ; ypos ++
            ld        hl, ypos
            inc        (hl)
            
            ;; D
            
            ; Pintamos el tercer char
            call     borra_char

            ; xpos++
            ld        hl, xpos
            inc        (hl)
            
            ;; E

            ; Pintamos el cuarto char
            call    borra_char
            
            ;; attr
            inc        de
            inc        de
            inc        de
            inc        de
            
            ;;
            
            ; xpos --
            ld        hl, xpos
            ld        a, (hl)
            dec        a
            ld        (hl), a
            
            ; ypos --
            ld        hl, ypos
            ld        a, (hl)
            dec        a
            ld        (hl), a
                    
            ;
            call    get_attr_address
            
            ;
            call    copyattrs
            
            ;
            
nxt2:        pop        bc
            djnz     i4chars2            
        
            ret

borra_char:                
            call    get_scr_address    ;
            ld        l,     c
            ld        h,     b            ;
            
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            
            ret

            
;; Print sprites routine

;; UDGs are labeled from  0 to 21. The addres of the UDG is:

;; *(23675) + 256 * *(23676) + 8 * N
            
bufchars:    defb    0,0,0, 0        ;
end asm
drawsprites:
asm
draw_sprites:

            ld         de, datap        ;

            ld        b,    4            ;
i4chars3:    push    bc

            ;;
            ld        a,    (de)
            cp        99
            jr        z,    nxt3

            ;; copiar aquí "de" a un buffer

            call    charsabuff
            
            ; Obtenemos xpos
            ld        a,    (de)
            ld        hl,    xpos
            ld        (hl), a
            
            inc     de
            
            ; Obtenemos ypos
            ld        a,    (de)
            ld        hl, ypos
            ld        (hl), a
            
            inc     de
            inc     de
            inc     de
            
            push     de
            
            ;;
            
            ld        hl, bufchars
            call    getde
            
            ;;
            call    docopy

            ; xpos++
            ld        hl, xpos
            inc        (hl)
            
            ; Dirección del gráfico
            
            ld        hl, bufchars
            inc        hl
            call    getde
            
            ; Pintamos el segundo char
            call    docopy
            
            ; xpos--
            ld        hl, xpos
            ld        a, (hl)
            dec        a
            ld        (hl), a
            
            ; ypos ++
            ld        hl, ypos
            inc        (hl)
            
            ; Dirección del gráfico
            
            ld        hl, bufchars
            inc        hl
            inc        hl
            call    getde
        
            ; Pintamos el tercer char
            call    docopy
            
            ; xpos ++
            ld        hl, xpos
            inc        (hl)
            
            ; Dirección del gráfico
            
            ld        hl, bufchars
            inc        hl
            inc        hl
            inc        hl
            call     getde
            
            ; Pintamos el cuarto char
            call    docopy
                            
            pop        de
            
            ; de = de + 32
            ld        bc, 32
            ld        h, d
            ld        l, e
            add        hl, bc
            ld        d, h
            ld        e, l
            
            ;; attr
            
            ; xpos --
            ld        hl, xpos
            ld        a, (hl)
            dec        a
            ld        (hl), a
            
            ; ypos --
            ld        hl, ypos
            ld        a, (hl)
            dec        a
            ld        (hl), a
                    
            ;
            call    get_attr_address
            
            ;
            call    copyattrs
            
            inc        de
            inc        de
            inc        de
            inc        de                ;
            
nxt3:        pop        bc
            djnz     i4chars3
            
            ret

charsabuff: ld        hl,    bufchars
            ld        a, (de)
            ld        (hl), a
            inc        de
            inc        hl
            ld        a, (de)
            ld        (hl), a
            inc        de
            inc        hl
            ld        a, (de)
            ld        (hl), a
            inc        de
            inc        hl
            ld        a, (de)
            ld        (hl), a
            inc        de
            inc        hl
            ret
                        
copyattrs:    ld        l,     c
            ld        h,     b
            ld        bc, 31
            ld        a,    (de)
            ld        (hl), a            ; Primer carácter
            inc        hl
            inc        de                
            ld        a,     (de)    
            ld        (hl), a            ; Segundo carácter
            add        hl,    bc
            inc        de
            ld        a,    (de)
            ld        (hl), a            ; Tercer carácter
            inc        hl
            inc        de
            ld        a,     (de)
            ld        (hl), a            ; Cuarto carácter
            inc        de                ; Ahora de apunta a datap+48, o sea, al siguiente sprite.
            ret
end asm
updatecoordinates:
asm
update_coordinates:
            ld         de, datap        ; Apuntamos a la zona de datos
            ld        hl, datap        ; idem

            ld        b,    4            ; 4 iteraciones
i4chars4:    push    bc

            ;; Para cada sprite hay que hacer:
            ;; *(datap + 6) = *(datap + 4)
            ;; *(datap + 7) = *(datap + 5)
            
            inc        de
            inc        de
            inc        de
            inc        de
            ld        a, (de)            ; a = X
            inc        hl
            inc        hl
            inc     hl
            inc        hl
            inc        hl
            inc        hl
            ld        (hl), a            ; CX = a
            
            inc     de
            ld        a, (de)            ; a = Y
            inc     hl
            ld        (hl), a            ; CY = a

            inc        hl
            
            ;; hl = hl + 40
            ld        bc, 40
            add        hl, bc
            
            ;; de = hl
            ld        d, h
            ld        e, l
            
            pop        bc
            djnz     i4chars4
            ret
            
;; Esta función calcula la posición en memoria del UDG apuntado por
;; el número que está en la dirección hl.
            
getde:        ld        a, (hl)
            ld        d, a
            ld        hl, 23676
            ld        a, (hl)
            ld        e, a
            ld        hl, 23675
            ld        a, (hl)
            ld        l, a
            ld        a, e
            ld        h, a
            ;;        HL = *(23675) + 256 * *(23676)
            ld        a, d
            rlca
            rlca
            rlca    ; a = N * 8
            ld        d, 0
            ld        e, a
            add        hl, de
            ld        d, h
            ld        e, l
            ret

docopy:        
            call    get_scr_address    ; Dirección (xpos, ypos) en BC
            ld        l,     c
            ld        h,     b            ; Dirección (xpos, ypos) en HL            
            
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            ld        a,    (de)
            ld        (hl), a
            inc        h
            inc        de
            
            ret
            
;; Esta función devuelve en bc la dirección de memoria
;; de la posición (xpos, ypos) en carácteres. Extraído de código
;; por BloodBaz.

get_scr_address:
            push     de
            ld         a,    (xpos)
            and        31
            ld        c,    a
            ld        a,    (ypos)
            ld        d,    a
            and        24
            add        a,    64
            ld        b,     a
            ld        a,    d
            and        7
            rrca
            rrca
            rrca
            or        c
            ld        c,     a
            pop        de
            ret
                    
;; Esta función devuelve en bc la dirección de memoria
;; de la posición (xpos, ypos) dentro del archivo de atributos.
;; Adaptado de código por Jonathan Cauldwell.

;; 010110YY YYYXXXXX

get_attr_address:
            
            ld        a,     (ypos)        ; Cogemos y
            rrca
            rrca
            rrca                    ; La multiplicamos por 32
            ld        c,    a            ; nos lo guardamos en c
            and        3                ; ponemos una mascarita 00000011
            add        a,    88            ; 88 * 256 = 22528, aquí empieza el tema
            ld        b,    a            ; Hecho el bite superior.
            ld        a,    c            ; Nos volvemos a traer y * 32
            and        224                ; Mascarita 11100000
            ld        c,    a            ; Lo volvemos a poner en c
            ld        a,    (xpos)        ; Cogemos x
            add        a,     c            ; Le sumamos lo que teníamos antes.
            ld        c,    a            ; Listo. Ya tenemos en BC la dirección.
            
            ret
            
spare:        defb    85,85,85,85,85,85,85, 85
end asm

The subroutines are the following:

1) Define your sprites:

fsprite (n,a,b,c,d) ; where n is the sprite number (0 to 3) and a-d are the UDGs number that compose the sprite (0-21)

2) Set the atributes for each of the sprite's UDG:

fspriteattr (n,a,b,c,d) ; n=sprite number ; a-d=attr of each UDG

3) Set the initial coords for your spries:
fspritecoord (n,y,x) ; n= sprite number ; y=vertical coord ; x=horizontal coord

The labels to be called via gosub are:

borrasprites ; this will erase the sprites, restoring the background.

initsprites ; this will select wether a sprite will be printed or not. If you don't want a sprite to be printed, you have to poke 99 into the first value of the sprite udg (i.e. fsprite (1,99,0,0,0) won't print sprite 1)

drawsprites ; this will draw the sprites on the screen

updatecoordinates ; this will update the current coordinates of each sprite, while storing the old ones so you can restore the background.
Reply


Messages In This Thread

Forum Jump:


Users browsing this thread: 1 Guest(s)