Thursday, November 09, 2006

Xe03: Sprites

Well I've not fallen off the face of the planet, Mike and I have been busy beavering away and we've both been looking at the issue of sprites, I've been unsure on the best way to do them on the Spectrum and wondering how he has acheived so much on the Plus/4. Anyway see Mikes blog for some of the fruits of those discussions about different techniques.

So now that I have the scrolling working and rendering I want to draw as many sprites as possible (Mike manages 10 masked sprites on the Plus/4) onto the main play area. On the 48K (which is still my target, as much as Mike keeps saying that I should look at 128K). So to achieve this I have to ensure that I draw the sprites before the raster displays the area that I am rendering to. Therefore I need to draw the sprites in a sorted order (from the top of the screen to the bottom) to stay ahead of the raster. Since the scrolling takes from the top of the screen (where I sync to) to the bottom of the screen (well a few scan lines over) I have the whole of the lower border, VBlank, upper border and then the screen area (staying ahead of the raster). Which is a fair amount of time...

So I have to get a really fast sprite routine, and I invite you all to give suggestions on the best way. Following some discussions on the World of Spectrum (www.worldofspectrum.org/forums) I'm using the zig-zag pattern of sprites i.e. for a sprite that is of the format

ABC
DEF
GHI


then the bytes would be arranged normally as

A0 B0 C0
A1 B1 C1
A2 B2 C2
...
G7 H7 I7


In Zig Zag they are arranged as

A0 B0 C0
C1 B1 A1
A2 B2 C2
C3 B3 A3
...
I7 H7 G7


In this way it minimises the number of increments and decrements that a sprite routine has to do (also means that the screen address does not need to be reloaded at all).

So the basic structure of a sprite routine is
// byte 0
get source
logical operation with dest
store in dest
next source
inc dest
// byte 1
get source
logical operation with dest
store in dest
next source
inc dest
// byte 2
get source
logical operation with dest
store in dest
next source
move dest down one line
// byte 3
get source
logical operation with dest
store in dest
next source
dec dest
// byte 4
get source
logical operation with dest
store in dest
next source
dec dest
// byte 5
get source
logical operation with dest
store in dest
next source
move dest down one line


So going with my old favourite, I'm going to use the stack pointer to point at the source data and then store my Mask and Data together so that a single pop will read both of them and my inner core will become

     pop   de
ld a,(hl)
and e
or d
ld (hl),a
inc l


Using the stack means that we fetch the data and increment to the next byte all at once, the logical operation is fairly simple and the step to the next screen byte is a simple increment all nice and easy!!

Now I've done some timings and I can get around 14 (24x16) of these in our time frame which is pretty good.

The observant among you will have noticed that I'm not doing any rotation in this routine, that's because I'm going to implement a sprite cache like Mikes and store all the sprites rotated in the cache (remaking them when I need to), which means I don't need to do that in here (remember staying ahead of the raster).

Lastly I need to feed these routine as quickly as possible so I am using a small routine that reads a table and calls the correct draw routine as quickly as possible

DrawSprites:    di
ld (DS_sp_restore+1),sp

ld de,6
ld hl,SpriteStack
DS_lp: ld sp,hl
exx
pop hl ; routine address
ld a,h
and a
jr z,DS_exit

ld (DS_jump_address+1),hl
pop de ; screen address
pop hl ; graphics address
ld sp,hl
ex de,hl
DS_jump_address jp #ffff
DS_sp_lp_back: exx
add hl,de
jr DS_lp

DS_exit:
DS_sp_restore: ld sp,#ffff
ei
ret


So if you can spot a quicker way to do things let me know, because I want to make the Spectrum version better than the C64 or Plus4... ;)

Comments:
Aaaaaah, are you throwing your gauntlet to us, uh? ;)
14 sprites! Let figure how much a screen can be filled of moving rubber to trash out!
Keep it 48K, that's my opinion.
 
Seems near optimal to me..

Of course there's always plenty of special case optimizations to implement. Like single-plane sprites, an opaque blitter for solid black areas, compiled sprites, etc.

I guess you could replace that OR with an XOR, and let sprites invert the background as a special effect.

By the way are you planning to use color in-game or will everything be monochrome?

/doynax
 
I'd like to get colour in the game and I've been arguing with Mike that colour clash on the Spectrum is acceptable.

I'm thinking of just putting colour in the background and not on the sprites so that we they will pass through the colour of the background. This is fairly normal for Spectrum games.

I'm already building several sprite routines and doing most of the ones that you mention, glad that we are on the same wavelength.
 
Damn Spammers! Like anyone would fall for that rubbish "I'm looking for different ways to earn money..." - he should start a cult.

Anyway, nice to see you've got the sprites sorted :-)

Keep up the good work.

Regards,

Shaun.
 
Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?