Sprites are much more than movable objects intended for games. For example, sprites can be used to set up a special bitmap screen suitable for plotting graphics. Once you have drawn your image, it’s fairly easy to move it – sprites can be moved by only changing the content of very few VIC-II chip registers.
For instance, a little sprite-based bitmap screen can be created by using four sprites. Those can be positioned like in the following picture:
Each sprite is 24×21 dots, so by joining four sprites together we obtain a 48×42 bitmap screen.
The following BASIC V2 program draws a circle, then moves it.
At the beginning, all sprite shapes are filled with the value 255 decimal. The program then draws a circumference on the sprites by turning off calculated points. Once the drawing is complete, points outside the circumference are turned off by an unfilling routine. This routine processes each sprite. It should be faster than filling the inner part of the circle.
Plotting on a sprite
First of all, we need a formula to find a given (X, Y) point on a sprite. A sprite is made up of 24 x 21 dots, and bytes are arranged as follows:
So, if the base address of a sprite shape is 12288 decimal, then byte 0 is on location 12288, byte 1 on location 12289, byte 2 on 12290, byte 3 on 12291 and so on.
Now, to plot a point (xp, yp) in a sprite shape, we need to know what byte contains this point and which bit corresponds to the point itself.
The byte can be evaluated as follows:
by = ba + yp*3 + int(xp/8)
Where ba is the base address of the sprite shape (that is, the first byte of the sprite drawing in memory).
The bit to turn on (from 0 to 7) can be evaluated by the following expression:
bn = 7 - (xp and 7)
Now, once a little array BI for the bit values is set up, the following basic statement will turn on the point:
poke by,peek(by) or bi(bn)
Please note that the array bi is used to get the precomputed term 2^bn. Since evaluating powers is slow in BASIC, this method provides a little speed advantage.
Plotting points on a four sprite bitmap screen
If we place four sprites together like explained above, we obtain the following situation:
When plotting points in sprite 0 (the pink sprite in the top, left-hand corner), we can use the above formula with no problem. In facts, we can use that formula on the whole sprite based bitmap screen.
Given the point to plot, we can check its coordinates. If both x and y coordinates are within the range of a single sprite, we can apply the above formula directly and plot the point on sprite 0.
If the x coordinate is in range but the y coordinate is greater than 20, then we know we must plot the point on sprite 2. We can still use the same plotting formula, but we have to adjust the y coordinate. We just need to subtract 21 to it. We also have to change the base address, so that it now matches sprite 2. So, using a pseudo-code:
if x <= 23 and y > 20 then y = y - 21 : plot on sprite 2 set BA = sprite 2 base address
Similarly, if the x coordinate is greater than 23, and the y coordinate is in range (that is, within the limits for a single sprite), we know that we must adjust the x coordinate and plot on sprite 1. So, again with pseudo-code:
if x> 23 and y <= 20 then x = x - 24: plot on sprite 1 set BA for plot = base address of sprite 1
Similar conditions will tell us when to plot on the remaining sprites.
The sprite plotter routine in the program (starting from line 300) handles all possible cases.
The program does not use a generic filling routine. Instead, I have just come up with a simple routine that suits this particular case. So, this routine makes the assumption that the circle is centered on the common point between the four sprites (that is, the center of the sprite based bitmap screen).
Instead of drawing a circumference and then filling it, I have decided to do something different. At the beginning, sprites are completely filled. Then, the circumference is plotted in reverse (that is, by turning points to 0).
This approach makes things easier. We can now start from the outer edges of a sprite and, moving horizontally across one row, clear the points which have been previously turned on until we reach a turned off point (that is, a point of the circumference). When we reach such a point, we just have to stop turning off points and do nothing more – we only have to leave the remaining points on that row turned on.
Instead of doing that check bit by bit, the code examines the content of each byte. When starting from the outer corner, if a byte contains the value 255, then we know it contains all filled points and we must clear them all. That just requires to POKE a zero on the corresponding location. If the next value has a value different than 255, then we know there is a circumference point in it. We now have to check bits, but not all bits. Just the bits before the circumference point. So, we need to keep track of how many bits we have before the circumference point, then we have to turn off only those points. Remaining points must be left on.
Since we have to start from the outer edges, on sprites 0 and 2 the check is done from left to right. On sprites 1 and 3, the check is done from right to left. So, the routine has been split in two similar routines to handle both cases (starting from lines 330 and 430). But the concept stays the same.
Each routine makes use of a small subroutine that checks some bits when needed (subroutines starting from lines 400 and 500). Again, one subroutine examines bits from left to right, the other from right to left.
Although such methods are not general, they are relatively fast. In facts, taking out the outer points doesn’t require too much time after all, considering it’s BASIC V2. A more sophisticated routine checking all bits would be more general, but clearly much slower.
Again, please note that only one circle centered on the sprite based bitmap screen is allowed for this routine to work.
Moving the sprites
As we have four sprites to move, moving them all even in X direction only is not that simple when using BASIC V2. Theoretically, we need four POKEs on each frame to move those sprites horizontally.
Maybe a short BASIC program can handle that (remember that short programs are faster). As this program is not that short, when trying to move all sprites on a single frame we get some flicker. So, I had to adjust the code a bit so that sprites are moved slower. The result is not perfect but it works enough to demonstrate the technique of putting more sprites together to get a bigger moving sprite. This approach is used in games very often.
Sprite-based bitmap screens
Setting up a sprite based bitmap screen has been a nice experiment for me (I have never done that before). This approach is used on assembly demos quite often, as interrrupt techniques allow sprite multiplexing, thus a big sprite based bitmap screen.
Advantages of creating such a special screen are several. For instance, if you plot a 3D object on a sprite screen, then translating it it’s just a matter of changing a few sprite registers. You don’t need to translate all the points of the object. Furthermore, if you have a background image made up with programmable characters, it wil just live along nicely with the sprite image. That means, no intersecting points headaches – priority between images is just handled on the hardware.
Sprites can be also used to extend the possible color combinations of an image. In facts, several software-driven graphics modes use sprites to improve the quality of images.
A text scrolling over a bitmap image is a clear example of a creative use of sprites (you’ll certainly remember the end part of the demo Deus ex Machina by Crest).