The following warnings occurred:
Warning [2] Undefined array key 0 - Line: 1677 - File: showthread.php PHP 8.2.31 (Linux)
File Line Function
/inc/class_error.php 157 errorHandler->error
/showthread.php 1677 errorHandler->error_callback
/showthread.php 916 buildtree




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)