Classic Computer Magazine Archive COMPUTE! ISSUE 86 / JULY 1987 / PAGE 60

P/M Magic

Gary Costanza

"P/M Magic" is a complete tool for the Atari BASIC programmer who wishes to use Player /Missile (P/M) graphics. It's a machine language program that enables fast movement and animation of both players and missiles from BASIC. With this system, you can create arcade-quality graphics and animation without being a machine language expert.

"P/M Magic" is designed to handle all the aspects of arcade graphics that BASIC can't handle. And because it runs as a background task, during the computer's vertical blank interrupt, P/M Magic is invisible to BASIC, doing its work without slowing down BASIC operations. Here are some of the features that P/M Magic provides:

  • High-speed animation of two players
  • Eight-direction missile firing logic for two players
  • Player and missile movement limits
  • Missile collision detection and automatic missile reset
  • Two players control with one joystick
  • Multicolored, double-width, or shadowed players
  • Detailed and realistic explosions
  • Variable speed for players and missiles
  • Works with any graphics mode, in one- or two-line resolution

Typing In P/M Magic

To show what P/M Magic can do, this article includes three demonstration programs. Before you can use any of them, you must type in Program 1 and LIST it to disk or tape. This program is a loader which puts all of the P/M Magic machine language routines in memory. It's important to use LIST instead of SAVE when saving Program 1, because you will later need to use ENTER to merge it with the three demonstration programs. Don't try to run Program 1; it isn't designed to be a stand-alone program—it's a subroutine to load the P/M Magic routines into memory.

After you enter Program 1 and LIST it to disk, type in and save Programs 2–4. The lines from Program 1 must be merged with each of these programs in order for them to work. Thus, to run Program 2, you would load Program 2, then ENTER Program 1 to merge its code with the program lines already in memory. When that step is complete, run the program. For example, if you saved Program 2 on disk with the name DEMO1 and Program 1 with the name PMMAGIC, then the steps for running Program 2 would be as follows:

LOAD "D:DEMO1" ENTER "D:PMMAGIC" RUN

The same process is used for Programs 3 and 4. If you like, the complete, merged versions of Programs 2–4 can be saved for future use.

This will eliminate the step of having to ENTER the lines from Program 1 each time.

We'll discuss each demonstration program in detail later in this article. In order to understand them fully, however, you should first note a few facts about the way that P/M Magic uses the computer's memory. This information is vital if you wish to use this utility in your own programs.

Memory Management

As noted earlier, P/M Magic works in the background, allowing you to run BASIC programs while it is active. To communicate with P/M Magic, you must place information somewhere in memory where the utility can find it. P/M Magic uses most of memory page 6 (locations 1536–1699) for this communication. By PEEKing or POKEing certain locations in page 6, you can tell P/M Magic exactly what you want done. The locations and their usage are detailed in Figure 1 and in the table.

P/M Magic resides at the high end of RAM and requires 4K (4096 bytes) of memory. To protect this memory area, you should perform POKE 106,PEEK(106)–16 before POKEing the machine language into memory. That statement moves the computer's RAMTOP pointer 4K lower in memory, making the computer think it has 4K of memory less than it actually has.

As shown in Figure 1, this 4K memory block will hold three things: the P/M Magic machine language program itself, data which the program uses for player animation, and P/M RAM. The program itself occupies about 1.5K and starts at the beginning of the 4K block. The animation data area begins 1.5K higher in memory (point A in Figure 1). The amount of memory available in this zone depends on the P/M resolution, which is 1280 bytes for one-line resolution and 1920 bytes for two-line resolution. The P/M RAM area starts at either point B or C, using eight 2K for one-line resolution and IK pages for two-line resolution. Since a certain amount of P/M RAM is unused (the first 384–768 bytes, depending on resolution), it is used for animation data storage.

Figure 1: P/M Magic Memory Usage

Running The Demos

With that information in mind, let's examine the demonstration programs. Note that all of them begin by performing some setup tasks. The screen appears blank during this process, which takes about one minute.

Program 2 demonstrates several basic features of P/M Magic. After a delay of about one minute, it displays a helicopter-shaped player on the screen, complete with a realistic shadow. Plug a joystick into port 1, and you will be able to move the helicopter in any of eight directions (up, up and left, left, and so on). Notice that the helicopter has definite horizontal and vertical limits; when you reach the edge of the screen, it simply stops moving.

Line 10 of Program 2 reserves 4K of memory for the purposes explained above. In line 20, RAMTOP is the first address of our reserved 4K block, which is used to call the P/M Magic machine code. Lines 30 and 40 both compute the address where P/M RAM begins and POKE it into the P/M hardware register, telling the computer where that zone is located. Lines 60 and 62 compute the address where our P/M data begins.

Lines 70 and 75 set up a GRAPHICS 0 screen and temporarily turn off the screen to make the computer run a bit faster. Note that you always should perform a GRAPHICS statement after modifying the RAMTOP pointer (as in line 10); that action causes the computer to set up its display list and screen below the new location of RAMTOP, protecting your reserved memory area.

Important Memory Locations

1536 Player 0 animation; POKE with frame number
1537 Player 1 animation
1540 POKE with 1 to disable Missile 0
1541 POKE with 1 to disable Missile 1 1542 Missile 0's X offset from Player 0
1543 Missile 0's Y offset from Player 0
1544 Missile 1's X offset from Player 1
1545 Missile 1's Y offset from Player 1 1546–47 Player 0's left limit; Player 0's left limits plus 1
1548–49 Player 0's right limit
1550–51 Player 0's top limit
1552–53 Player 0's bottom limit
1554–55 Player 1's left limit
1556–57 Player 1's right limit
1558–59 Player l's top limit
1560–61 Player l's bottom limit
1562–63 both missiles' left limit
1564–65 both missiles' right limit
1566–67 both missiles' top limit
1568–69 both missiles' bottom limit
1570 POKE with 1 to allow Player 1 to be program-controlled
1587 X position of Player 0
1588 Y position of Player 0
1589 X position ol Player 1
1590 Y position of Player 1
1591 X position of Missile 0
1592 Y position of Missile 0
1593 X position of Missile 1
1594 Y position of Missile 1
1600 Player 1ís change in X position; use when under program control (POKE with 0, 1, 2, 3, 255, 254, or 253)
1601 Player Is change in Y position
1610–1625 players' horizontal speed
1626–1641 players' vertical speed
1642–1657 missiles' horizontal speed
1658–1673 missiles' vertical speed
1674 POKE with 1 to stop Player 0
1684 Missile 0 to Playfield 0; collisions—POKE with 1 to enable
1685 M0 to PF 1
1686 M0 to PF 2
1687 M0 to PF 3
1688 Ml to PF 0
1689 Ml to PF 1
1690 Ml to PF 2
1691 Ml to PF 3
1692 M0 to Player 0
1693 M0 to PI
1694 M0 to P2
1695 M0 to P3
1696 Ml to P0
1697 Ml to P1
1698 Ml to P2
1699 Ml to P3
1744 POKE with 1 to disable P/M Magic

Player Data

Line 80 calls the subroutine that POKEs the P/M data into the area defined in line 62. In this case, each DATA line containing the P/M data consists of 14 numbers, which contain pixel data for each of the 14 lines in the player shape (see Figure 2).

This particular player is 14 bytes tall, so each 14-item DATA line represents an entire player shape. Once these shapes have been stored in memory, we can display any shape at will, or flip through an entire series for animation. In effect, each 14-byte data set is one "frame" of an animated series. To switch to a new shape, POKE its frame number into location 1536 (for player 0) or 1537 (for player 1). Frame numbers correspond to the position of the data sets in memory. For instance, the data in lines 9010, 9020, and 9030 represents frames 0, 1, and 2, respectively, and so on. Frame 0 (in line 9010) contains all zero values; it can be used to erase either player.

Notice that every player data set must have a "cushion" of two extra zeros both at the top and at the bottom of the shape (see Figure 2). This cushion is counted as part of the player's height and is necessary for P/M Magic to function.

Line 90 of Program 2 calls a routine that POKEs some important information into the page six storage area (Figure 1). P/M Magic allows you to set horizontal and vertical movement limits for both players and missiles. Locations 1546–1569 contain these limits, but you'll notice that two locations are provided for each limit. Simply make the second number one larger than the first, as shown in line 10010. Horizontal limits can be anything in the range 0–228, while vertical limits can range from 0–191 for one-line resolution or 0–95 for two-line resolution. The extreme upper left corner of the screen is represented by coordinate 0,0.

Locations 1610–1673 determine player and missile speed, and are divided into four 16-byte sections. To change the speed of any of these sections, simply change the values they contain. Two speeds are possible. For normal speed, the sections should contain 0, 1, and 255 values in the order shown in lines 10040–10060 of Program 2. For fast speed, change every 1 in those lines to 2, and change every 255 to 254 (leave the 0 values unchanged).

Line 100 calls the routine (from Program 1) that POKEs the P/M machine code into memory. Line 120 disables missiles 0 and 1 and sets the colors for player 0 and the background. Line 122 turns on players and missiles and clears the P/M Magic disable flag. Line 123 clears all of P/M RAM and then, since the setup is complete, turns the screen back on.

At this point, we are ready to enable P/M Magic, a task that is done with USR. Here is the general form for the USR statement:

X = USR(RAMTOP,P0X,P0Y,P1X,P1Y, HEIGHT,FLAG,RESOLUTION)

Here is an explanation of the values you must supply in the USR statement:

RAMTOP start address of P/M Magic
POX X position of player 0
P0Y Y position of player 0
P1X X position of player 1
P1Y Y position of player 1
HEIGHT height of taller player; add zeroes to bring the shorter player up to this height FLAG set flag to allow one joystick to control two players
RESOLUTION 1 for one-line, 2 for two-line

Once P/M Magic is enabled, a number of interesting effects are possible. For instance, the first two demonstration programs take advantage of the feature that lets you control two players with one joystick. In the first example, the players are arranged vertically to create a shadow under the helicopter. In the second case, the players are placed side by side to create an extra-wide walking figure. By overlapping two players, you can create the appearance of a player with three colors.

Locations 1562–1569 define the limits of a missile's travel. When it exceeds these bounds, it is reset automatically. Locations 1542–1545 define the missiles' offsets from their respective players; when a missile is unfired, these offsets center a missile underneath its player, making it invisible.

The final demonstration program moves player 1 under program control. Locations 1600–1601 control the player's speed and direction, using the same scheme described earlier for locations 1610–1673.

Location 1693 is used to detect collisions between missile 0 and player 1. To enable detection, POKE a 1 into this address. When this type of collision occurs, P/M Magic first checks location 1693 to see whether detection is enabled, then resets the missile and stores a zero in the same location. After detecting a collision—with PEEK (1693)—you should store a 1 in this address as soon as you want to detect collisions again.

Avoid using the GRAPHICS statement or executing PRINT "{CLEAR}", or the equivalent PRINT CHR$(125), after P/M Magic is enabled. Any of these activities can clear the RAM above the RAM-TOP pointer, where P/M Magic resides. If you must perform one of those commands, disable P/M Magic with POKE 1744,1; then reinstall the P/M Magic machine code and activate it with USR.

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