sprites
Hi everybody,
Initially, when I was asked to explain what was going on under the bonnet of my
aliens!, I thought it was quite obvious. Then I thought a bit more about it
and prepared these notes. Line numbers, where given, refer to the attached
little
demo. It is actually a sanitized copy of my first attempt, with a few comments
thrown in for a good measure.
All the usual disclaimers and customary lies apply here too: this is my first
venture into the sprite territory, and there is always a better/faster way of
doing anything, etc...
I shall concentrate on the mode 19, because it has such an easy, linear
arrangement of the video memory: a block of 64,000 bytes, one for every pixel on
the screen. It starts at #A0000 location, which corresponds to the top left hand
corner of your screen, and continues in left-to-right, line-by-line manner to
the bottom of your screen. I shall also assume, for simplicity, that in this
case the *whole* screen is our playfield.
The method consists of six basic steps:
Step 1: Reserve two blocks of memory for your virtual screens, one as a
working area, and the other as a permanent storage of the screen
background. Lines 74 & 75.
Step 2: Draw the background directly on the screen in any way you fancy.
Step 3: Store the background in one of the virtual screens.
Normally, it would be something like: mem_copy(s1,A,N)
I short-circuited the step 2 and 3 in the demo, drawing the
background directly into the storage memory: Lines 78 to 82.
The next three steps will be repeated over and over again in the main action
loop (lines 114 to 118), which usually contains some other things like timing,
checking of input, etc. Here they are gathered in the frame() routine, lines 23
to 54.
Step 4: Prepare your working virtual screen first by copying the background
into it, line 26: mem_copy(s2,s1,N)
Step 5: The tricky bit: update your sprites and draw them into the virtual
working screen, lines 28 to 52.
Step 6: Display the updated working screen by copying it to the video memory,
line 53: mem_copy(A,s2,N)
In real life, of course, you will need more than two virtual screens to store
temporary backgrounds for your Intro, Game Over screens,etc.
The step 5, especially its second part, drawing of sprites, is most critical in
terms of speed. Hollow and/or complicated sprites lead to short, broken poke
sequences and are expensive. A bit of care and effort with things like sprite
pre-processing, or taking advantage of symmetries (as in the following demo),
can make a huge difference!
That's it! Jiri
-- snip ------------------------------------------------------------------------
-- sprite.ex : sprite experiments
-- jiri babor
-- j.babor at gns.cri.nz
-- version 1.00 97-03-29
include graphics.e
include machine.e
include get.e
constant
A=#A0000, -- start of video memory
N=64000, -- screen size
ns=20, -- number of sprites
x=1, y=2, -- sprite labels
xv=3, yv=4, -- sprite labels
h=5, -- sprite half height
w=15 -- sprite width
atom dt,s1,s2,t
integer count,junk
sequence c,sdata,pal,s,S,ss
procedure frame()
sequence s
integer m,n
mem_copy(s2,s1,N) -- fresh copy of background into working screen
-- update sprites
for i=1 to ns do
if sdata[i][x]+sdata[i][xv]<1 or sdata[i][x]+sdata[i][xv]+w>320 then
sdata[i][xv]=-sdata[i][xv]
end if
if sdata[i][y]+sdata[i][yv]<1 or sdata[i][y]+sdata[i][yv]+h+h>200 then
sdata[i][yv]=-sdata[i][yv]
end if
sdata[i][x]=sdata[i][x]+sdata[i][xv]
sdata[i][y]=sdata[i][y]+sdata[i][yv]
-- write sprites to virtual screen
for r=1 to h do
m=1 n=1
while m<w do
if ss[i][r][m] then exit
else m=m+1 end if
end while
n=m
while n<w do
if ss[i][r][n+1] then n=n+1
else exit end if
end while
poke(s2+(sdata[i][y]+r-1)*320+sdata[i][x]+m-1, ss[i][r][m..n])
poke(s2+(sdata[i][y]+10-r)*320+sdata[i][x]+m-1, ss[i][r][m..n])
end for
end for
mem_copy(A,s2,N) -- display: copy virtual screen s2 into video memory
end procedure
-- main ------------------------------------------------------------------------
junk = graphics_mode(19)
-- set palette
pal=repeat({0,0,0},256)
for i=0 to 16 do
pal[i+1]=palette(i,{0,0,0})
end for
for i=0 to 63 do
pal[i+65]={32+floor(i/2),i,i}
pal[i+129]={i,32+floor(i/2),i}
pal[i+193]={i,i,32+floor(i/2)}
end for
all_palette(pal)
-- allocate memory for virtual screens
s1=allocate(N)
s2=allocate(N)
-- set background
for i=0 to 199 do
for j=0 to 319 do
poke(s1+i*320+j,255-floor(i*0.25))
end for
end for
-- set sprite data
sdata=repeat(repeat(0,4),ns)
for i=1 to ns do
sdata[i][x]=rand(319-w)
sdata[i][y]=rand(199-h-h)
sdata[i][xv]=6-rand(11)
sdata[i][yv]=5-rand(9)
end for
-- generate sprite images
S={{0,0,0,0,1,1,1,1,1,1,1,0,0,0,0},
{0,0,1,1,1,1,1,1,1,1,1,1,1,0,0},
{0,1,1,1,2,2,2,2,2,2,2,1,1,1,0},
{1,1,1,2,2,2,2,2,2,2,2,2,1,1,1},
{1,1,1,2,2,2,2,2,2,2,2,2,1,1,1}}
ss={}
for i=1 to ns do
s=S
c={64*rand(3)+rand(40),64*rand(3)+rand(40)} -- random color
for j=1 to h do
for k=1 to w do
if s[j][k] then s[j][k]=c[s[j][k]]+k end if
end for
end for
ss=append(ss,s)
end for
count=0
t=time()
while 1 do
frame()
if get_key()!=-1 then exit end if
count=count+1
end while
dt=time()-t
junk = graphics_mode(-1)
printf(1,"%5.2f f.p.s.\n",count/dt)
|
Not Categorized, Please Help
|
|