8-bit computers are pretty slow, and that makes creating large, fast-moving graphics difficult. However, some early computer designers came up with the idea of giving the video hardware the capability of generating certain graphical elements itself. Each frame, these elements were effectively laid on top of the graphics or text generated from memory, and were called ‘sprites’, after the mythical creatures, due to their similar ability to move about quickly, appear and disappear.
This meant that a game developer could generate a background, then use sprites for the moving objects, without having to undraw and redraw the background underneath them, a very time-consuming process. This allowed computers such as the Atari 800 and the Commodore 64 to have fast-moving, arcade-style graphics in their games.
However, the Apple II does not have sprites, and this means that if you want fast-moving games you need to program them in machine (assembly) language. But we would like people to be able to create BASIC games that are fun, and so the solution (at least in microM8) was to add virtual sprite capabilities to our video renderer.
Our virtual sprite chip supports up to 128 sprites (numbered from 0 to 127) 20 pixels wide and 20 pixels high, up to 16 colours, depending on the underlying video mode.
While not yet accessible through assembly language, there are several sprite-related commands in microBASIC that have been added:
@sprite.bounds{sprite,x,y,size}
x and y define the top-left corner of the cropped sprite, and size is the number of pixels in the x and y directions the cropped area covers. For example, {1,5,5,10} will crop sprite 1 from pixel 5,5 to 15,15.
@sprite.color{sprite,colour}
Causes non-0(black) areas of the sprite to be rendered using the specified colour.
@sprite.copy{source,destination}
Duplicates the sprite index specified by source into the destination sprite index.
@sprite.define{sprite,”data string”}
To keep the size of BASIC programs from getting too unwieldy, sprites are defined using a run-length encoded string. This string can be generated using the Sprite Editor available in the Tools sub-menu of the microM8 menu; however, if you would like to implement it yourself, details are below:
The string is a hex string, where values 0-9 and A-F represent each pixels colour, from 0 to 16. Additional letters indicate multiple pixels of the same colour: P means one MORE pixel of the previous colour, Q means 2, R means 3, S means 4, T means 5, U means 6, V means 7, W means 8, X means 9, Y means 10 and Z means 11. This simple encoding is easy to implement yourself, if you would like to create your own sprite editor.
@sprite.flip{sprite,value}
Values 0,1,2 and 3 flip the specified sprite in neither direction, vertically, horizontally and both directions respectively.
@sprite.off{sprite}
Turns sprite off.
@sprite.on{sprite}
Turns sprite on.
@sprite.place{sprite,x,y}
Places or moves sprite at / to screen pixel co-ordinate x,y (top-left corner of sprite). For example, @sprite.place{10,20,20} will place sprite 10 at co-ordinate 20,20.
@sprite.reset{}
Deletes all sprite data and turns all sprites off.
@sprite.rotate{sprite,value}
Values 0,1,2 and 3 rotate the specified sprite 0, 90, 180 or 270 degrees respectively.
@sprite.scale{sprite,value}
Values 1,2 and 3 scale the sprite 100%, 200% and 300% respectively.
@sprite.stamp{sprite,x,y(,colour)}
“Stamps” the specified sprite into the graphics memory at coordinate x,y and if an optional colour is specified, all non-0 (black) pixels are rendered using that colour. Stamps are useful for generating backgrounds.
@sprite.unstamp{sprite,x,y}
Similar to stamp, except sets all of the pixels overlaid by the sprite to 0 (black). You could use stamp and unstamp similarly to Applesoft’s ‘shape’ facility, but this is more complex than using sprites.
A=@sprite.collision{sprite}
Returns the index of another sprite overlapping (colliding) with the specified sprite, or -1 if there are no colliding sprite(s). If there are multiple colliding sprites, the lowest index is returned (if sprite 15 and 6 intersect with sprite 3, A=@sprite.collision{3} will set A to 6, for example)
A=@sprite.test{sprite,x,y}
Sets A (or whatever variable you specify) to a value of 1 (true) if specified sprite placed at x,y will collide with another sprite. You can also PRINT @sprite.test{sprite,x,y} similarly to other functions.
A=@sprite.xpos{sprite}
Sets A to the specified sprite’s X position.
A=@sprite.ypos{sprite}
Sets A to the specified sprite’s Y position.