Classic Computer Magazine Archive COMPUTE! ISSUE 87 / AUGUST 1987 / PAGE 99

SoftSprite

Richard Schramm

This compact machine language routine for Atari computers allows you to move playfield shapes rapidly anywhere on the screen using simple BASIC commands.

Eight-bit Atari computers—the 400, 800, XL, and XE models—have a variety of powerful graphics features. However, the only way to draw, move, or animate a playfield shape (any shape that's not a player/missile) from BASIC is with a series of PLOT or POKE statements, an extremely slow process. "SoftSprite" permits you to move such shapes quickly and easily, with simple BASIC commands.

SoftSprite can move, animate, or duplicate a playfield shape on any portion of the GRAPHICS 8 screen. The shapes may be any size, as long as the data for each shape does not exceed 250 bytes. SoftSprite also offers collision detection, and the only limit to the number of shapes is the amount of memory available. And since the SoftSprite machine language code is only 281 bytes long, you can use it in any BASIC program without sacrificing a lot of memory.

Type in the demonstration program and run it to see SoftSprite in action. The program contains extensive REMark statements to explain in detail how SoftSprite works; we'll refer to the code throughout this article.

Making A Shape Table

Before you call SoftSprite from BASIC, you must store two things in memory: the SoftSprite machine code itself and the shape data for the image you want to display. The simplest way to store the data is with loops that READ numbers from DATA statements and that POKE them into safe memory areas.

The shape data can be any size, depending on the image, up to a maximum of 256 bytes (see below). This data is organized into what we'll call a shape table, which is simply a list of numbers that defines the shape.

The figure illustrates how to construct a shape table. The shape we want to construct is an arrow like those shown in the demonstration program. By plotting the shape on graph paper, you easily can determine the numbers needed for its shape table.

This particular shape is ten dots high, so we draw a grid ten rows high. Each row of squares in the grid represents a row of dots in the arrow shape. The shape is nine dots wide. However, because it's easier for the program to deal with byte-length quantities, the shape table is 16 (2 * 8) columns wide. Thus, the grid for this shape is 10 dots high and 16 dots wide.

Within the grid, each group of eight horizontal squares represents a byte, or eight bits of memory. Each bit represents a power of 2, in ascending order from right to left. Thus, the rightmost bit has a value of 1, the next bit to the left has a value of 2, and so forth, up to the leftmost bit, which has a value of 128. The numbers at the top of the figure indicate the values assigned to each bit.

The next step is to fill in the squares where a dot will appear. Once this is done, you add up the bit values for each byte in the grid. The upper left byte, for instance, has a value of 170(128 + 32 + 8 + 2 = 170). The upper right byte, however, has no darkened squares, so its value is zero. The lower right byte has a value of 128, since only its leftmost bit is turned on, and so on.

Shape Table Grid

Once you have written down the values for each byte in the grid, you are ready to construct the shape table. The first six bytes of the shape table are always reserved for SoftSprite's internal use. The first four of these bytes must be zeros, while the fifth and sixth bytes of the shape data represent the shape's height and width, respectively, in terms of bytes. In this case, the shape is 10 bytes high and 2 bytes wide, so the fifth and sixth bytes of its shape table are 10 and 2. The table illustrates the complete shape table for the arrow image.

The shape table can be a maximum of 256 bytes in length, including the six reserved bytes which begin the table. Thus, a shape can be a maximum of 250 bytes in size. You can calculate the size of the shape table by multiplying its height by its width and adding 6; the arrow shape table requires 26 (10 * 2 + 6) bytes.

Once the shape table is complete, you must find a safe memory area to store it. One common technique is to store the table in a string variable. The demonstration program shows how to do this. It first reserves the needed amount of memory with DIM, setting aside 278 bytes for the string SOFT-SPRITE$ and 26 bytes for the string SHAPE$. The ADDR function lets us determine the addresses where the strings SOFTSPRITE$ and SHAE$ begin. These values are assigned to the numeric variables SOFTSPRITE and SHAPE. (Since string variables and numeric variables are of different types, BASIC has no trouble distinguishing SOFTSPRITE from SOFTSPRITE$ and SHAPE from SHAPE$.)

Shape Table For Arrow Image

0 reserved
0 reserved
0 reserved
0 reserved
10 height
2 width
170 row 1, column 1
0 row 1, column 2
170 row 2, column 1
0 row 2, column 2
160 row 3, column 1
0 row 3, column 2
168 row 4, column 1
0 row 4, column 2
168 row 5, column 1
0 row 5, column 2
170 row 6, column 1
0 row 6, column 2
138 row 7, column 1
0 row 7, column 2
138 row 8, column 1
128 row 8, column 2
2 row 9, column 1
128 row 9, column 2
2 row 10, column 1
128 row 10, column 2

After finding the addresses where the strings begin, we can use simple FOR-NEXT loops to READ the required values from DATA statements elsewhere in the program and to POKE them into the string space.

Calling SoftSprite From BASIC

The SoftSprite routine works in GRAPHICS 8, so the next step is to select that display mode. At this point, you are ready to display the shape with a USR statement. Here is the general syntax for calling SoftSprite with USR:

COL = USR(ML address, x, y, shape address

The USR statement always takes four values inside parentheses. The first value is the address where the SoftSprite machine language routine begins. In the demonstration program, the variable SOFTSPRITE equals this address. The second and third parameters are the horizontal (x) and vertical (y) screen coordinates where you want the shape to appear. The fourth parameter is the memory address of the shape table (SHAPE in the demonstration program).

A simpler USR statement can be used to turn the shape off, once it is on the screen. In this case you can omit the coordinates, supplying only the address of the ML routine and the address of the shape data:

COL = USR(ML address, shape address)

Collision Detection

SoftSprite tests for collisions while it draws each byte of data from the shape table. The result of this test is stored in the variable which precedes the USR function (COL in the preceding statements). This variable is set to a nonzero value when a collision occurs and to zero when no collision takes place.

Experienced Atari programmers may have noticed that both the demonstration program and the arrow shape itself take advantage of an effect known as artifacting, which results when you display colored shapes (often a single pixel) in a higher resolution than the computer's display hardware can handle. Artifacting explains why only alternate columns of the arrow shape contain data. As a result, the arrow is either green or blue depending on whether it begins on an odd-numbered screen column or an even-numbered column. You can find more information about artifacting in COMPUTE!'s Second Book of Atari Graphics, available from COMPUTE! Books.

Artifacting also affects collision detection in SoftSprite. Simply put, SoftSprite cannot detect a collision between two artifacted shapes if they are different colors. For instance, if one shape is solid blue and the other is solid green, they can pass through one another without triggering a collision in Soft-Sprite. In that case, the area where the shapes overlap turns white. This effect can be observed in the demonstration program; when the moving arrow overlaps the blue arrow, no collision is detected, but the program does detect a collision when the moving arrow overlaps the green arrow. One way to circumvent the problem is to design one of the shapes so that it's completely enclosed by a solid border.

Animation

Lines 150 and 170 show how Soft-Sprite can copy a shape from the shape table to any portion of the display screen. The first USR call in line 150 puts the shape on the screen as usual. Next, the program POKEs a zero into the first byte of the shape table. The effect of this POKE is to turn off the shape without removing its image from the screen. Once this is done, however, the data for that shape's location is lost, and the only way to erase it is to redraw it at exactly the same screen position.

You may copy a shape to the screen as many times as you like. The first and second bytes of the shape table contain the last screen address where the shape appeared, held in low byte/high byte format.

Animation is simply a matter of turning a series of shapes on and off at the same screen position. Unlike other bitmapped graphics routines, SoftSprite does not require that each frame of the animation be the same size.

The shapes drawn by SoftSprite will always flicker when you move them. Because the program shifts each byte of the shape as it is being drawn, there is not enough time during the computer's vertical blank interrupt to perform the shift. Because the drawing occurs outside the vertical blank period, some flickering is inevitable.

Softsprite does not check for boundary errors and faithfully draws the designated shape at whatever screen coordinates you assign. If you attempt to draw outside the screen boundaries, you might corrupt important information, such as the data stored above the computer's RAMTOP pointer. The only error checking performed by the program is to determine whether you have supplied the right number of parameters in the USR call.

Machine language programmers should note that SoftSprite uses nearly all of the computer's floating point registers; any attempt to call the SoftSprite ML code from within a vertical blank interrupt routine will probably cause a system crash.

SoftSprite Demonstration

For instructions on entering these programs, please refer to "COMPUTE!'s Guide to Typing In Programs" elsewhere in this issue.

KL 5 REM COPYRIGHT 1987
BJ 6 REM COMPUTE! PUBLICATIONS, INC.
FD 7 REM ALL RIGHTS RESERVED.
PA 10 ? CHR$(125); "LOADING DATA FILES.."
OD 20 REM reserve memory for SOFTSPRITE{9 SPACES}program and shape table using (9 spaces) strings : 
MK 30 DIM SOFTSPRITE$ (281), SHAPE$ (26)
BL 40 REM initialize both strings : 
KK 50 SOFTSPRITE$(1) = "A" : SOFTSPRITE$(281) = "A" : SOFTSPRITE$ (2) = SOFTSPRITE$ : SHAPE$ = SOFTSPRITE$
HL 60 REM find starting addresses of {12 SPACES} SOFTSPRITE program and shape{10 SPACES}table : 
LL 70 SOFTSPRITE = ADR(SOFTSPRITE$) : SHAPE = ADR(SHAPE$)
AM 80 REM load shape table into the {13 SPACES} memory reserved for the string {8 spaces}"SPAPE" : 
FA 90 FOR OFFSET = 0 TO 25 : READ DATA : POKE SHAPE + OFFSET, DATA : NEXT OFFSET
ID 100 REM load SOFTSPRITE program into {10 SPACES}memory reserved for the string {8 SPACES}"SOFTSPRITE" : 
ED 110 FOR OFFSET = 0 TO 280 : READ DATA : POKE SOFTSPRITE + OFFSET, DATA : NEXT OFFSET
BD 120 REM open screen to graphics 8 full {8 SPACES} screen mode with a black {14 SPACES} background : 
AM 130 GRAPHICS 8 + 16 : POKE 71 0, 0
CL 140 REM put shape on an even x {16 SPACES} coordinate causing it to {14 SPACES} appear green : 
DJ 150 COL = USR(SOFTSPRITE, 100, 95, SHAPE) : POKE SHAPE, 0
MP 160 REM put shape on a odd X{18 SPACES} coordinate causing it to {14 SPACES} appear blue : 
EE 170 COL = USR (SOFTSPRITE, 181, 95, SHAPE) : POKE SHAPE, 0
AB 180 x = 140 : Y = 95
EJ 190 REM put shape on even coordinate, {9 SPACES} but do not rubber-stamp it, {11 SPACES} will be used as a sprite : 
JP 200 COL = USR (SOFTSPRITE, X, Y, SHAPE) : SOUND 0, COL, 10, 8
BE 210 REM scan keyboard for key press : 
BP 220 KEY = PEEK (764) : IF KEY = 255 THEN 220
DB 230 IF KEY = 14 THEN Y = Y-2 : GOTO 200
DB 240 IF KEY = 15 THEN X = X-2 : GOTO 200
AC 250 IF KEY = 6 THEN X = X-2 : GOTO 200
AC 260 IF KEY = 7 THEN X = X + 2 : GO TO 200
AA 270 IF KEY = 33 THEN COL = USR (SOFTSPRITE, SHAPE) : GOTO 220
BH 280 GO TO 220
ML 290 REM shape table of arrow, 1st four {8 SPACES} bytes MUST ALWAYS be zero : {12 SPACES} followed by height & width : 
MM 300 DATA 0, 0, 0, 0, 10, 2
KP 310 REM rest of shape table, actual {11 SPACES} shape data of arrow : 
EN 320 DATA 170, 0, 170, 0, 160, 0, 168, 0, 168, 0, 170, 0, 138, 0, 138, 128, 2, 128, 2, 128
HL 340 REM
OC 350 REM the folowing data file the {12 SPACES} SOFTSPRITE program : 
HM 360 REM
KI 10000 DATA 216, 104, 133, 222, 201, 1, 240, 29, 201, 3, 240, 11, 10, 168, 104, 136, 208, 252, 169, 32, 133, 195, 96, 169, 0, 133
IK 10010 DATA 222, 104, 133, 221, 104, 133, 220, 104, 104, 133, 219, 104, 133, 225, 104, 133, 224, 160, 6, 132, 231, 136, 177, 224, 133
DI 10020 DATA 228, 136, 177, 224, 133, 229, 133, 230, 136, 177, 224, 133, 233, 136, 177, 224, 133, 226, 136, 177, 224, 133, 236, 136, 177
PP 10030 DATA 224, 133, 237, 240, 87, 169, 0, 133, 235, 165, 226, 133, 227, 166, 228, 169, 0, 133, 234, 164, 231, 177, 224, 240, 10
CN 10040 DATA 164, 233, 240, 6, 74, 102, 234, 136, 208, 250, 5, 235, 72, 164, 227, 49, 236, 240, 2, 133, 212, 104, 81, 236, 145
BK 10050 DATA 236, 165, 234, 133, 235, 230, 227, 230, 231, 202, 208, 209, 200, 165, 234, 72, 49, 236, 240, 2, 133, 212, 104, 81, 236
BL 10060 DATA 145, 236, 165, 236, 24, 105, 40, 133, 236, 144, 2, 230, 237, 198, 229, 208, 169, 165, 222, 240, 16, 201, 6, 240, 9
FA 10070 DATA 160, 0, 132, 212, 132, 213, 152, 145, 224, 96, 208, 149, 165, 220, 41, 7, 133, 233, 160, 3, 145, 224, 70, 221, 165
JJ 10080 DATA 220, 106, 74, 74, 133, 226, 136, 145, 224, 169, 0, 133, 212, 133, 213, 6, 219, 42, 6, 219, 42, 6, 29, 42, 133
NK 10090 DATA 237, 166, 219, 134, 236, 6, 219, 42, 6, 219, 42, 170, 165, 219, 24, 101, 236, 133, 236, 138, 101, 237, 133, 237, 165
DJ 10100 DATA 88, 24, 101, 236, 133, 236, 136, 145, 224, 165, 89, 101, 237, 133, 237, 136, 145, 224, 165, 230, 133, 229, 169, 6, 133
LC 10110 DATA 231, 133, 222, 208, 161