Use Basic to Animate
An easier way to program your own games
By Fred Pinho
This article, the first in a two-part series, shows you how to control Player/Missile graphics from BASIC. The accompanying BASIC program is a four-player, tank-battle game. It requires a minimum of 32K ram. XL owners should modify the program as specified below. For an introduction to Player/Missile graphics, see "Player/Missile Tutorial" by Chris Chabris (Antic, p.14, September 1983). Part Two will appear next month.This tutorial was inspired by a plea from a desperate reader Despite having read numerous magazine articles about Player/Missile (P/M) graphics, he hasn't been able to fulfill his desire: to write a tank-warfare game that uses four tanks on the screen. More importantly, he needs to learn a simple method, via BASIC, to move players and fire missiles horizontally.
Alas, it's not that simple. BASIC knows little or nothing of the P/M system, so it's not easy to control P/M graphics with BASIC. The programmer must keep track of all important registers, and must write a program to move players around on the screen. The horizontal movement of a player can be accomplished with relative ease by means of a single POKE, but vertical motion is much more complex.
You must relocate data bytes in memory to move a player vertically. And to make things even more confusing, if you move data upwards in memory, your player moves downward on the screen. As a result of these factors, vertical motion from BASIC is almost always excruciatingly slow.
You can achieve rapid player motion with machine language. However, most BASIC programmers aren't familiar enough with machine language to accomplish this.
Now for the good news. There is a way to do a passable job of achieving vertical player motion through BASIC, if you use some specialized tricks. But because of the speed problem, you'll have to keep your game fairly simple.
The accompanying program is a simple, four-player tank game. Each player is controlled by a separate joystick (one each in Ports 1 to 4). You can fire vertically and horizontally. To prevent random firing, each tank is limited to 30 shells. The first tank to hit its opponents 10 times wins. Only the score is displayed; you have to keep track of how many shots you've fired. There's a "reload" time of two to three seconds between each shot, during which you must maneuver for safety You can only fire while moving, and you cannot move or fire diagonally.
For XL Owners Only
Since Atari XL machines have only two joystick ports, you cannot play Tank Battle as a four-player game. As a result, you must disable two of the tanks. The simplest way to do this is to delete lines 1170 and 1180. If you follow the program logic, this may seem to be illogical, since it eliminates the instructions for Players 1 and 2, not Players 2 and 3. (The Antic staff tried eliminating the instructions for Players 2 and 3, but when we did so the remaining tanks wouldn't fire.)
Modifying the Game
You can add features such as diagonal movement/firing and the ability to keep track of the number of shots fired without too much trouble. However, each feature you add will slow down the game. You can then move tanks and missiles in greater increments to compensate for the lack of speed, but their motion will appear "jerky" and problems with collision detection will be introduced. The choice is up to you, the programmer.The game isn't as smooth as it would be if it were coded in machine language. However, within BASIC's limits, it's fast enough to result in a playable game.
P/M System Paramaters
To help you set up housekeeping for the P/M system, I've listed all of the important registers and their functions in Table 1. Note that some of the registers have two different meanings, depending on whether you're reading (with a PEEK) or writing (with a POKE) to them. For instance, you can POKE player 0's horizontal position into location 53248. But you can't check its position by PEEKing 53248. When PEEKed, that register functions as a collision register for player 0 missiles. Table 1 indicates whether a register is read only, write only, or both.
Programmung the P/M System
This section describes, in order, the registers that you must use to set up a Player/Missile system.
Vertical Player Resolution
See Table 1, Item 15. A player can be drawn in either of two resolutions. Single-line resolution provides high resolution, equivalent to that of Graphics 8, but uses more memory (2K). Double-line resolution, which is equivalent to that of Graphics 7, uses only IK.
Storage of PM data
See Table 1, Item 14. Examine Figure 1, which shows the organization of memory for P/M data. Note that a block of memory that is safe from other activities must be reserved. My program places data below the display list, as shown in Figure 1. If you store your data here, be careful not to let the BASIC program move into the P/M data area. In Figure 1, note that each player has its own memory space, but that the missiles are lumped together in a common area. Each player is eight-bits wide, but the missiles are only two-bits wide. Thus, each byte contains data for all four missiles. To put a missile on the screen, POKE these numbers into the missile data area:
HALF-WIDTH FULL-WIDTH MISSILE# MISSILE MISSILE 0 1 or 2 3 1 4 or 8 12 2 16 or 32 48 3 64 or 128 192Data for one missile is independent of that for other missiles. You can, for instance, POKE a three into one byte for missile 0 and 12 into another byte for missile 1. Since the bytes are different, each missile appears at a different vertical location on the screen. Each missile also has its own horizontal-position register, so you have complete control over its movement.
Table 2 shows you where to store P/M data for each graphics mode, while taking certain restrictions into account. The first of these is the actual amount of memory required (2K for single-line resolution, 1K for double-line resolution). The second is that the block of memory must start on a 2K boundary for single-line resolution, and on a 1K boundary for double-line resolution. This means that the address of the start of P/M memory must be exactly divisible by 1024 (1K boundary) or 2048 (2K boundary). If you don't place P/M data on the proper boundary, the system won't work correctly.
TABLE 1 PLAYER/MISSILE REGISTERS LOCATION(S) FUNCTION COMMENTS POKE and PEEK -------------- ----------------------------------- ----------------------------- ------------- 1) 53248-53251 Horizontal-position registers for POKE values of 0 to 255. Only POKE only players 0 to 3 values of about 48-208 are visible on the screen. 2) 53252-53255 Horizontal-position registers for same. POKE only missiles 0 to 3 3) 53256-53259 Size registers for players 0 to 3 See Note 1 POKE only 4) 53260 Size registers for players 0 to 3 See Note 2 POKE only 5) 53248-53251 Collision registers between See Note 3 PEEK only missiles and playfield graphics. Missiles 0 to 3 6) 53252-53255 Collision registers between See Note 4 PEEK only players and playfield graphics. Players 0 to 3 7) 53256-53259 Collision registers between See Note 5 PEEK only missiles and players. Missiles 0 to 3 8) 53260-53263 Colision registers between players. See Note 6 PEEK only Players 0 to 3 9) 53278 Used to clear all collision registers POKE any number but zero to POKE only clear register. See Note 7 10) 53261-53264 Graphics-data registers for Used by the computer to disply POKE only players 0 to 3 P/M data, Not normally used by programmers. 11) 53265 Graphics-data register for all Same POKE only missiles 12) 704-707 Color registers for players 0 to 3 Missile has same color as its Both and associated missile player. Must POKE color value into register. See Note 8. 13) 623 Priority register See Note 9 Both 14) 54279 PMBASE. Page number of start of Both Player/Missile memory area 15) 559 DMA control. Specifies type of See Note 10 Both P/M resolution and whether the screen is turned on or off. 16) 53277 Graphics control. Enables the POKE zero to dissable P/M system. POKE only Player/Missile system POKE 3 to enable P/M. Notes1. Player-Size Register
Value to POKE Size 0,2 Normal Width 1 Double Width 3 Quadruple WidthThe default (normal) register value is zero. Only the width, not the height, is affected.
2.Missile-Size Register
Value to POKE for Size Missile Normal Double Quadruple 0 0 1 3 1 0 4 12 2 0 16 48 3 0 64 192Each missile's width can be controlled independently with this register.
3. Missile/Playfield Collision Registers
A planyfield object is anything drawn on the screen with PLOT and DRAWTO commands. Characters that are PRINTed to the screen are also playfield objects. The playfield's number corresponds to the COLOR command used before graphics plotting. If a collision between a missile and a playfield object occurs on screen, PEEKing these registers tells you which playfield was hit.
Value in Playfield COLOR Command Register Hit Corresponding to Playfield 1 0 1 2 1 2 4 2 3 8 3 None. Used to print in Graphics 1 and 24. Player/Playfield Collision Register
These registers are affected when a player collides with a playfield. This table is identical to the one in Note 3.
5. Missile/Player Collision Registers
These registers are affected when a player collides with a missile.
Value in Player Register Hit 1 0 2 1 4 2 8 36. Player/Playfield Collision Registers
These registers are affected by collisions between players. This table is identical to that in Note 5.
7. Collision-Clear Register
POKE this register with any value from zero to 255 to clear all of the collision registers. It's important that your program clear these registers frequently. If this isn't done, multiple collisions may result in unanticipated values that confuse your program. It's best to clear these registers just before each player or missile movement.
8. Player/Missile Color Registers
Set each player's color by POKEing the proper register with the result of this formula: COLOR = LUMINANCE + 16 * HUE
9. Priority Register
This selects the screen objects that are to be displayed "in front" of other objects. Background color always has the lowest priority.
POKE Priority Order
1 Players 0, 1, 2, 3, Playfields 0, 1, 2, 3
2 Players 0, 1, Playfields 0, 1, 2, 3, Players 2, 3
4 Playfields 0, 1, 2, 3, Players 0, 1, 2, 3
8 Playfields 0, 1, Players 0, 1, 2, 3, Playfields 2, 3
If you increase the value of the contents of the Priority Register by 32, you can combine players (0 with 1, and 2 with 3) to form multicolored players'.
10. Direct-Memory-Access (DMA) Control Registers
This register controls the screen and Player/Missile display as follows:
Add to Final Option Value for POKE Comments Narrow Playfield 1 Choose Standard Playfield 2 only Wide Playfield 3 one Enable-Missile DMA 4 Enable-Player DMA 8 Double-Line Player Resolution 0 Default value Single-Line Player Resolution 16 Regular-Graphics DMA 32The default (normal) value for this register is 34 (regular graphics, standard playfield, P/M not enabled). POKE 559,0 to turn off the screen and speed processing time by up to 30 percent (for fast initialization).
Table 2 Locating P/M Data Beneath the Display List Graphics Locate PMBASE at indicated Offset Mode (in pages) below RAMTOP Double-line Single-line Resolution Resolution 0 8 16 1 8 16 2 8 16 3 8 16 4 8 16 5 12 16 6 16 24 7 24 32 8-11 36 40PMBASE is the location in memory of the start of P/M data. Store the page number (address/256) of PMBASE in location 54279. RAMTOP, in location 106, holds the number of pages of RAM in the machine. Let's pick Graphics 5. We code the following:
PM = PEEK(106)-16:POKE 54279, PM
So far, we've covered some of the registers listed in table 1. I'll describe the remaining registers, and provide a detailed program description next month.
Listing: PMTANKS.BAS Download
Fred Pinho is a biochemical research engineer and a self-taught programmer who is interested in BASIC and assembly language. The Atari 800 is his first computer.