THE SECRETS OF BASIC ANIMATION
Enhance your games in BASIC
by FRED PINHO
This article concludes a two-part series on Player/Missile animation throw BASIC. See "Use BASIC To Animate" (Antic, p. 46, June 1984) for the first article in the series as well as the accompanying program listing (Tank Battle) and Tables 1 and 2. Tank Battle is a four-player, tank-battle game that requires 32K.( XL owners should modify the program as specified in the first article.) The goal of this tutorial is to teach you how to use BASIC to move players and fire missiles both horizontally and vertically.
Last month's article gave you an introduction to the Player/Missile (P/M) system. This month I'll finish discussing the P/M registers listed in Table 1 last month and explain in depth how the program works.
See Table 1, Items 3 and 4. You can double or quadruple the width of the player's image (in this game, that of a tank) by POKEing a number into the player-size register. My program uses the smallest, or normal width for players.
See Table 1, Item 13. When players "collide" with each other or with another object on the screen, the computer must know which image should appear "in front" of the others. You can assign this priority, by means of the priority register. Tank Battle uses the normal setting, and gives players priority over all other objects.
See Table 1, Item 12. You cannot use the BASIC SETCOLOR command with the P/M system. You must use the command POKE to change the proper registers.
See Table 1, Items 1 and 2. You set a player's horizontal location on your screen by POKEing these registers. Initial values must be present before the system is enabled.
ENABLING THE P/M SYSTEM
See Table1, Items 15 and 16. Once you've set up the above registers properly and stored the data for each player in memory, you must turn on the system. Two registers control this: DMACTL (Direct Memory Access Control) and GRACTL (Graphics Control).
DMACTL, for our purposes, sets P/M resolution; it must be set for the system to function. POKE GRACTL with 3 to enable the Player/Missile system. To turn the system off, POKE GRACTL with O.
This covers most of the registers in Table I (p. 48, June 1984). The remaining registers pertain to player movement, and will be described below.
The program in 1 can be neatly subdivided as follows:
Line # - Description
10 - DIMension variables
20 - Calls initialization routine, then goes to main loop.
30-1140 - Subroutines for player movement, collision detection and missle firing
1150 - Tank Sound
1160-1210 - Main game loop
1220-1280 - End-of-game routine
1290-1540 - PM initialization
MOVING PLAYERS WITH STRING MANIPULATION
To obtain passable P/M speed from BASIC, you must know how BASIC stores and retrieves variables and strings. Specifically, you need to understand the Variable Value Table (VVT) and String/Array Table (SAT).
The VVT is maintained by BASIC and resides in memory below your BASIC program (see Figure 1, p. 50,June 1984). BASIC automatically makes an 8-byte entry in this table for each variable, array and string that you write in your program. These entries are made in the order in which BASIC: encounters each of them. You can obtain the table's memory address with the following formula:
VVT = PEEK(134)+ 256* PEEK(135).
The SAT, which resides above your BASIC pmgram, storesthe actual string and array data. Space is reserved for it by DIMension statements. To find its memory address, use:
SAT = PEEK(140)+ 256 * PEEK(141).
BASIC manipulates strings quickly. You should use the following techniques to move players via string manipulation. First, DIMension the strings that are intended to hold P/M data. Initially, you should DIMension them to one byte so they'll be entered into the VVT. Then, using POKE statements, change the memory address in the VVT so that the string data are located in the preserved P/M data area, rather than the SAT. Finally, expand the string length to cover each player's memory area.
These steps will allow you to create vertical motion by using string manipulation (moving data around within the string). This technique gives you the same effect as poking data into the P/M area, but it does so much more rapidly.
The 8-byte entry in the VVT for each string is structured as follows:
BYTE - DESCRIPTION
1 - Defines variable type. l29 represents a dimensioned string variable.
2 - Variable number (0-127)
3,4 - Starting location of the string as an offset from the beginning of the SAT.
5,6 - Defines current string length.
7,8 - DIMensoned length of the string
Note that each byte pair is stored in low-byte, high-byte form. To obtain the complete value, multiply the contents of the second byte by 256 and add the contents of the first byte.
Unless you fill P/M memory with zeros each time you run the program, leftover data from a previous program may appear on the screen. Normally you'd use a loop to POKE 0 into each location, but this takes too much time in this application. Instead, simply declare a graphics mode whose memory requirement is larger than the one you plan to use. This causes the Operating System to automatically zero (set to zero) the screen memory. These lines call Graphics 8 + 16 (full screen) first, and then Graphics 5.
Next, calculate the proper setback from the top of RAM (in pages), and POKE that value into location 54279. Then calculate the actual value of PMBASE, and those of the VVT and SAT.
LINES 1310-1320 AND 1520
These Lines modify the VVT. Note that the strings for each player (T0$ to T3$) and for the missiles (MSL$) were DIMensioned first. This makes it easy to find the proper entries in the VVT.
You must calculate the initial offset from the start of the SAT to PMBASE and place it in variable Z. Then, add each player's (or missile's) individual offset (stored as DATA in line 1520) to Z. The final offset to the player data is calculated as OFS.
Since this number is greater than 256, you must break it down into low (V2) and high (V3) bytes and POKE them into the third and fourth bytes of each entry in the VVT. In single-line resolution, each player's or missile's memory area is 256 bytes long. POKE the length of the desired string into the final two-byte pairs in VVT. Here, the low byte is zero and the high byte is one.
LINES 1330-1340, 1480-1510 AND 1530-1540
These lines place the player data (lines1530-1540) into direction strings that contain an image for the direction in which a tank is to move. These strings (UP$, DW$, LF$, RT$) are loaded by the subroutines at lines 1480-1510.
The program loads the player strings (T0$-T3$) with the proper image, depending on the direction of motion, from the correct direction strings. As noted above, the computer thinks the player strings are in the P/M memory area. As a result, you see the image on the screen as soon as the player string is loaded. The creation of vertical motion is as simple as moving data back and forth within a player string.
Note that each player image is seven to eight bytes long, while each direction string is 14 bytes in length. Included in the direction string are a minimum of three initial and three tailing zeros. Since each player moves in steps of three, you need these zeros to erase any remnants of the previous image. You can maximize program speed using a single string manipulation both to move a player and to erase the older player.
Initialization of the horizontal-position registers occurs here. You must also zero all missile-position registers, initialize the number of missiles and set the firing- delay counters (D0-D3) to zero at this point.
This line loads player strings with the proper initial image from the direction strings. It also sets the index variables (T0-T3) to indicate the starting position of the image within the string.
These lines set the size for players and missiles. You need to POKE in color values for players and background (black). The program turns the cursor off and then positions it to print the score line.
These lines draw the playfield. Note that lines are three times as wide as normal lines; this is done to ensure that the colIlision registers work properly. The program moves the missiles in steps of six with a FOR/NEXT loop for speed. If the lines weren't this wide, the missile image would either skip over or penetrate them.
These strings move the missiles. Each 13-byte-long string contains six zeros, the value for the missile, and then six more zeros. The leading and trailing zeros erase any remnants of a missile image after it moves.
This turns on the P/M system and returns to the main program.
Here you set a single sound effect prior to entering the main loop. This is one of the compromises needed for faster execution in BASIC -- fancy sound effects would slow the program down considerably.
MAIN GAME LOOP (LINES 1160 TO 1210)
The main loop is only six lines long. Subroutines do most of the program's work.
LINES 1160 TO 1190
Each line here handles a specific tank. First, D0-D3, the reload delay counters, must be incremented. Then the program reads the joystick with a PEEK (I used Boolean algebra to simplify and speed this process). Once the direction has been determined, movement is executed by a subroutine.
Note that the subroutines are placed at the beginning of the Tank Battle program. When BASIC has to find a certain line, it always starts the search at the beginning of the program. As a result, if you place a subroutine here it reduces execution time significantly.
Finally, clear all collision registers with a single non-zero POKE into the collision-clear register (53278).
This line determines if any tank has won the battle or if all tanks have exhausted their missile supplies. If either condition is met, the program branches to the end- of-game routine.
PLAYER-MOVEMENT SUBROUTINE (LINES 30-1140)
These subroutines move players, fire missiles, check for collisions, and update the score. They also make sure that the players stay in bounds (that is, on the screen). Since the set of routines is identical for each player, I'Il just describe the routines for Player 0.
These lines produce movement to the right. H0 is the horizontal-motion index. Motion occurs in increments of four, which causes slightly jerky -- but rapid - movement. This is accomplished by POKEing the horizontal-position register with H0. Then T0$ is loaded with the image for rightward motion from RT$; be sure to do this at the correct vertical position by using the vertical counter (T0).
Line 30 checks for a tank-to-tank collision. Note the line's short time delay. This was required for proper collision detection. If it finds a collision, the program decrements the horizontal index and rePOKEs the horizontal register.
Line 40 checks for a collision with a non-P/M object on the screen. If it finds one, it moves the tank backwards. In either case, the program immediately returns to the main loop to let the other players move.
Line 50 checks to see if the fire button has not been pressed, if the tanks are out of missiles, and if there is any reload time left. If any of these are found program returns immediately to the main loop.
When control passes to line 60, it means that a missile's been fired. The reload counter is then set to 0, and the number of missiles is decremented. MSL$ is loaded with 3 for Missile 0; the vertical counter T0 is used to ensure that it's loaded at the correct vertical position. Next, the program moves the missile rapidly in steps of six. Rapid motion is necessary here, because all other motion stops while the missile is moving. If a collision occurs, the program breaks out of the FOR/NEXT loop prematurely (and uses POP to avoid disturbing the mechanisms BASIC uses to keep track of such loops). If a hit occurs, the score (S0) is updated and printed.
Note that when a RETURN is encountered at lines 70, 80, or 90, you must enter a zero into MSL$ to erase the old missile image. If you don't do so religiously, you'll wind up with a lot of unnecessary missiles on the screen!
These statements move players left. Look at lines 30-90 (right) for comparison.
These lines create downward motion. For this, as opposed to horizontal movement, you must use string manipulations instead of simply POKEing registers. Place the images, which move increments of three, into T0$ (or MSL$). If you want to move players or missiles in greater increments (for increased speed), add a leading and a trailing to each image for each extra step taken.
These lines mirror lines 170-230 to produce upward motion.
END-OF-GAME ROUTINE (LINES 1220-1270)
There's no time restraint, so you modify this section as much as you like. Note that line 1280 zeros the graphics-data registers for all players and missiles. If you neglect to include this line, and then type RUN after the program ends, you'll see vertical bands of player/missile "garbage" on the screen until the P/M system is enabled again at line 1470.
Feel free to experiment with this program. Since it's written entirely in BASIC, any bugs that crop up will generate error messages without locking up your computer. As you modify the game, you'll find that you'll have to make a number of trade-offs: BASIC just isn't fast enough to do everything you might want. But after studying Tank Battle, you should he able to explore many of the exciting possibilities of Player/Missile graphics on your own. Many of these possibilities can be explored in BASIC; a knowledge of machine language is not required to have fun with Player/Missle graphics.
Fred Pinho is a biochemical reseach engineer and a self-taught programmer who is interested in BASIC and assemby language. The Atari 800 is his first computer.