sprites
- Posted by "BABOR, JIRI" <J.Babor at GNS.CRI.NZ> Mar 30, 1997
- 1387 views
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)