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:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
FourSpriter MK III
#1
Okay, reduced the flicker quite a bit more.

Sadly, because it's erase all four sprites and then redraws all sprites, different sprites start to flicker at different points.

If using 4 sprites:
Sprite 0 starts to flicker at above (pixel) line 10
And every other sprite at about 8 lines further down, per sprite.

If using 3 sprites
Sprites 0 is stable
Sprite 1 flickers above row 6
Sprite 3 starts to flicker at above line 16.

If using 2 sprites
Everything is stable.

I assume this is why the mojon's demonstrations only use 2 sprites...

I can't see any more speed optimizations (and right now it probably completes a redraw cycle in less than half the time of the original). There are probably some left, and no doubt Boriel will spot them immediately because he's a genius. However, right now I'm looking at changing /how/ it works. Things like not redrawing a sprite if it hasn't moved, and rather than erase all sprites and then draw all sprites, perhaps go for an erase-buffer-draw routine that does it on a per-sprite basis; limiting the time in which flicker can hit to areas of the screen.

The only alternative to that is to use a back-buffer screen; and that's a LOT of memory.

So right now, it's perfectly useable, if you think about where your sprites are going to go on the screen. The more sprites you have, the more careful you have to be - and keep the later numbered sprites away from the top of the screen!

So, here's how it stands right now (with a tweaked version of Apenao's demo program):

Code:
#DEFINE BLACK 0 #DEFINE BLUE 1 #DEFINE RED 2 #DEFINE MAGENTA 3 #DEFINE GREEN 4 #DEFINE CYAN 5 #DEFINE YELLOW 6 #DEFINE WHITE 7 #DEFINE TRANSPARENT 8 #DEFINE CONTRAST 9 #DEFINE TRUE 1 #DEFINE FALSE 0 SUB fspInitialize (n as uByte, udgA as uByte, udgB as uByte, udgC as uByte, udgD as uByte,x as uByte,y as uByte) 'Initialize Sprite: n (sprite number 0-3);a,b,c,d (UDG number 0-20,99 means the sprite won't be printed) #ifndef FINAL_CODE IF n>3 OR (udgA>20 AND udgA<>99) or udgB>20 or udgC>20 or udgD>20 then Print "Out Of Bounds Call in ";"fspInitialize" : stop : END IF : REM Bounds checking - so a bad function call doesn't poke all over memory. #endif DIM targetAddr as uInteger targetAddr=@fspDataStart+(48*n) fspErase() POKE targetAddr,udgA targetAddr=targetAddr+1 POKE targetAddr,udgB targetAddr=targetAddr+1 POKE targetAddr,udgC targetAddr=targetAddr+1 POKE targetAddr,udgD targetAddr=targetAddr+1 POKE targetAddr,x targetAddr=targetAddr+1 POKE targetAddr,y targetAddr=targetAddr+1 POKE targetAddr,x targetAddr=targetAddr+1 POKE targetAddr,y fspBufferAndDraw() RETURN fspDataStart: REM This Section contains Fourspriter data and code that is called by other routines. ASM ;; 16x16 Sprites moving a character each frame ;; Copyleft 2009 The Mojon Twins. ;; Updated Copyleft 2010 Paul Fisher ;; Uses UDGs (it reads the address from the system variables). ;; It moves up to 4 sprites, preserving the backgrounds. ;; 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 ; Note that the sprites are initialized to disabled. fspDataStartAsm: ; each block is 48 bytes long. [This comment originally said 40 bytes, and it's clearly 48] ;; Sprite 1 udgs1: defb 99,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 ; Background Gfx buffer. attrs1: defb 6,7,7,7 ; Sprite ATTRs buffatrs1: defb 0,0,0,0 ; Background Attr's buffer ;; Sprite 2 udgs2: defb 99,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 99,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 99,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 fspCollisionDetect: defb 0,0,0 ; Sprite 0 with 1,2,3 defb 0,0 ; Sprite 1 with 2,3 defb 0 ; sprite 2 with 3 fspCopyToScreen: call get_scr_address ; Returns (xpos, ypos) in 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 fspCopyFromScreen: call get_scr_address 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 ; This function returns the address into HL of the screen address ; b,c in character grid notation. ; Original code was extracted by BloodBaz get_scr_address: push de ld a,b ; b=x and 31 ld l,a ld a,c ; c=y ld d,a and 24 add a,64 ld h,a ld a,d and 7 rrca rrca rrca or l ld l,a pop de ret ;; This function returns the memory address of the Character Position ;; b,c in the attribute screen memory. ;; Adapted from code by Jonathan Cauldwell. get_attr_address: ld a,c ;ypos rrca rrca rrca ; Multiply by 32 ld l,a ; Pass to L and 3 ; Mask with 00000011 add a,88 ; 88 * 256 = 22528 - start of attributes. ld h,a ; Put it in the High Byte ld a,l ; We get y value *32 and 224 ; Mask with 11100000 ld l,a ; Put it in L ld a,b ; xpos add a,l ; Add it to the Low byte ld l,a ; Put it back in L, and we're done. HL=Address. ret ;; Routine to save the background to the buffer fspEraseAsm: ld hl, fspDataStartAsm EXX ld b, 4 i4chars2: EXX ;; ld a, (hl) cp 99 jr z, nxt2 ;; A LD BC,6 ;EX DE,HL ; HL now points at the start sprite data instead ADD HL,BC ; HL moved on to point to old x-y positions. LD b,(HL) ; b=x INC HL LD c,(HL) ;c=y INC HL EX DE,HL ; Now it's DE that points into the data buffer. ; Draw first background character call fspCopyToScreen ;; B ; xpos++ inc b ; Draw second background Character call fspCopyToScreen ;; C ; xpos -- dec b ; ypos ++ inc c ; draw Third background Character call fspCopyToScreen ;; D ; xpos++ inc b ; Draw Fourth background Character call fspCopyToScreen ;; move to attr inc de inc de inc de inc de ;Set our position to top left corner again ; xpos -- dec b ; ypos -- dec c call get_attr_address EX DE,HL ;copyattrs ld bc, 32 ;First LDI ;Second LDI ; DE=DE+BC EX DE,HL add hl,bc EX DE,HL ;Third LDI ;Fourth LDI nxt2: EXX djnz i4chars2 ret fspBufferAndDrawAsm: ld hl, fspDataStartAsm EXX ld b, 4 i4chars: ;push bc EXX ;Active Sprite? ld a, (hl) cp 99 jr z, nxt1 ;; A LD BC,4 ADD HL,BC ; move past the udg part ;xpos ld b,(hl) inc hl ;ypos ld c,(hl) inc hl inc hl ; move past the old co-ordinates inc hl EX de,hl call fspCopyFromScreen ;; B ; xpos++ ;ld hl, xpos ;inc (hl) inc b call fspCopyFromScreen ;; C ; xpos -- ;ld hl, xpos ;dec (hl) dec b ; ypos ++ ;ld hl, ypos ;inc (hl) inc c call fspCopyFromScreen ;; D ; xpos++ ;ld hl, xpos ;inc (hl) inc b call fspCopyFromScreen ;; Now we point to the ATTR buffer,adding 4: inc de inc de inc de inc de ;Put ourselves back at the top left corner. ; xpos -- dec b ; ypos -- dec c call get_attr_address ld bc, 32 ;First Character LDI ; bc was loaded with 32 instead of 31 to account for the BC-- this instruction has. ;Second Character LDI add hl, bc ; we can get away with this because BC++ as well as hl-- ;Third Character LDI ;Fourth Character LDI EX DE,HL ; back to an HL pointer. nxt1: EXX djnz i4chars ; Go straight into Painting new sprites for speed. ;; Print sprites routine ;; UDGs are labeled from 0 to 21. The addres of the UDG is: ;; *(23675) + 256 * *(23676) + 8 * N fspDrawAsm: ld hl, fspDataStartAsm ; EXX ld b, 4 ; i4chars3: ;push bc EXX ld a, (hl) cp 99 jr z, nxt3 ;; Copy pointer "HL" to alt reg push HL exx pop HL exx ld bc,4 add hl,bc ; Get xpos LD b,(hl) ;x inc hl ; Get ypos ld c,(hl) ;y inc hl push HL ; de Save pointer. EXX LD A,(HL) INC HL EXX call fspGetUdgAddr ;Draw the first character call fspCopyToScreen ; xpos++ inc b ; Address of the graphics EXX LD A,(HL) INC HL EXX call fspGetUdgAddr ; Draw the second Character call fspCopyToScreen ; xpos-- dec b ; ypos ++ inc c ; Address of Graphics EXX LD A,(HL) INC HL EXX call fspGetUdgAddr ; Draw the third character call fspCopyToScreen ; xpos ++ inc b ; Address of next Graphic EXX LD A,(HL) INC HL EXX call fspGetUdgAddr ; Draw the fourth Character call fspCopyToScreen pop hl ; Recover hl to point at the start of the pixel buffer ; hl = hl + 32 ld a,l add a,34 ld l,a jp nc, fspNoIncH inc h ; hl now points to the attr data. fspNoIncH: EX DE,HL ;Reset position to top left. ; xpos -- dec b ; ypos -- dec c ;; attr call get_attr_address EX DE,HL ;copyattrs ld bc, 32 ;First LDI ;Second LDI ; DE=DE+BC EX DE,HL add hl,bc EX DE,HL ;Third LDI ;Fourth LDI LD BC,4 ADD HL,BC ; Move pointer to start of next block nxt3: EXX djnz i4chars3 ret fspGetUdgAddr: ; finds the address of the UDG # in A ld HL,(23675) ;HL points to the UDG space rlca rlca rlca ; a = N * 8 ld d, 0 ld e, a add hl, de EX DE,HL ret fspUpdateAsm: ; This name will be used from ASM ; For each Sprite: ;; *(data + 6) = *(data + 4) ;; *(data + 7) = *(data + 5) ld hl, fspDataStartAsm+4 ; Points to sprite 1 ld de, fspDataStartAsm+6 ldi ldi ld hl, fspDataStartAsm+4+48 ; Points to sprite 2 ld de, fspDataStartAsm+6+48 ldi ldi ld hl, fspDataStartAsm+4+48+48 ; Points to sprite 3 ld de, fspDataStartAsm+6+48+48 ldi ldi ld hl, fspDataStartAsm+4+48+48+48 ; Points to sprite 4 ld de, fspDataStartAsm+6+48+48+48 ldi ldi ret END ASM END SUB SUB fspDisable (n as UByte) #ifndef FINAL_CODE IF n>3 then Print "Out Of Bounds Call in ";"fspDisable" : stop: END IF #endif fspErase() POKE @fspDataStart+48*n,99 end SUB SUB fspCoord (n as uByte, x as uByte, y as uByte) 'Set sprite coords: n (sprite number);x,y (vertical,horizontal coords) #ifndef FINAL_CODE IF n>3 then Print "Out Of Bounds Call in ";"fspCoord" : stop: END IF #endif DIM targetAddr as uInteger targetAddr=@fspDataStart+4+48*n POKE targetAddr,x targetAddr=targetAddr+1 POKE targetAddr,y rem targetAddr=targetAddr+1 rem POKE targetAddr,x rem targetAddr=targetAddr+1 rem POKE targetAddr,y END SUB SUB fspAttrs (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) #ifndef FINAL_CODE IF n>3 then Print "Out Of Bounds Call in ";"fspAttrs" : stop: END IF #endif DIM targetAddr as uInteger targetAddr=@fspDataStart+40+48*n POKE targetAddr,attra targetAddr=targetAddr+1 POKE targetAddr,attrb targetAddr=targetAddr+1 POKE targetAddr,attrc targetAddr=targetAddr+1 POKE targetAddr,attrd END SUB FUNCTION fspAttrByte(fspInk as uByte,fspPaper as uByte,fspBright as uByte, fspFlash as uByte) as uByte #ifndef FINAL_CODE if fspInk > 7 OR fspPaper > 7 OR fspBright > 1 or fspFlash >1 then Print "Out Of Bounds Call in ";"fspAttrByte" : stop: END IF #endif return (fspFlash shl 7) + (fspBright shl 6) + (fspPaper shl 3) + fspInk END FUNCTION SUB fspAttr(n as uByte,fspInk as uByte,fspPaper as uByte,fspBright as uByte, fspFlash as uByte) #ifndef FINAL_CODE if fspInk > 7 OR fspPaper > 7 OR fspBright > 1 or fspFlash >1 then Print "Out Of Bounds Call in ";"fspAttr" : stop: END IF #endif DIM attrByte as uByte attrByte=fspAttrByte(fspInk,fspPaper,fspBright,fspFlash) fspAttrs(n,attrByte,attrByte,attrByte,attrByte) END SUB SUB FASTCALL fspErase() asm call fspEraseAsm end asm END SUB SUB FASTCALL fspBufferAndDraw() asm call fspBufferAndDrawAsm end asm END SUB SUB FASTCALL fspUpdate() asm call fspUpdateAsm END ASM END SUB SUB fspRedraw() asm halt ;REM Erase the sprites call fspEraseAsm ;REM Save background and ;REM print sprites call fspBufferAndDrawAsm ;REM update coordinates call fspUpdateAsm end asm END SUB REM below this is Apenao's Demo Program: #include <sinclair.bas> #include <memcopy.bas> #include <keys.bas> 100 DIM gentle (0 to 3,0 to 7) AS uByte => { { 15, 15, 15, 15, 15, 15, 13, 15} , _ { 240, 144, 208, 208, 240, 240, 176, 240} , _ { 15, 14, 63, 0, 0, 12, 26, 30} , _ { 176, 112, 252, 0, 0, 48, 104, 120}} 110 POKE Uinteger 23675, @gentle(0,0) CLS for n = 0 to 15 print paper (n mod 7); ink ((n+3) mod 8); "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456" next n let cx=1:let cy=1: let cmx=1:let cmy=1 let dx=7:let dy=5: let dmx=1:let dmy=-1 let tx=10:let ty=7: let tmx=-1:let tmy=1 LET gx=15:LET gy=11 fspInitialize (0,0,1,2,3,gx,gy) : REM (sprite number, udgA, udgB,udgC,udgD, initial X co-ordinate, initial y-coordinate) fspInitialize (1,0,1,2,3,dx,dy) fspInitialize (2,0,1,2,3,tx,ty) fspInitialize (3,0,1,2,3,cx,cy) fspAttr(0,WHITE,MAGENTA,FALSE,FALSE) : REM (sprite number, ink, paper, bright, flash) fspAttr(1,YELLOW,BLACK,FALSE,FALSE) fspAttr(2,GREEN,BLUE,TRUE,FALSE) fspAttr(3,RED,WHITE,FALSE,FALSE) DO pause 2 IF MULTIKEYS(KEYO) and gx>0 THEN LET gx=gx-1: END IF IF MULTIKEYS(KEYP) and gx<30 THEN LET gx=gx+1:END IF IF MULTIKEYS(KEYQ) and gy>0 THEN LET gy=gy-1 :END IF IF MULTIKEYS(KEYA) and gy<22 THEN LET gy=gy+1: END IF let dx=dx+dmx:if dx=1 or dx=30 then let dmx=-dmx : END IF let dy=dy+dmy:if dy=0 or dy=22 then let dmy=-dmy: END IF let tx=tx+tmx:if tx=0 or tx=30 then let tmx=-tmx: END IF let ty=ty+tmy:if ty=0 or ty=22 then let tmy=-tmy: END IF let cx=cx+cmx:if cx=0 or cx=30 then let cmx=-cmx: END IF let cy=cy+cmy:if cy=0 or cy=22 then let cmy=-cmy: END IF fspCoord (0,gx,gy) fspCoord (1,dx,dy) fspCoord (2,tx,ty) fspCoord (3,cx,cy) fspRedraw() loop
Reply


Messages In This Thread

Forum Jump:


Users browsing this thread: 1 Guest(s)