
So, after working out exactly what is needed for animated sprites and how to implement them in a safe robust way, I though I'd upload a starter kit with the bare bones code to render 16 moving animated sprites. You only need 2 INL files and 7 asm call functions.
"SPRITES.INL" (4 functions) and "WAIT_VBI.INL" (3 functions).
Note: This code does a few things which is not the typical "GFA BASIC style". eg: I load INL at runtime and I calc jump table addresses via a procedure.
This was done to provide robust safely checks to minimize the chances of crashes due to slightly incorrect code.
I also used a different method of defining the sprite records. I used a 2D array which allows for code like this to set sprite positions:
Code: Select all
sprite(xpos|,a)=RAND(320)
sprite(ypos|,a)=RAND(200)
Here is the code in question, so it can be read without download:
Code: Select all
DEFLIST 0
DEFWRD "A-Z"
'
' ** Set this to the path location of STARTER.GFA
' ** Remove it before compiling!
'
' CHDIR "\STARTER"
'
screen.init(16)
'
SETCOLOR 0,0
SETCOLOR 15,&H777
'
animation.init(4,FALSE,16,ball())
FOR i=0 TO 3
r=2+i*2
CLS
DEFFILL 2
PCIRCLE 8,8,r
DEFFILL 0
PCIRCLE 8,8,r\2
COLOR 6
CIRCLE 8,8,r
animation.grab(i,0,0,ball())
NEXT i
'
CLS
FOR i=1 TO 500
PSET RAND(320),RAND(200),RAND(15)
NEXT i
BMOVE screen%(0),screen%(1),32000
'
sprite.show(0,ball())
sprite.show(1,ball())
sprite.show(2,ball())
sprite.show(3,ball())
sprite.show(4,ball())
sprite.show(5,ball())
sprite.show(6,ball())
sprite.show(7,ball())
sprite.show(8,ball())
sprite.show(9,ball())
sprite.show(10,ball())
sprite.show(11,ball())
sprite.show(12,ball())
sprite.show(13,ball())
sprite.show(14,ball())
sprite.show(15,ball())
'
FOR a=sprite.min TO sprite.max
sprite(xpos|,a)=RAND(320)
sprite(ypos|,a)=RAND(200)
NEXT a
'
REPEAT
FOR a=sprite.min TO sprite.max
sprite(frame|,a)=sprite(xpos|,a) AND 3
INC sprite(xpos|,a)
INC sprite(ypos|,a)
IF sprite(xpos|,a)>320+16
SUB sprite(xpos|,a),320+32
ENDIF
IF sprite(ypos|,a)>200+16
SUB sprite(ypos|,a),200+32
ENDIF
NEXT a
screen.swap
UNTIL LEN(INKEY$)
'
screen.done
'
END
'
' ---------------------------------------------------------------------------
'
PROCEDURE screen.init(count)
library("sprites.inl",sprites%())
'
extern(1,sprites%(),print_sprites%)
extern(2,sprites%(),erase_sprites%)
extern(3,sprites%(),clip_sprites%)
extern(9,sprites%(),store_sprite%)
'
library("wait_vbi.inl",wait_vbi%())
'
extern(0,wait_vbi%(),counter_on%)
extern(1,wait_vbi%(),counter_off%)
extern(3,wait_vbi%(),swap_sync%)
'
LOCAL a
CLS
HIDEM
SPOKE &H484,BCLR(PEEK(&H484),0)
'
sprite.min=0
sprite.max=PRED(count)
sprite.count=count
'
mode|=0
animation|=1
frame|=3
xpos|=4
ypos|=5
width|=6
height|=7
size|=8
buffer_1|=9
buffer_2|=11
'
DIM sprite(12,sprite.max)
DIM screen.buffer|(2320,1,sprite.max)
DIM screen.double|(32256),screen%(2)
'
FOR a=sprite.min TO sprite.max
{V:sprite(buffer_1|,a)}=V:screen.buffer|(0,0,a)
{V:sprite(buffer_2|,a)}=V:screen.buffer|(0,1,a)
NEXT a
'
screen%(0)=(V:screen.double|(0)+&HFF) AND NOT &HFF
screen%(1)=XBIOS(3)
screen%(2)=screen%(1)
screen.oldrez=XBIOS(4)
'
~XBIOS(5,L:screen%(0),L:screen%(1),0)
'
bc(clip_sprites%)
~C:clip_sprites%(0,0,319,199)
bc(counter_on%)
~C:counter_on%()
'
ON BREAK GOSUB screen.break
ON ERROR GOSUB screen.error
RETURN
'
PROCEDURE screen.done
bc(counter_off%)
~C:counter_off%()
~XBIOS(5,L:screen%(2),L:screen%(2),screen.oldrez)
RETURN
'
PROCEDURE screen.error
screen.done
~FORM_ALERT(1,ERR$(ERR))
END
RETURN
'
PROCEDURE screen.break
screen.done
END
RETURN
'
PROCEDURE screen.swap
bc(erase_sprites%)
~C:erase_sprites%(sprite.count,L:V:sprite(0,0))
bc(print_sprites%)
~C:print_sprites%(sprite.count,L:V:sprite(0,0),L:screen%(0))
SWAP screen%(0),screen%(1)
bc(swap_sync%)
~C:swap_sync%(1,L:screen%(0),L:screen%(1))
RETURN
'
PROCEDURE animation.init(frames,width!,height,VAR a())
frames=MIN(MAX(frames,1),16)
height=MIN(MAX(height,1),48)
DIM a(3+SHL(5,width! AND 1)*height*frames)
a(0)=width! AND 1
a(1)=height
a(2)=SHL(10,width! AND 1)*height
a(3)=frames
RETURN
'
PROCEDURE animation.grab(frame,x,y,VAR a())
LOCAL w
IF frame>=0 AND frame<a(3)
x=SHL(x,4)
w=SHL(16,(a(0)<>0) AND 1)
bc(store_sprite%)
~C:store_sprite%(frame,x,y,w,a(1),L:V:a(4),L:screen%(0))
ENDIF
RETURN
'
PROCEDURE sprite.show(a,VAR a())
sprite(mode|,a)=1
sprite(width|,a)=a(0)
sprite(height|,a)=a(1)
sprite(size|,a)=a(2)
{V:sprite(animation|,a)}=V:a(4)
RETURN
'
PROCEDURE sprite.hide(a)
sprite(mode|,a)=0
RETURN
'
PROCEDURE library(filename$,VAR library%())
OPEN "I",#1,filename$
DIM library%(SHR(LOF(#1),2))
BGET #1,V:library%(0),LOF(#1)
CLOSE #1
RETURN
'
PROCEDURE extern(index,VAR library%(),extern%)
IF extern%<>0
ERROR -36
ENDIF
extern%=V:library%(index)
bc(extern%)
RETURN
'
PROCEDURE bc(VAR a%)
IF a%=0
ERROR 9
ENDIF
IF DPEEK(a%)<>&H6000
ERROR 9
ENDIF
RETURN
'
END