Atariplayermisslegraphicsinbasic
Atariplayermisslegraphicsinbasic
Philip C. Seyer
Seyer, Philip C.
Atari player missile graphics in BASIC.
10 9 8 7 6 5 4 3 2 1
Special thanks go to my eleven year old son, Dan Seyer, who helped design
the game in Chapter 11 . Dan also came up with several programming sugges-
tions, including a clever way to handle "collision detection."
Thanks go to game programmer, Robert Sombrio for his innovative joy-
stick reading routine . And thanks to Datasoft Inc., for their Graphics Master
program, which was helpful in preparing some of the graphics for this book.
Likewise, thanks to Robert Martin for his MMG BASIC Debugger, which
proved quite helpful in preparing the programs in this book.
Thanks, too, to the people at Atari, Inc. for their help in answering techni-
cal questions and supplying supportive instructional documents.
Last, but not least, I would like to thank the people at Reston Publishing
Company who helped put this book together, especially: Nikki Hardin, Senior
Editor; Nanette T. Edwards and Camelia Townsend, Production Editors; AI
Pagan, cover artist.
vii
Preface
ix
-
-.
Contents
xi
xii I Contents
Chapter 8: Missiles, 89
Defining the Missile Image, 89
Horizontal Position Register, 92
Revising the Main Loop, 92
Building a Missile Move Routine, 93
Error Routine, 101
Missile Size Register, 103
Complete Listing, 105
Contents / x iii
DMACTL, 156
Sample Program, 157
Appendix, 163
ATARI® Player-Missile Graphics
Introducing PMG
Surprise! .Atari has a secret feature that sets it apart from most other personal
computers. It's called Player-Missile Graphics (PMG for short). With PMG you
can create all sorts of special graphic effects-effects that wou ld be extremely
difficult. if not impossible, with an Apple , IBM, or TRS-80.
EXTRA COLORS
You can make your "bab ies" any color you want. These images (or "players,"
as Atari calls them) are independent of the usual screen images. Let's say you
are using what is ca lled "graphics mode 5." Normally, with thi s mode, you are
'limited to four colors. But with PMG you can have up to nine colors, because
each player can be a different co lor.
2 / Introducing PMG
THREE-DIMENSIONAL EFFECTS
PMG lets you simulate 3-D. Because players are independent of the other screen
images, they can be set to hide behind (or go in front of) other objects. Also, it's
really easy to change the size of a player and to make a player look like it is
moving from a distant location into the foreground. Atari uses this technique
effectively in STAR RAIDERS to animate the attacking spacecrafts. So can you!
ANIMATION
PMG greatly simplifies animation. With PMG you can move players quickly and
smoothly with just a few commands. At the same time you can simultaneously
create sound effects and carry out other processing. That's because PMG is
controlled by two extra microprocessors called ANTIC and CTIA (or GTIA).
• Design the graphic images you want to display. Then calculate the
data needed in memory to produce these images.
• Allocate space in memory for PMG.
• Dimension strings that will hold player image data.
• Set the PMG memory to zero data .
• Read the player image into the player image strings.
• Set the color of the players.
• Tell Atari where the PMG memory starts.
• Tell Atari whether you want single- or double-line resolution.
• Turn on PMG.
• Set the initial position coordinates for players and missiles.
• Animate the players and missiles as desired.
These are the basic things you 'll need to get started . I'll cover them first.
Then after you've mastered them I'll show you some advanced programming
tricks you can amaze your friends with. "How did you do thatT they'll say.
Now, let's get started with the first task-designing player images.
Designing
Player Images
In this chapter you'll learn how to design an original graphic image that you
can animate using Atari's special PMG features . We'll call this image a "player"
to distinguish it from other graphic objects that may appear on the screen.
Specifically, when you finish this chapter, you'll be able to:
Let's begin by taking a look at the way graphic images are stored in
memory.
5
6 / Designing Player Images
~-----------------------------------~
I
i
I
Ii
• ~-PTXEI
~.-
I
-
Ii
i
If you'd like to see what a pixe l actually looks like in different modes,
trying running this program :
As you may know, all data in random access memory (RAM) is stored in
consecutive memory locations called bits. (Eight consecutive bits are called a
. byte.) Each bit contains either a one or a zero.
One- and Two-Dimensional Images / 7
A certain part of RAM is used to hold data that will be used to display
screen images. Let's call that screen RAM . If a bit in screen RAM is set to one,
then the corresponding screen pixel will light up. If a bit is a zero, then the pixel
will be turned off.
• Suppose a byte (eight bits) contains these values : 00011000. Which of these
diagrams correctly shows the screen image that would be displayed by
that byte?
A.-
B. _
c.
ANSWER
A (Remember that each bit set to one causes the corresponding screen
pixel to be illuminated.)
....IL+<-E-- LINE 2
. - . or;: LINE 3
lot of calculating to figure out which bits in RAM to set to one. Why? Well, RAM
is linear; it consists of a series of bytes laid end to end . It is one-dimensional.
R A H
ONE DIMENSION )
VERTICAL
HOP.IZO~THL
all this. They arranged for the second byte in PM memory to be displayed
directly under the image of the first byte. Similarly. the third byte is displayed
directly under the image of the second byte, and so on. This way the data for
an image can be stored in consecutive bytes in RAM as illustrated here:
Of course, before you put any data into those consecutive bytes, you
need to know exactly what image you wa nt to create. So let's go over the
procedure for designing a player image.
First. layout a grid that is 8 columns wide with as many rows as you like up to
128. For example, you might start with a grid that has 8 columns and 11 rows,
like this:
Designing A Player Image / 9
• In this example, how many pixels are lit up to draw the character's neck?
ANSWER
Just one.
10 / Designing Player Images
LIGHTING UP PIXELS
The next step is to figure out which bits in memory to set to one so the proper
pixels are turned on. This is really quite simple. All we do is convert each row in
our grid to a number..
To do that we look at each square in our grid. If the square is shaded in,
we write down a "one." If the square is not shaded, we write down a zero. For
example, we wou ld convert the first row of our player like this :
;
~----~--~.--~~--~~
00011100
• I did the first row; now you try the second and third . Convert them into
binary numbers.
Ughting Up Pixels / 11
00011100
ANSWER
00011100 (row 2)
00001000 (row 3)
00011100
00011100
00001000
12 / Designing Player Images
ANSWER
a. 00011100 g. 00011000
b. 00011100 h. 00101000
c. 00001000 i. 01001100
d . 00011100 j. 01000100
e. 00111010 k. 01000100
f. 01011001
Now we have all of the binary numbers needed for our player image. But
before we can put these values into Atari's memory, we need to convert them
into decimal numbers. That's because BASIC was designed for inputing dec-
imal numbers, not binary ones.
If you already know what decimal and binary numbers are and how to
convert from binary to decimal, you can skip ahead to "Converting the Image
to Decimal Numbers." Otherwise, read on and I'll explain.
Decimal numbers are the kind used by most normal people (You know
what I mean-people who aren't assembly language programmers). The word
part "dec" means " ten" . For example, a decade is a period of ten years. The
decimal number system contains ten different number symbols, which are:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Similarly. the word part "bi" means "two." For example, bimonthly
means "every two months ." Binoculars are field glasses designed for use by
two eyes. The binary number system uses only two kinds of number symbols:
I's and O's.
Let's look at some binary numbers. To keep things simple, we'll start out
with small binary numbers and put each number symbol in a box.
r
L
A "1" in this box
represents a decimal
"2",
/ \
A " 1" in this box
represents a decima l
"1".
Ughting Up Pixels / 13
1.10
I
ANSWER
2 (2+0=2)
Now let's try a binary number with three number symbols. Again, we'll
put each symbol in a box. This time, above each box, we'll show what the box
is worth in decimal if it has a "1" in it.
1
11.
I
:
: Ii!
L __ --1.
!
i 1. 1.
1
i
i
!
1
I
j
/
A " 1" in this box
represents 4.
• Got that? Let's see. Give me the decimal equivalent of each of these binary
numbers :
11.11.101
1011.11.1
1011.101
14 / Designing Player Images
ANSWER
6(4+2), 3(2+1), 2
• Let's take away the boxes. What is the decimal equivalent of each of these
binary numbers?
a, 101
b. 010
c. 001
d, III
ANSWER
a. 5 b, 2 c. I d. 7
Now let's look at an eight-position binary number. We'll put the digits in
boxes again to help you visua lize the number.
,
ij
i i "
• .1 ..1 ,i .1 ,
11111t IJ.I'..L ,
i
!
i
i
.
_ 'I
I
I
j
1
I ! :i
!
.
1
1
128+64+32+16+8+4+2+1=255
• Now, you try one. How much is thi s in decimal? (Hint: compare this one
with the previous binary number,)
ANSWER
253 (It isjust two less than the previous example. Notice we now have a
"0" in the "2 box" instead of a"/."
o 0011101J.loo. ! i i i !
// 16+4 = _ __
ANSWER
20
10IolJ.I~JI.110 0 0
II i
i
II !: I !
.--1..'_ _-,-I_ _~_-''--_ _
ANSWER
40 (32+8=40)
• Here's the image we worked on ea rlier. I've do ne the first three rows for
you . Try the rest if yo u like:
ANSWER
a. 28 g. 24
b. 28 h. 40
c. 8 i. 76
d. 28 j. 68
e. 58 k. 68
f. 89
MORE PRACTICE
• Give the decimal numbers for creating this shape:
a. _ _
:= b. _ _
C. _ _
= d.
8.
- f.
- g.
=h. _ _
- _ . _- _ . _ - - - -
More Practice / 17
ANSWER
a. 60132+16+8+4)
b. 124 164 more than the previous row)
c. 116 11 24-8)
d. 127 13 more than row 2)
e. 124 Isa me as row 2)
f. 11211 2 less than row 5)
g. 124 Isa me as row 2)
h. 96 164+32)
Congratulations. You can now design yo ur own player image and calcu-
late the decimal numbers needed for it. Next. yo u lea rn how to re seNe memory
for your player-miss ile image data.
Dimensioning Strings
for PMG
In this chapter you'll learn an important secret- one not revea led in most other
books and articles on PMG. * The secret is to use strings to store PM (Player-
Missile) data . [If you don't know w hat a string is or how to dimension it, I
suggest you see Inside ATARI BASIC by William Carris (Reston, Va .: Reston
Publishing Company, Inc., 1982J
Why is this such a big deal? Because (as I mentioned earlier) Atari has the
ability to move string data super fa st. So by using strings you can achieve fast
vertical animation w ithout resorting to machine language! Without using
strings, vertical movement in BASIC is slow and Jerky.
'I'd like to thank Sheldon Leemon for his excellent article on how to use strings for fast PMG
animation: " Take Apart: Outer Space Attack," Softside Magazine, March 1982.
19
20 / Dimensioning Strings for PMG
PLAYER 3
PLAYER 2
PLAYER 1. ! 128 BYTES
PLAYER 0
H3 I H2 I H1 I HO
Note that this diagram shows the PM memory organization for what is
called double-line resolution . Double-line resolution simply means that two
lines are used to display each byte in PM memory. That is, if a bit is set to "1,"
then two pixels (one underneath the other) are lit up. We'll talk about double-
line resolution in more detail later. Just remember that this diagram is for
double-line resolution. Later we'll discuss single-line resolution (see Chapter 9).
1. How big is the buffer area at the beginning of the PM memory area?
2. In double-line resolution, how many bytes are set aside for each
player?
lK Boundary / 21
ANSWER
1. 384 2. 128 3. a
One important rule, then , is that when using double-line resolution, you
must have a 384-byte buffer at the beginning of the PM memory area. This
buffer area is not used to turn on screen pixels. That is, if a bit is set to "1" in this
area, there will be no direct effect on what is displayed on the screen. That's
why we say the actual PM display area starts 384 bytes after the beginning of
the PM memory area.
Another important rule is that when you are using double-line resolution ,
the PM memory area must start on w hat is called a "IK boundary." If you know
w hat I mean by "IK boundary," yo u ca n sk ip to "Starting on a lK Boundary. "
Otherwise, read on and I'll explain.
lKBOUNDARY
Al K boundary is simply a location in memory that can be divided evenly by 1K
(1 K = 1024 bytes). For example, 2048 is on a 1K boundary because 1024 goes into
2048 evenly two times.
ANSWER
a and c 11 024 goes into 4096 evenly four times. 1024 goes into 3072 evenly
three times).
22 / Dimensioning Strings for PMG
STARTING ON A lK BOUNDARY
To get your Player-Missile Base Register (PMBASE) to start on a 1K boundary,
you need to do some calculations . That's because the first string you define
won 't automatically start at any given point in memory. There are different
ways to find a 1K .boundary. The method I recommend is to dimension some
"filler strings" to take up space until the 1K boundary is reached. Here is some
code you can use to define these "filler" strings. Take a moment to look it over.
DIM FILLER1$(1),
FI LLER2$( (I NT(ADR(FI LLER1 $)/1 024)+1)
*1024-ADR$(D$)-1 )
Note: When typing this code into your computer, you would normally
enter it as one continuous line. I've broken it into separate lines here to make it
easier to read.
You don't really need to understand this filler code. All you need to know
is that it takes up string memory until a 1K boundary is reached. But, if you like,
I'll explain; otherwise, you can skip ahead to "Setting Up PM Memory."
10 DIM FILLER1$(1)
20 BOUNDARY = INT(ADR(FILLER1 $) / 1024+1 )*1 024
30 LENGTHFILLER2 = (BOUNDARY-ADR(D$)-1
40 DIM FILLER2$(LENGTHFILLER2)
Let's examine this code line by line, starting with line 10:
10 DIMFILLER1$(1)
In line 10 we define our first filler string, which we call FILLER1S. We do this so
we have a reference point, to know where the beginning of string memory
starts.
adding 1 and throwing away the remainder. Then we multiply that answer by
1024. (INT "throws away the remainder." ADR gives us the address of FILLERI S.)
Let's apply this code to a simple example. Suppose the address of
FILLER1S is 2040. We divide 2040 by 1024 and get 1.992. We add 1 to 1.992 and
get 2.992. We throwaway the remainder (.992) and get 2. Then we multiply 2
by 1024 to get 2048, which is the 1K boundary above 2024.
30 LENGTHFILLER2 = (BOUNDARY-ADR(D$)-1)
2049
'.. .1.-..
FILLER2$
7 BYTES
.t.
"'1'"
t
'I"
FILLER.1$ .1K BOUNDARY
(.1 BYTE) (2048)
• Suppose that the address of FILLER1S were 2030. What would the proper
string length be for FILLER2S?
ANSWER
17 (2048-2030-1 =17)
This finishes our explanation of the filler code. Now let's go on to the
next step.
24 / Dimensioning Strings for PMG
SETTING UP PM MEMORY
After dimensioning the filler strings, the next step is to allocate space for the PM
memory by dimensioning additional strings, Let's look aga in at the way PM
memory is organized so you can see what PM strings will be needed:
PLAYER 3
PLAYER 2
PLAYER 1. 1 .128 BVTES
PLAYER 0
H3 I H2 I H.1 ~ He
• Based on this diagram, which string do you think we should define first?
a, BUFFERS
b, MISSILESS
c. PLAYEROS
ANSWER
a, BUFFERS
It's important to determine the BUFFERS string immediately after the filler
strings, That way the buffer wi ll start on a 1K boundary, For examp le:
10 DIM FILLER1$(1),
FILLER2$((INT(ADR(A$)/1024+1 )
*1024-ADR(FI LLER1 $)-1)
20 DIM BUFFER$(384)
Player Numbering / 25
ANSWER
It's not finished because we still need to dimension strings for the miss iles
and players.
In doing this, we use one string for all of the missiles and a separate string
for each of the players.
20 DIM BUFFERS(384)
ANSWER
Of course, you could use different variable names, such as MS for MIS-
SILESS, or POS for PLAYER1S, and so on. Also, notice that there is on ly one string
defined for all four missiles.
PLAYER NUMBERING
Notice that the players are numbered from zero to three. Does that seem a little
strange to you? (It does to me!) Actually, you can name the players any way
you want to. This kind of naming convention is often used by assembly lan-
guage programmers. It really means that PLAYERO starts 0 bytes from the
beginning of the player area. Similarly. the name "PLAYER1" means that the
player is located 1* 128 or 128 bytes from the beginning of the player area.
Similarly, PLAYER2 is located 2*128 or 256 bytes from the beginning of the
player area.
That's quite a mouthful I know. Let's see if I got the message across:
• Suppose you know that the beginning of the player memory area starts on
byte 4480. Where wou ld PLAYERI start?
ANSWER
• Again, assuming the player memory area starts on byte 4480, where
would PLAYER3 start in memory?
ANSWER
4864 (4480+3*128=4864)
You now know how to allocate space for the PM memory area using
double-line resolution . Later you'll learn how to do a similar setup for single-
line resolution. That will be easy since you've already learned the fundamental
concepts involved. Now that we've defined our player image and allocated
space for PM memory, let's get a playe r on the screenl
Getting a Player
on the Screen
Now that you have designed a player and have allocated space for PMG
memory, let's see what that player looks like.
When you finish this chapter you will be able to:
To start with, let's go over the main programming tasks required to get a
player on the screen.
27
28 / Getting A Player on the Screen
9. Turn on PMG.
You have already learned to write the code for steps 1 and 2, so let's go
on to step 3.
11020 BUFFER$=CHR$(O)
11030 BU FFER$(384)=CHR$(0)
11040 BUFFER$(2)=BUFFER$
This code may seem somewhat confusing, but rest assured -it works.
Line 11020 sets the first byte of BUFFERS to zero. Line 11030 sets the 384th byte to
zero. Line 11040 says "start with the second byte of BUFFERS and set all the re-
maining bytes of BUFFERS to the first byte of BUFFERS." (I know, it's a mouthfuL)
As an aside, if you wanted to set al l of BUFFERS to some other va lue be-
sides zeros, all you need to do is to change line 11020. For examp le to set
BUFFERS so that it has nothing but "X's," change line 11020 to read:
11020 BUFFER$="X"
If you'd like to take a break from read ing, you may want to enter the
above lines and experiment with changing line 11020 to see what affect it has
on BUFFERS. If so, I suggest you start by entering these lines:
11030 BUFFER$(384)=CHR$(0)
11040 BUFFER$(2)=BUFFER$
11050 ? BUFFER$
Note that in line 11020 we set the first byte of BUFFERS to "x." In line 11 050
we print BUFFERS just to see what it contains. (The question mark is short for
"PRINT.")
After entering the lines, type "RUN." Since all of BUFFERS has been set to
'X" you will see this:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXX
11020 BUFFER$=CHR$(O)
Run the program again. This time you will see a screen full of hearts. That's
because the Atari code for a heart character is a zero.
• Think for a moment. Does the memory location of BUFFERS contain hearts
or zeros?
a. Hearts
b. Zeros
ANSWER
Note: In line 11070 I am using "ASC' to return the actual number stored in
each byte of BUFFERS rather than displaying a character
Now that we have set BUFFERS to zeros, we can use it to set the rest of
PM memory to zeros. For example, we can set the missile area to zeros like this:
MISSILES$=BUFFER$
• You try it. Assume that BUFFERS has already been set to zeros. Then, write
the statements needed to set the entire PM memory area to zeros. (Re-
member, besides BUFFERS, our PM memory area contains these strings:
MISSILESS, PLAYEROS, PLAYER1S, PLAYER2S, PLAYER3S.)
ANSWER
MISSILESS=BUFFERS:PLAYEROS=BUFFERS:
PLAYERI S=BUFFERSPLAYER2S=BUFFERS:
PLA YER3S=BUFFERS
DIM IMAGE1$
Putting the proper data into a string is a bit harder. First you need to
know how to refer to specific bytes of a string. If you alredy know how to do
that you may wish to Skip ahead to "Putting Data into IMAGE1S."
byte of the section of the string you want to refer to . The second number gives
the ending byte. For example, to refer to the first three bytes of a string called
STORAGES, we would write :
STORAGE$(J. .. 3)
FIRST LAST
BYTE BYTE
• How would you refer to bytes 5 through 9 of STORAGES?
ANSWER
STORAGES(5,9)
If you want to refer to a single byte,just list the number of that byte twice.
For example, to refer to byte 5 of STORAGES, you would write:
STORAGE$(5,5)
ANSWER
STORAGES(15.15)
FOR 1=1 to 15
This sets up the loop so that I is set to I the first time through the loop. The next
time through the loop, I will be set to 2 and so on until I is 15.
• Can you guess why we need to make 15 passes through the loop?
32 / Getting A Player on the Screen
ANSWER
Here is the complete loop for putting all 15 numbers into IMAGEI $:
Let's look at each statement separately. We've already discussed "FOR 1=15."
The next statement is "READ A."
READ A This simply gets a number contained in a data statement and puts it
in variable A.
This means set the first byte of IMAGEI$ to the contents of variable A. The
second time through the loop, I will be set to 2. So the statement will be
equivalent to:
I MAGE1 $(2,2)=CHR$(A)
ANSWER
Now let's talk about CHR$(A). We need this because the variable A is
numeric. You can't put numeric data into a string directly. It has to be converted
to string data (also referred to as character data). That's what CHRS does. It
takes whatever number is in parentheses and gets the corresponding character,
which can then be stored in the string.
IMAGE1$=A
Main Programming Tasks / 33
ANSWER
Actually Atari' s syntax checking feature won't even let us enter a statement
like this. If we try to, the word "ERROR" appears, and the "K will be
displayed in inverse video showing that something else probably needs to
come after the equa l sign.
Now that we have set the PM memory area to zeros, our next step is to
specify what color we would like our player to be.
Player Location
o 704
1 705
2 706
3 707
(For your convenience these locations are also summarized in Appendix A.)
If you use graphics modes 3, 5, or 7, then you can use the following
numbers as a guide for designating you r player's color:
Color Number
Gray 0
Gold 16
Orange 32
Red 48
Pink 64
Violet 80
Purple 96
Blue 112
Blue 128
Light Blue 144
Turquoise 160
Blue-Green 176
Green 192
Yellow-Green 208
Orange-Green 224
Light Orange 240
34 / Getting A Player on the Screen
These are starting numbers. To any given number you can add an even
number from 0 to 14 to change the lightness of the color. For example, for a
light green color you might add 14 to 192 and use 206 as the color number. For
a darker green you might add, say, 4 to 192 and use 196.
ANSWER
Dark
ANSWER
62 (48+14)
You might also use 56, 58, or 60 for a light red, depending on how light a
shade you want. Notice that when yo u go beyond 62, you start moving into
pink.
POKE 704,16
ANSWER
POKE 706,80 (You might also use 82, 84, or 86 for dark violet. The lower the
number, the darker the color.)
ADR function . The ADR function gives the address of the string that follows it in
parentheses. For exa mple:
ADDRESS=ADR(STORAGE$)
After this statement is executed, the variable ADDRESS will contain the starting
address of the string area called STORAGES.
• Recall the structure of the PM memory area . What is the first string in the
PM memory area?
ANSWER
• How would you refer to the address in memory where BUFFERS starts?
ANSWER
ADR(BUFFERS)
• From what you've learned, see if you can write a statement to inform
ANTIC of the location of the PM memory area.
ANSWER
PMBASE
PMBASE=54279
then we can tell ANTIC where PM memory starts by writing a statement like
this :
36 / Getting A Player on the Screen
POKE PMBASE,ADR(BUFFER$)
Did you notice how I use the word "register' above to refer to a memory lo-
cation? (Player-Missile Base Register=location 54279.) Remember, in data pro-
cessing, a register is nothing more than a memory location dedicated to a
specific purpose. Usually we put data into a register to contro l the computer's
operation.
Specifying Resolution
Another important register is the one used to specify resolution. We touched on
resolution earlier, but now let's consider it in more detail. With PMG you have
your choice of either double- or single-line resolution. Single-line resolution
means that when ANTIC sees a "1" in PM memory it will light up a sing le pixel.
In double-line resolution, when ANTIC sees a "1" in PM memory it lights
up two pixels. Both pixels will be right underneath each other on two separate
lines (hence the name double-line resolution) Perhaps an illustration will help
clarify this. Suppose you have this binary data in PM memory:
00011100
00011100
00001000
00011100
00111010
01011001
00011000
00111100
00100100
00100100
01100110
With single-line resolution, your player will look like this:
----... .. A-
'
•
PMBASE / 37
With double-line resolution, you will get a player that looks like this:
ANSWER
• So far we have been using double-line resolution. How many bytes per
player does double-line resolution require? (Hint: look back at how we
dimensioned each player)
ANSWER
128
ANSWER
256
38 / Getting A Player on the Screen
Keep in mind that if we dimension our players for 128 bytes, then we
must use double-line resolution . We can't change to single-line resolution,
unless we change the way we dimension PM memory. Also, the filler strings
(remember them?) must be dimensioned differently because single-line resolu-
tion must start on a 2K boundary. (More on single-line resolution later.)
• We can ask for double-line resolution by poking location 559 with 46.
How would you code that?
ANSWER
POKE 559,46
Location 559 is called the direct memory access control register (DMACTL).
It is used for more than just specifying the type of resolution. We'll talk more
about DMACTL later. For now just note that you need to poke it with 46 to ask
for double-line resolution. As we did before, you cou ld use DMACTL as a
variable in place of "559. " At the beginning of the program you could write:
DMACTL = 559
• What is the other statement needed to ask for double-line resolution?
ANSWER
POKE DMACTL.46
Turning on PMG
Another important register is memory location 53277, ca lled the graphics con-
trol register (GRACTL) . You use GRACTL to "turn on" the PMG system. You
have different options here. You can turn on just players, just missiles, or players
and missiles. Here's how you do it:
• Suppose you want to use players and missiles. How do you specify this
with the GRACTL register?
PMBASE / 39
ANSWER
POKE 53277.3
GRACTL=53277
Then, to turn on PMG with both players and missiles, you could write:
POKE GRACTL,3
ANSWER
Well, we're almost there. Once you have taken care of these steps you
have completed the task of setting up PMG. Often you will need to carry out
these steps only once, so it's a good idea to put the code needed to do this into
a subroutine.
Assigning Line Numbers As a rule of thumb, I suggest you assign high
numbers to subroutines that will be performed just once or when speed is not
critical. That's because when Atari BASIC executes a subroutine, it has to search
for it sequentially, starting with the lower line numbers.
• Because the PMG setup routine will usually be done just once at the
beginning of the program, which of these line numbers do you think
would be most appropriate for it?
a. 100
b. 500
c. 11 000
ANSWER
c. 11000 (That way you will save the lower line numbers for routines
where speed is important).
40 / Getting A Player on the Screen
Once the setup routine is complete, all you need to do is say where you
want the player to appear on the screen horizontally and vertically. Let's take
the horizontal specification first. since it's the easiest. We use a set of registers
for that-the horizontal position registers for players (HPOSPO to HPOSP3).
HPOSPO
HPOSPO is the horizontal position register for player O. It is memory location
53248.
Here are the values you poke for various horizontal screen locations:
• • • • •
50
r r r r r
80 1.20 1.60 200
HORIZONTAL
COORDINATES
Check your understanding:
ANSWER
ANSWER
Often it's handy to use a variable to specify the value to be poked into the
horizontal position register. For example. you might use HI to designate the
horizontal coordinate for player 1. Then you would write:
M ore on w hy this is useful later. Let's now look at how you set the
vertica l position of a player.
Vertical Position
Atari BASIC doesn't have a vertica l position register. So specifying vertical posi-
tion can be a problem. But because we use string memory for PMG, it's easy to
specify vertica l position. First, set a variable like, say, "vert" to the desired va lue:
VERT=30
Then use a string command to set the player string to the data contained in the
player image string, like so:
PLAYERO$(VERT)=IMAGE1 $
Remember our discuss ion of how string commands work? The value in
parentheses after the string specifies the starting byte. If VERT equals, say, 30,
42 / Getting A Player on the Screen
then the data in IMAGEIS wi ll be placed in PLAYEROS starting with the 30th
byte. This has the effect of displaying our player at vertical position 30.
ANSWER
• Write the two statements needed to put player 1 at vertica l position 80. Use
the data contained in IMAGEI S. Use the variab le VERT to specify the 80th
byte of PLAYERIS.
ANSWER
VERT=80
PLAYER1S(VERT) =IMAGE1S
TRYING IT OUT
Well that's it! Now let's put this all together and get that player on the screen. A
complete program appears on the next page. Look it over briefly. Then read the
comments that follow it. For your convenience, I have listed the program so
that each line has no more than 38 characters. This way the printed listing will
match up with your screen listing.
Caution: Be careful in typing XO and YO at lines 13000 and 13010 (and
elsewhere in the program). "XO" is "X zero," not "XO." Notice the difference?
The zero is more oval shaped than the letter "0."
The zero represents player number O. "XO" contains the horizontal posi-
tion for player O. "YO" contains the vertical position for player O. Of course, you
can adopt any variable naming scheme that you want. Just be consistent.
Don't type "YO" one time and "YO" the next.
Comments on Program
This program will let you look at all the different colors that a player can be. We
have already gone over the code in detail so I wi ll just comment briefly on a
few points of interest.
Trying It Out I 43
Notice that the subroutine at line 2000 calls these additional setup
routines:
The "playfield" referred to here is simply the screen image that the player
moves around on. In this case, I have used a few PLOT and DRAWTO state-
ments to create a simple playfield. Notice that I set the graphics mode before
doing the PMG setup. This is important because once the PMG setup is done,
the graphics mode should not be changed. (Actually, you could change the
graphics mode after setting up PMG, but then you need to call the PMG setup
routine all over again.)
I won't go into the details of how to create playfields. For details on
playfield creation, you may wish to refer to Designs from Your Mind with Atari
by Tom Rowle (Reston, 1983)
LIne 2: GOTO 200 Obviously this line transfers control to line 200. But why?
Simply because we want to jump over line 3, which is really not part of the
program.
Line 200 to 240 Here is where the main "activity" in the program occurs.
Notice that I have created a loop in which successive even numbers are poked
into location 704, which is the color control register for player O.
AN ASSIGNMENT
I suggest you type the program into memory. Then save it by typing G.3. Next,
try running it. If it doesn't work, proofread your work carefully. Watch out for
typos! They are especially destructive when you are working with PMG. That's
why it's important to save the program before running it.
46 / Getting A Player on the Screen
Once the program is working, you may wish to try modifying it slightly.
That's the best way to learn. For example, you might try changing the values
following the $ETCOLOR command at line 13000. If you do, notice how this
affects the color of the playfield and the player. Or, try changing the horizontal
and vertical position of the player. You can do that by changing the values
assigned to XO and YO in the subroutine starting at line 13000. Happy hacking!
Animating Your Player
So far you have learned to design a player image and carry out the necessary
PMG setup routines needed to display it on the screen in any desired color.
After finishing this chapter you will be able to move your player around on the
screen with or without joystick control.
Animation of a player without joystick control is much easier to program,
so let's start with that first.
47
48 / Animating Your Player
• As you examine this code, see if you ca n tell which statement puts the
program into a never-ending loop.
ANSWER
The "GOTO" statement on line 230 puts the program into a never-ending
loop.
Note that because the program is looping, the horizontal and vertical
positions of the player are constantly being set. With every pass through the
loop we have the opportunity to change the player'S position. For example, to
move the player up the screen, all we need do is decrease the value in YO. We
can do this with the statement YO=YO-I. A better way, though, is to use the
statement YO=YO-SP, where SP is a variable set to " I. " This way yo u have more
flexibility. You can easily set SP to a different value and the player will move
more or less rapidly.
• Now, take a look at the code above for a moment and decide where we
need to put YO=YO-SP to make the player move up the screen.
ANSWER
To make the player move up the screen, we need to insert the statement
somewhere between lines 200 and 230. Notice that the statement must be
within the loop so that the value in YO decreases with each pass through
the loop.
Try it. Load the program you typed in from the previous chapter. (You did
type it in didn't you 7) Then make these changes:
Animation Without a Joystick / 49
Important: again, watch out that you don't confuse XO with XO. "XO" is "X
zero." Similarly, "YO" is "Y zero" not YO. Remember that a zero has a different
shape than the letter "0. "
Run the program. When yo u've got the player moving up and off the
screen, continue reading below.
Error 5 What happened when the player disappeared off the screen? You
shou ld have gotten Error 5: "String Length Exceeded. " I'll show yo u how to
handle this problem later. For now, just know that this error is to be expected
whenever your player moves too far up or down. It happens whenever YO is set
to a number less than 1 or greater than 128. That's because PLA YEROS is dimen-
sioned to 128 bytes. On line 220 we are moving data into PLAYEROS at the byte
specified by YO. Because there is no such thing as byte 0 for a string, a value of 0
in YO results in an error.
As soon as you get Error 5, try this : Print the value in YO. (Type 7 YO and
press RETURN.) You w ill notice that YO contains "0," an illegal value!
Horizontal Movement
• By now you may already know how to move the player horizontally.
Assuming that you take out line 225, what statement would you need to
put into the loop to make the player move horizontally across the screen
from right to left.?
SO/Animating Your Player
ANSWER
XO=xo-sp
Try it. First insert "REM" at the beginning of line 225 so that line 225 will
not be executed. Then insert XO=XO-SP, as line 227. When you run the program,
the player should move from right to left across the screen. Again, don't worry
about the error message that occurs when the player runs off the screen. This
time you will get Error 3: "Bad Value." The bad value this time will be a -1 in XO.
We'll handle this problem later.
Diagonal Movement
Now let's try diagonal movement. First, let's position the player at the top left
corner of the screen. We do this by changing lines 13000 and 13010 so that they
read:
13000 XO=52
13010 YO=12
For the moment also change line 230 to "GOTO 230." When you run the
program, the player will appear at the top left corner of the screen and just stay
there.
• Now let's make him run diagonally. See if you can come up with the
statements required to make that happen. The compare your code with
mine.
ANSWER
To make the player move diagonally change lines 225, 227. and 230 as
follows:
225 YO=YO+SP
227 XO=XO+SP
230 GOTO 200
Try it!
• Now here's another one. Write the statements needed to move the player
diagonally (as before). But when she reaches vertical position 45, move her
Joystick Control/51
horizontally from left to right until she reaches horizontal position 125, at
which point just have her stop, Write the necessary code in the space
provided, Then try it out and debug it as necessary, It may take a bit of
experimenting to get it to work, Finally, compare your code with mine,
ANSWER
Note: Lines 200- 227 could be combined into a single line, This would
make the player move slightly faster. But to make these programs easier to read,
I'm putting each statement on a separate line,
Well, moving a player without a joystick was fairly simple, Moving her
with a joystick is not quite so easy.
JOYSTICK CONTROL
Reading the stick is easy, For example, this statement will read joystick 0
(the one on the far left) and put a numerical value in "S:"
S=STICK(O)
Note: The place where you plug in joystick 0 is labeled "Controller Jack
1." Similarly, "Controller Jack 2" is the label forthe port forjoystick 1, and so on,
This diagram shows the various numbers that will be read into "S" when
the joystick is moved to each position,
52 / Animating Your Player
10 1.4 .6
.... 7
11. • '__.-'
'---~--~
5
1.3
• Suppose you move the joystick to the right. What will be the va lue of "5"
after the statement S=STICK(O) is executed?
ANSWER
• What is the value of "5" w hen the joystick is not moved, but left in its
J
normal resting position?
ANSWER
15
' - - - - -
You can handle the va lues put into "5" in different ways. Here's one
simple way:
S=STICK(O)
IF S=7 THEN XO=XO+SP
IF S=11 THEN XO=XO-SP
IF S=14 THEN YO=YO- SP
IF S=13 THEN YO=YO+SP
IF S=6 THEN YO=YO-SP:XO=XO+SP
IF S=10 THEN YO=YO-SP :XO=XO-SP
IF S=9 THEN YO=YO+SP:XO=XO-SP
IF S=5 THEN YO=YO+SP:XO=XO+SP
Modifying the Program / 53
This works. But look at all those IF-statements! They slow down program
execution and make it difficult to get smooth and lively animation. Actually.
you don't need to use any IF-statements at all. You don't even need the STICK
statement. *
For maximum speed, it's better to peek into memory location 632 to read
joystick 0, like this:
PEEK(632)
• Suppose you pull straight back on joystick O. What value will be in memory
location 6327 (Look at the joystick drawing if you need to.)
ANSWER
13
ANSWER
It will go to the subroutine starting at line 13 (since location 632 will contain
a 13 when the JOystick is pulled backward)
*Thanks go to that wild and wacky game programmer. Robert Sombrio. for showing me the fast
joystick read ing routine prese nted in this chapter. I tested it against a machine language subroutine
published in a major magazine. Robert's routine won hands down!
54 / Animating Your Player
5 XO=XO+SP:YO=YO+SP :RETURN
6 YO=YO-SP :XO=XO+SP:RETURN
7 XO=XO+SP :RETURN
9 XO=XO-SP:YO=YO+SP:RETURN
10 XO=XO-SP :YO=YO-SP:RETURN
• To complete the routine, we need to add lines 11 , 13, and 14. See if you can
write line I I:
ANSWER
II XO=XO-SP (If the joystick is moved left. location 632 w ill contain II . To
move our player to the left, we decrease XO by one with "XO=XO-I ''j.
• Now w rite the code for lines 13 and 14. (If location 632 contains 13, the
joystick was moved down; if location 632 contains 14, the joystick was
moved up.)
ANSWER
13 YO=YO+SP:RETURN
14 YO=YO-SPRETURN
Setting Display Priorities / 55
• How about line 157 If the joystick is not moved at all, location 632 will
contain 15. In this case we don't want to change the XO or YO values at all
but simply return from our subroutine. Given that information see if you
can write line 15.
ANSWER
15 RETURN
To clean up the program, be sure to delete lines, 2, 190, 220, 225, 227, 230, 235,
and 240 since they are not needed for joystick contro/.
Also, after deleting line 190, be sure to change line I to:
On the next page you will find a complete listing of the program for moving a
player under joystick control. Try it out. When you've got it running, continue
reading and we'll make a few more Changes.
*Location 623. technically. is the shadow of hardware register 53275. A shadow is a RAM register
as opposed to a ROM hardware register in an Atari ch ip like GTIA. Thirty times a second the
operating system takes whatever value is in the shadow register and sticks it into the corresponding
hardware register.
56 / Animating Your Player
11045 MISSILES$=BUFFER$:PLAYERO$=BUFFE
R$:PLAYER1$=BUFFER$:PLAYER2$=BUFFER$:P
LAYER3$=BUFFER$
11050 DIM IMAGE1$(15)
11060 FOR 1=1 TO 15:READ A:IMAGE1$(I,I
)=CHR$(A) :NEXT I
11080 POKE 54279,ADR(BUFFERS)/256:REM
DTELL ANTIC WHERE START OF PM MEMORY I
S
11085 POKE 559~46:REM DOUBLE LINE RES.
playfield objects drawn with co lor 1 or 2, but in front of objects drawn with
color 3.
The best way to learn to use the priority register is to experiment with it *
Let's mOdify our program to do that by making these seven changes:
'I am deliberately avoiding, here. the usual discussion of "playfields 0 thru 4." That's because it's
difficult to define how a spec ific playfield is created using SETCOLOR. COLOR. PLOT. and
DRAWTO statements.
58 / Animating Your Player
4020 RETURN
POKE PRIOR,PR
SAVE "D:MOVE2.SAV":STOP
After making these changes save the program and then run it. Try poking
different numbers (1,2,4,8) into the priority register. Then move your player in
front of the different colored playfield Objects on the screen. Make a note of the
results .
If you're going to take a break, now is a good time. When you come
back, we'll discuss speed.
CHANGING SPEED
In some situations you may want to change the speed of a player. For example,
in a horse race simu lation, you might want to assign different speeds to the
different horses. In a baseball game, you might want to assign various running
speeds to different players. To do this all you need to do is set SP to different
values .
Also, delete SP=l from line 10050. Then run the program several times,
setting SP to various numbers from 1.0 to 2.0. When you've got the player's
speed under your control, contin ue reading.
Faster Speeds
Now try to set the player's speed even faster-to a number greater than 2.0.
• What happens when you move the player vertica lly? Horizontally?
ANSWER
Notice that when you move the player vertica lly, you leave a trail consisting
of pieces of the player l But when you move him horizontally, this doesn't
happen. That's because horizontal movement is controlled by poking a
number into the horizontal position reg ister. Atari then takes care of eras ing
the player and repositioning him horizontally. But for vertical movement
there is no horizontal position register, yet. *
To move the player vertica lly, we have to write the player image data into
different bytes of the player image string. Consider for a moment the data that
we put into IMAGE1 S:
• Notice that the first two bytes of IMAGEI $ contain zeros. What do the last
two bytes contain?
ANSWER
*1suspect that when Atari updates its PMG system. a vertical position register will be added. After
all, the Commodore 64 has one I In the meantime. we have to manage w ith other means to move
ou r players vertically.
60 / Animating Your Player
These zeros serve the purpose of automatically erasing the player image
as we move it around within PLAYEROS. Let's look at some specific examples.
Suppose we position the player near the bottom of the screen at vertical
position 80. To do this we might use these commands:
YO =80 : PLAYERO$(YO)=IMAGE1 $
Byte Contents
1 0
2 0
3 0
(and so on)
80 0
81 0
82 28
83 28
84 8
85 28
86 28
87 89 PLAYER IMAGE DATA
88 24
89 40
90 76
91 68
92 68
93 0
94 0
Notice that our player image data is located at bytes 80 thru 94. Now
suppose we want to move our player upward by one byte. To do this we need
to move all 15 bytes upward. For example, the value 76 in byte 90 will be
moved up so that byte 89 will contain 76.
• Consider byte 92. Before we move the player, byte 92 contains 68. This is
the data for the bottom of the player (his feet). When we move the p layer
image data up one byte, what will be in byte 927
Looking at PM Data / 61
ANSWER
A zero! Thi s is important. As we move th e player data up, the player erases
himself.
Since we have two zeros at the beginning of IMAGEI S and two at the
end, we can move the data in one or two byte increments and the "trailing
zeros" will automatically erase the player image.
• We ca n sti ll move the player vertica lly in three byte increments. But we w ill
need to change IMAGE1 S. What changes would we need to make?
ANSWER
M ake those changes. Then try setting SP to 3. Yo ur player w ill now erase
himse lf completely as he moves vertica lly at a speed of 3 bytes per move!
LOOKING AT PM DATA
To get a better idea of how PM data is stored in PLAYEROS, try this. Move the
player to some vertica l position of interest. Then press the SYSTEM RESET key.
Next type in and run the foll owing routine. You ca n run the routine simply by
62 / Animating Your Player
typing " GOTO 600,'" and pressing RETURN. The routine w ill show you the
contents of PLAYEROSbyte by byte. To temporarily halt the routine, hold down
the CONTROL key and press "1" Do the same to restart it.
Well, we've come a long way. But there is still a lot to learn about PMG!
For one thing , although our player moves around the screen at our command,
she looks funny because her legs don't move! In the next chapter you'll lea rn
how to fix that.
For your convenience at the end of this chapter is a complete listing of
the program. It's set up so yo u can choose the va lue to poke into the priority
register. You ca n also choose the va lue for SP, wh ich determines the speed of
the player.
610 END
1999 REM SETUP ROUTINES FOLLON:
2000 GOSUB 10000:REM MISC. INITIRLI-
ZRTION
2005 GRAPHICS 5:REM SET GR. HODE
BEFORE PHG SETUP'
2010 GOSUB 11000:REM PMG SETUP
2015 GOSUB 12000:REM DRRM PLRYFIELD
2020 GOSUB 13000:REM PLRYER COLOR RND
SCREEN POSITION
2130 RETURN
4000 ? "WHAT NUMBER WOULD YOU LIKE TO
F'OI<E I NTO THE PR lOR I TY REG I STER? I
II :
NPUT PR
4010 ? "WHAT SPEED WOULD YOU LIKE FOR
THE PLAYER? 1, 2, OR 3?":INPUT SP
11299 RETURN
11300 DATA 0~0~0~28~28~8,28,58,89,24,4
0~76,68,68,O,O,0
11999 REM DRRN PLRYFIELD
12000 SETCOLOR 4,16,2:COLOR 1
12010 PLOT O~20:DRAWTO 40~20
12020 COLOR 3:DRAWTO 60,35:COLOR 2:DRA
WTO 79,35
12030 RETURN
12999 REM SET PLRYER COLOR RND
POSITION
13000 XO=52
13010 YO=12
13020 POKE 704,88
13030 POKE 53248~XO:REM POKE HORI-
ZONTRL URLUE INTO HORIIONTONPL
POSITION REGISTER.
13040 PLAYERO$(YO)=IMAGE1$:REM PUT
IMRGE INTO PROPER BYTE OF PLPYERO. YO
DETERMINES VERTICAL POSITION
13050 RETURN
Making Your Player
Dance
Next you wi ll learn how to add life to your player by making his or her legs
move. You'll also be able to create other kinds of movements as desired. In
addition, you'll learn how to take care of those troublesome errors that occur
when you move a player too far off the screen.
Let's start by animating those legs.
DEFINING IMAGES
To make our player's legs move, we need to define three player images, which
we will call "LEGSIS, LEGS2S, and LEGS3S."
Here's the first image for our player along with the data needed to create
her. (Notice that we have omitted the leading and trailing zeros.)
65
66 / Making Your Player Dance
I
028
028
8
";<8
'5"8
89
.:21-
, '0
' 3~
:86
/0«'
/
oZg
' -~-
1l.lILIL--_ _--'
.28
8
.:2.8
'08
J - . - - -_.J.lI.LWUII
81
-----"---
02-1
-90
'717i----
7~
~--
, r,g
--- "8
• Now it's your turn. As a review, see iF you ca n ca lculate the data For this
third image
Initializing the Image Strings / 67
ANSWER
28,28,8,28,58,89,24,56,72.132,130
• The data For this w ill appear on line 11300 like this
ANSWER
50 the player will erase herself when we move her up or down. By using
three leading and trailing zeros we can bump the player up three bytes
and still get a clean erase.
Now to initialize our second image we simply insert line 11065, which is
almost identical to line 11060:
Of course we also need to add the data for LEGS2$. We do that on line 11310:
• Your turn again. Write the lines needed to initialize the third player image.
I'll supply the line numbers.
11067
11320
ANSWER
• That takes care of setting up the image strings. Next we need to set up a
routine to move these images into the PM memory area. Specifically. we
will want to move them into which string?
An Experiment / 69
ANSWER
We'l l wa nt to move the data into PlayerOS, which is the PM memory area
for PLAYERO.
AN EXPERIMENT
First, enter the last program from the previous chapter into memory. Then make
these changes:
1. Delete lines 4000 through 4020 and remove GOSUB 4000 from line 1.
2. Change line 11050 so it reads:
GOSUB PEEK(JOYSTICK):
GOSUB MOVELEGS:GOTO 200
MOVELEGS=30:
SP=1:
PR=8
31 PLAYERO$(YO)=LEGS3$ :
RETURN
PLAYERO$(YO)=LEGS1 $
Notice that we are now moving each of the three images, in turn, into
the PM memory area.
• Before you run the revised program, write down a prediction as to how it
will turn out Then try it What's the result?
ANSWER
(I trust you have tried the experiment by now. If you haven't you might
want to do that now. You'll learn more that way, honest ) Well, the player's
legs are moving all right. but they're moving too fast! We need to slow
them down. First, delete lines 30 and 31 and I'll show you how.
One way is to set up a counter. We'll use the variable Z for this. To
increment the counter we simply put the statement "Z=Z+I" at the beginning of
line 30.
Remember that our animation routine is based on a loop. Each time we
pass through the loop, variable Z w ill be increased by one. Also, our player will
An Experiment / 71
be moved to a new position based on the new horizonta l and vertical coordi-
nates . Suppose we wa nt the first image to be displayed during the first three
times through the animation loop. Then we might use an IF-statement at the
end of line 30. Line 30 would then look like this :
Notice the "RETURN" statement that sends control back to the main loop at
line 200.
ANSWER
ANSWER
• We need to add a statement on line 33 before this routine will work. See if
you can figure out w hat it is. Here's a hint. What happens if X=77 Control
72 / Making Your Player Dance
w ill pass to line 32. and the th ird image wi ll be moved into PLAYEROS. But
since Z is not equal to 9 ... what wi ll happen?
ANSWER
Since Z is not equa l to 9. control w ill pass to the next statement. w hatever
it may happen to be. and we wi ll never return from the subroutine. This
w ill lead to problems! Consequently. line 33 needs to be "RETURN" so that
control w ill return to the main loop.
32 PLAYERO$(YO)=LEGS3$:
IF X=9 THEN X=O:
RETURN
33 RETURN
ANSWER
The player's legs move even when he is standing stilll Fortunately. this is
easy to fix. Just change line 15 to read:
15 POP:PLAYERO$(YO) =LEGS1 $: GOTO 200
Control is passed to line 15 when the Joystick is not moved -when the
p layer is stationary. So we can use this line to display a single image and then
jump back to line 200. The POP command seNes to cance l the GOSUB that
passed control to line 15. By using "POP" we make it " legal" to use the "GOTO
200" statement Without the POP statement. you wou ld eventually end up
w ith an error message as a result of "GOTO 200." That's because BASIC is set
up to expect a RETURN statement at the end of a subroutine.
Trapping Errors / 73
Try adding line 15. If everything goes we ll, you will find that the player's
legs move only when you move the joystick! If yo u want. you can experiment
with a different "standing still" image of the player. For example, you might
code line 15 like this
15 POP:PLAYERO$(YO)=LEGS2$:GOTO 200
With this statement. image 2 wi ll be displayed when you leave the joystick in
the upright position. The program will now work fine. If yours doesn't, you may
wish to compare it with the listing at the end of this chapter.
TRAPPING ERRORS
I promised you I'd explain how to handle those error messages that pop up
when you move the player too far off the screen. Here's one simple way:
3000 PLAYERO$=BUFFER$:YO=128:
XO=80:Z=0:TRAP 3000:GOTO 200
The TRAP at line 1 says, "Trap any error you find. Don't print an error message.
Instead,just GOTO line 3000.
ANSWER
Erase the player image from the screen. rBUFFERS is set to ze ro s, so setting
PLAYEROS equal to BUFFERS is the same as setting PLAYERO to zeros. That.
in effect. erases the PLAYERS image.)
After that. the variables YO and XO are set to some specific values. The
value of 128 for YO hides the player off the bottom of the screen. The value 80
for XO puts the PLAYERS at the left of the center of the screen. The result is that if
you move the player too far off the screen in any direction, she will be automat-
ically repositioned off the bottom of the screen on the left side. To bring her
back, Just push forward on the joystick and she will scoot up onto the screen.
74 / Making Your Player Dance
The idea here is that the error condition is caused by a bad value in either
XO or YO. To fix that. we simp ly trap the error and reset XO and YO to any desired
" legal" values. In addition, we reset the leg movement counter IZ) to zero.
Also, notice that we repeat the TRAP command at line 3000, so that if
another error occurs, we will again branch to line 3000. IA TRAP statement
must be reset after an error occurs.)
If you haven't yet got your player's legs to move, now's the time. You may
w ish to refer to the following program, which is a complete listing of all the
lines needed to make your player dancel
Once you have it working, you may wish to animate your player in other
ways . For example, you might want to add some additional images to make
the legs move more smooth ly-or you may wish to have the player move her
arms or other body parts. Have fun!
610 END
1999 REM SETUP ROUTINES FOLLoN:
2000 GOSUB 10000:REM MISC. INITI~LI
Z~TION
2005 GRAPHICS 5:REM SET GR. HaDE
BEFORE PMG SETUP!
2010 GOSUB 11000:REM PMG SETUP
2015 GOSUB 12000:REM DRRM PL~YFI£LD
2020 GOSUB 13000:REM PLRYER COLOR RND
SCREEN POSITION
2130 RETURN
2999 REM ERROR CORRECTION ROUTINE
3000 PLAYERO$=BUFFER$:YO=128:XO=80:Z=0
:TRAP 3000:GOTO 200
10000 REM MISC . INITIRLIZ~TION
10050 JOYSTICK=632:HPOSPO=53248:PRIOR=
623:MDVELEGS=30:SP=1:PR=8:RETURN
10999 REM PHS SETUP ROUTINE
11000 DIM FILLER1$(1),FILLER2$«INT(AD
R(FILLER1$)/I024)+I)*1024-ADR(FILLER1$
) -1)
11010 DIM BUFFER$(384),MISSILES$(128),
PLAYERO$(12B) ,PLAYER1$(128) ,PLAYER2$(1
28),PLAYER3$(128)
11020 BUFFER$=CHR$(O)
11030 BUFFER$(384)=CHR$(O)
11040 BUFFER$(2)=BUFFER$
11045 MISSILES$=BUFFER$:PLAYERO$=BUFFE
R$:PLAYER1$=BUFFER$:PLAYER2$=BUFFER$:P
LAYER3$=BUFFER$
11050 DIM LEGS1$(17),LEGS2S(17),LEGS3$
( 17)
11060 FOR 1=1 TO 17:READ A:LEGS1$(I,I)
=CHR$(A):NEXT I
11065 FOR 1=1 TO 17:READ A:LEGS2$(I,I)
=CHR$(A):NEXT I
11067 FOR 1=1 TO 17:READ A:LEGS3$(I,I)
=CHR$(A):NEXT 1
11080 POKE 54279,ADR(BUFFERS)/256:REM
DTELL ANTIC WHERE START OF PM MEMORY I
S
76 / Making Your Player Dance
Now that you have your player dancing around the screen, let's add some
sound effects! They can help to make an exciting animation sequence even
better.
When you finish this chapter you'll be able to create some interesting
sound effects to go along with the movement of your players. In addition,
you'll learn how to maximize the execution speed of these sound routines.
I'm going to begin with a brief discussion of the SOUND statement. If
you're already an expert on this, you may wish to skip ahead to "Chords" in this
chapter. Otherwise, read on.
77
78 / Adding Sound
group (or "voice") usually sings a separate melody (series of notes) Here are
the names and ranges of the different voices in a four-voice choir:
Now back to the SOUND statement. In Atari BASIC the names of the four
voices are 0, 1, 2, 3. (Again, notice that we start counting with "0" rather than
" 1.") Here's how you specify the voice, pitch, distortion, and loudness with a
sound statement
SOUND VOICE,PITCH,DISTORTION,VOLUME
"SOUND" is a key word such as "GOTO." The other items ("VOICE."
"PITCH," "DISTORTION," and "VOLUME") are called parameters. Let's ca ll
them "parms" for short. In the above example they are variables. Before
executing the above statement, you would need to set these variab les to
appropriate values .
Alternatively, you cou ld use fixed numerical va lues (constants) or arithme-
tic expressions in place of those variab les. For example, you might write:
SOUND 0,121,10,8 or SOUND 0,5*20+1,10,8
Both statements wou ld cause voice 0 to play the note called "Midd le C" since
a value of 121 ="Middle c." (S ee page 58 in your ARARI BASIC REFERENCE
MANUAL for numbers corresponding to the various musical pitches.)
The "10" in the above statement (the third parm) creates a "pure tone"-
one with no distortion. Instead of " 10," you can use other even numbers
between 0 and 14 for various sound effects.
The fourth parm tells Atari how loud you want the sound to be. This
value can be between 1 and 15. The higher the number, the louder the sound.
Before we go any further. let's experiment with a few simp le SOUND
statements. Get your Atari up and running. Then type in this next command
just like it is-without a line number:
SOUND 0,121,10,8
• When you press RETURN the command will immediately execute. What
note wi ll you hear?
CHORDS / 79
ANSWER
STOP
.. VVhathappened?
ANSWER
Nothing really. The sound will continue. The STOP command has no effect
on a SOUND command. To turn off the sound. si mply enter the END
command. Try it
The END command can come in handy when you decide you want
some peace and quiet for a change.
Experiment
Move the cursor back up to the SOUND command you entered earlier (To
move the cursor, hold down the CTRL key w hile press ing the arrow keys.) Try
changing the distortion parameter (the third one). Enter various even numbers
from a to 14. If you hear an effect you like, you may wish to make a note of the
SOUND parms. In the same way, experiment with the volume parm byenter-
ing various numbers from 1 to 15.
CHORDS
A chord is a combination of musical pitches. It's easy to make chords with the
Atari. You simple turn on more than one voice. Try this example. It will produce
what musician's call a C-major chord:
SOUND 0,243,10 ,8
SOUND 1,121,10,8
SOUND 2,96,10,8
SOUND 3,81,10 ,8
80 / Adding Sound
One caution: if the total of all the volume parms exceeds 32, an un-
pleasant "clipped" tone will result.
• In the example above, did I obseNe this caution? What is the total of the
volume parameters in the example?
ANSWER
POKE 53760,121
POKE 53761,168
• Now you try it. What POKE commands would be needed to replace this
SOUND command?
SOUND 0,96,5,5
ANSWER
POKE 53760,96
POKE 53761,85 (since 5*16+5=85)
SOUND REGISTERS
So far I've shown you only two sound contro l reg isters: 53760 and 53761. Here
is a more complete list:
• Look over these locations for a moment. What do the even numbered
locations all control? The odd ones?
ANSWER
The even numbered locations all control pitch. The odd ones control distor-
tion and volume.
MORE EXPERIMENTS
Now let's try some more experiments. Type in and try out th is little sound demo
program. Then read on.
4 GDTD 10
::) HP1\}I~~ "D: C:)'-.CJDt~" ~3A\'" : ::; l' Clj='
10 c:mmJB -1000
20 T I:;~AF' =:':U :::' CHF:$ ( 12'.3) : '7 : '7 : ':) "E~nEJ:;~
(31 . I D I !\~(J f:3F'I::'::ED (j-::!5:'r) "~::r I\IPUT 51'
:50 ':C' : ) "E~I'HEF: D:r. ~:;Tur-n I (Jr.1 (E'-/EJ'I /\/UI1BER
Fr;.:OI"/ ()-14) ";: II\/F'LJT D I ~3T
35 DO=16*DIST+VDL
50 FOR PO=l TO 255 STEP ST
60 F'DI::E ~:;U " /='0
82 / Adding Sound
70 I::'UI<E D\J() !I DO
ElO NE XT' PO
CtU F'CWE D\/O ~ U
100 CJCJTU :2 ':)
<:/9 C,. t~ND
lUOO SO=53760:DVO=53761:S1=53762:DV1=5
3763:S2=53764:DV2=53765:S3=53766:DV3=5
6 7 : \/ UI-::::8
:~; '1
11. 00 RETUHI\I
Line 70: POKE OVO,DO Here I turn on the distortion and volume of voice O.
(J initialized DVO to 53762 in line 1000. 53762 is the distortion and volume
control register for voice 0.) The value contained in DO was calculated on line
35.
Line 35 OO=16*OlST+VOL Here I set DO to the value that is derived from the
desired distortion and volume . As I mentioned earlier, we do this by first
multiplying the desired distortion by 16 and then adding the desired volume.
You'll notice that DIST is set at line 30 in response to the prompt " ENTER
DISTORTION." I initialized VOL to 8 in line 1000. I could have set it to any value
fromOto15.
• Suppose we set ST to 20. What will PO equal on the second pass through
the loop?
Using A Loop / 83
ANSWER
21 (1 +20)
So the higher the value of ST, the bigger change in PO at each pass
through the loop. When ST is set to, say, I, there wi ll be a slow, smooth gliding
pitch. when ST is set to progressively higher values, the sound changes in pitch
rapidly and has a shorter duration (since it takes fewer times through the loop
to reach 255).
Line 90: POKE OVO,O This simply turns off the volume for voice O. I do this
so that the sound stops when control returns to the initial prompt at line 20. I
could also have turned off the sound by poking a a into ~O .
Experiment
If you haven't already done so, I suggest you try experimenting with different
values for distortion (OIST) and gliding speed (ST).
Also, you might want to modify the program to make it easier to hear the
various sounds being produced. For example you might put a delay on the
FOR/ NEXT loop. You could do this by adding this line to the program:
USING A LOOP
Notice how I produced a gliding effect by putting the poke statements inside of
a loop. In the same way you can put these poke statements within your
animation loop. This way, you get a kind of gliding effect as your player or
missile moves around the screen.
Assignment
Let's try this with the moving legs routine we developed in the last chapter.
What we will do is create some interesting "traveling sounds" for our player.
Whenever the player moves we'll play some sounds. When the player stops,
the sound will stop.
84 / Adding Sound
Perhaps you have some ideas about how this might be done. If so, you
might want to experiment on your own before continuing.
Traveling Sounds
Take a look at the program yo u entered in the previous chapter (which I called
" LEGS.SAV"). One approach to making traveling sounds might be to add a
"sound statement" to the " MOVELEGS" subroutine, which begins at line 30.
A simple way to do this would be to use the variable Z to set the pitch of
the sound. As you will recall we used Z as a counter to control the display of
various running images of our player. When Z was less than 4, we disp layed
" LEGIS". When Z was in the range of 4 through 6, we displayed "LEG2S," and
so on. We added I to Z at the beginning of the MOVELEGS routine so that
each time the routine was called, Z was greater than before. When Z reached 9,
it was reset to O.
Well, we can make Z do double work. Here's how we might do it with a
sound statement:
SOUND 0,Z,10,8
• Based on what I've sa id so far, at what line might you insert this sound
statement? What would the revised line look like?
ANSWER
You might insert the statement into line 30. like this:
Before you continue reading, you might want to revise the " LEGS"
program by changing line 30 as we've just discussed.
USING POKES
Suppose you were to use Poke statements to create the sound. First you might
initialize these variables
SO=53760
DVO=53761
Adding Variety / 85
ANSWER
SO would stand for the pitch control register for voice O. OVO wou ld stand
for the distortion/volume control register for voice O.
• What would line 30 look like if you used Poke statements to create sound?
ANSWER
(Recall that to find the proper value for a distortion of 10 and a volume of
8, we multiply 16 times the distortion. This gives us 160. We then add the
vo lume (8) to 160 to arrive at the DVO va lue of 168.)
ADDING VARIETY
To give more va riety to the sound, you might consider multiply ing Z by some
number. For example:
add-like sound, missile firin g, collision detection, and so on, the bigger your
loop becomes and the slower the animation. That's why I've stressed tech-
niques that will help you maximize execution speed-such as poking values
into sound registers and placing frequently executed code early in the program.
Of course, machine language is probably the best-although the hardest-
way to obtain fast player/ missile action.*
Well, speaking of miss iles, in our next chapter let's take a look at what
they are and how to use them.
1 GOSUB 2000:GOTO 2 00
2 SAVE "D:SOUNDRUN.SAV":STOF' :REM DIS';
30
4 REM RDJUST HORIZONTRL & VERTICRL
COCIRD I NRTE S
5 XO=XO+SP:YO=YO+SP:RETURN
6 YO=YO-SF':XO=XO+SF':RETURN
7 XO=XO+SF':RETURN
9 XO=XO-SP:YO=YO+SF':RETURN
10 XO=XO-SP:YO=YO - SP:RETURN
11 XO=XO-SP:RETURN
13 YO=YO+SF':RETURN
14 YO=YO-SF':RETURN
15 POP : PLAYERO$ (YO) =LEGS 1 $ :§I<E DVO?J
: GOTO 200 -
29 REM ~OUE PLRYERS ~
30 Z=Z+1:POKE SO,Z*TONE:POKE DVO,DO PO
KE HPOSPO,XO: HEN PLAYERu 0)=
LEGS1$:RETURN
31 IF Z<7 THEN PLAYERO$(YO)=LEGS2$:RET
URN
32 PLAYERO$(YO)=LEGS3$:IF 1=9 THEN 1=0
: RETURN
33 RETURN
199 REM MRIN LOOP
200 IF P K(BUTTONO)-O THEN GOSUB SETS
OUND'
204 GOSUB PEEK(JOYSTICK):GOSUB MOVE LEG
S:GOTO 200
260 REM
270 REM
280 REM
*When you're ready to dirty your hands with machine language, look for my new book on Player
Missile Graphics in Assembly Language.
Adding Variety / 87
290 REM
600 GRAPHICS O:TRAP 610:FOR 1=1 TO 128
:? I;" ";ASC(PLAYERO$(I»:NEXT I:STOF'
610 END
1000 POKE DVO,O:? :? "ENTER DISTORTION
NUMBER (0-14) ";: INPUT DIST:? "ENTER
TONE NUMBER (1-28) ";:INPUT TONE
1010? "ENTER VOLUME NUMBER (0-15) ";:
INPUT VOL:DO=DIST*16+VOL:REM DO NILL
BE POKED INTO DISTORTION/VOL. REGISTER
11045 MISSILES$=BUFFER$:PLAYERO$=BUFFE
R$:PLAVER1$=BUFFER$:PLAYER2$=BUFFER$:P
LAVER3$ =BUFFER$
11050 DIM LEGS1$(17),LEGS2$(17),LEGS3$
(17)
11060 FOR 1=1 TO 17:READ A: LEGS 1 $ ( I , I )
=CHR$(A):NEXT I
11065 FOR 1=1 TO 17:READ A: LEGS2$(I, I)
=CHR$(A):NEXT 1
11067 FOR 1=1 TO 17:READ A:LEGS3$(I,I)
=CHR$(A):NEXT I
11080 POKE 54279~ADR(BUFFER$)/256:REM
DTELL ANTIC WHERE START OF PM MEMORY 1
S
11085 POKE 559,46:REM DOUBLE LINE RES.
• How many bits wide is a single missile? (Keep in mind that a byte is made
up of eight bits.)
ANSWER
Each missile is two bits wide lin contrast to players, whi ch are eight bits
wide) .
89
90 / Missiles
10101010101010101
~ ---...-- ---...-- ---...--
MISSILE 3 M ISSILE 2 MISSILE 1 MISSILE 0
Since this byte has nothing but zeros in it, no missiles would appear on
the screen. Now if we wanted to make miss ile I appear on the screen, we
might put this binary data into a byte of miss ile memory:
! !
10
l
0 0 01J.1J. 0/01 I :
---...--
MISS ILE 1
ANSWER
ANSWER
• Ok, try this one. What binary number would you use to turn on missile 0
so that it has full width? What would the corresponding decimal number
be?
Binary Number:
Decimal Number:
ANSWER
• Suppose you wanted to turn on both bits of missiles 0 and J. What binary
number would you need? Decimal number?
Binary Number:
Decimal Number:
ANSWER
Ok, so let's say we want to turn on both bits of missile O. We know tha~
we need to put a 3 into miss ile memory to do this since a binary 0000001 J = 3.
But what specifica lly do we do to code this?
Image String
It's fairly simple. We just create an " image string" similar to the strings we
defined earlier. For a missile, a single byte string may be enough. Remember,
the more bytes in your image string, the taller the player or missile will be.
Once we have the data in the image string we can easily zap it into the
missile memory area at machine language speed. This on ly works, of course,
because we have carefully defined our PMG area w ith strings.
92 / Missiles
• Let's ca ll our miss ile image string MIMAG ES. We need to do two things to
set up MIMAGES: dimension it and then plug in a decimal 3. See if you can
write the code to do it. (It w ill go into your new program as line 11070.)
ANSWER
HPOMSO=53252
(Note that HPOSMO ends w ith a zero, not the letter "0.")
Another minor change to make in SOUNDRUN is the automatic save
routine at line 2. Change it to:
2 SAVE "D:MISSILE.SAV":STOP
That way you won't w ipe out the previous program w hen you save this one.
POKE SO,X*TONE
POKE DVO,DO
ANSWER
We need to delete GOTO 200; otherwise control will not fall through to
our new routine.
• Got all that? See if you can write the code for it.
ANSWER
IF PEEK(BUTTON) =O AND
PEEK(JOYSTICK)<>15
94 / Missiles
THEN
MOVEO=PEEK(JOYSTICK):
FIREO=FIREO+1
Of course, Atari won't pay any attention to this fancy indentation. But it
does make it easier to read . It's also easier for me to type on my ATARI TEXT
WIZARD. This w ill be line 301. (Yes, there is a line 300. But it will come later. For
now just put a REM at line 300.)
Next we need to be able to jump out of this loop if the fire button was
not pressed. We can't just peek at BUDONO to decide whether to leave the
missile routine because BUDONO will return to zero as soon as the button is
released .* If we relied on BUDONO, then on the second pass through the loop
our missile would stop.
So we look at FIREO. If it equals 0 then we know we need to return to line
200. The code would then be:
ANSWER
On first pass through the missile move routine we will also want to:
• Set DIRO to a number representing the direction we want the missile to
move. (Again that will be the familiar joystick value such as 7 for right
14 for up, and so on.)
• Add 1 to FIREO so that on the next pass through the loop FIREO will be
greater than 1.
* Technica l note: there is a way to " latch" the fire button so that location 644 is not reset as soon as
the button is released. I find it easier to use this method, howeve r.
Building A Missile Move Routine / 95
• Consider for a moment what the code might look like for doing that:
ANSWER
Note that with this code, DIRO will be set to the stick deflection value only
on the first pass through the loop. Also notice that I set MYO to YO+ 7. That's
because I wanted to move the missile down a bit from the player image.
Remember that the player image has zeros at the top so she erases herself as
she moves down the screen.* I set MXO to XO+ 3 because a value of XO would
put the missile at the far left edge of the player image-I want tht missile to be
hidden " underneath" the player.
ANSWER
335 MISSILESS=BUFFERS
POKE HPOSMO,MXO:
MISSILESS(MYOj =MIMAGEOS
HPOSMO=53252
* 8y now you have probably noticed that I sometimes refer to our player as male and sometimes as
female. Working w ith a feminist writer ta ught me to do this as a way to avoid sex ist writing. I hope
it doesn't jar you too much. Of course, you might still complain that the p layer doesn't look at all
female-oh we ll.
96 / Missiles
13000 XO=120
13010 YO+43
SAVE "D:MISSILE.SAV":STOP
15 POP:PLAYERO$(YO) =LEGS1 $:
GOTO 300
MXO=XO-10
Why? Because I want you to be ab le to see the missile so you can verify that
your routine is working at this point. Otherwise, the missile wi ll be positioned
directionally on top of the player and you won't be ab le to see it. (Remember,
the missile is normally the same color as the player it belongs to.)
Also, put a stop at line 340 just to temporarily freeze the action so you can
see exactly w here the missile appears when you press the fire button.
I've cove red a lot. I know. So for your convenience, here is a li sting of the
new program with the changes circled,
6 YO=YO-SP:XO= XO+SP:RETURN
7 XO=XO+SP:RETURN
9 XO=XO-SP:YO=YO+SP:RETURN
10 XO=XO-SP:YO=YO-SP:RETURN
11 XO=XO-SP:RETURN
13 YO=YO+SP:RETURN
14 YO=YO-SP:RETURN
uS POP :PLAYERO$ (YO)=LEGS1$:GOTO 300
29 REM MOUE PLRYER"S LEGS
30 Z~Z+1:POKE HPOSPO~XO:IF Z<4 THEN PL
AYERO$(YO)=LEGS1$:RETURN
31 IF Z<7 THEN PLAYERO$(YO)=LEGS2$:RET
URN
32 PLAYERO$(YO)=LEGS3$:IF Z=9 THEN Z=O
: RETURN
33 RETURN
199 REM MfHN LOOP
200 GOSUB PEEK(JOYSTICK):GOSUB MOVELEG
XO=120
YO=43
POKE 704,88
13030 POKE 53248,XO:REM POKE HORI-
ZONT~L U~LUE INTO HORIZONTON~L POSITIO
N REGISTER.
13040 PLAYERO$(YO)=LEGS1S:REM PUT
IM~GE INTO PROPER BYTE OF PL~YERO. YO
DETERMINES UERTIC~L POSITION
13050 RETURN
14000? "To fire missile ._ mO~/e joystic
k and push fire button":RETURN
When your new program is working properly, the missile will appear to
the left of the player. That's because we set the horizontal coordinate (MXO) to
ten less than the player coordinate. Now that we've got the missile on the
screen, let's see about moving it. But first. go back and change line 315 so it says
MXO=XO+3.
65 MXO=MXO+MSO:MYO=MYO+MSO:RETURN
66 MYO=MYO-MSO:MXO=MXO+MSO:RETURN
67 MXO=MXO+MSO:RETURN
69 MXO=MXO-MSO:MYO=MYO+MSO:RETURN
70 MXO=MXO-MSO:MYO=MYO-MSO:RETURN
71 MXO=MXO-MSO:RETURN
73 MYO=MYO+MSO:RETURN
74 MYO=MYO-MSO:RETURN
Notice that we are now using MSO to increment or decrement our missile
coordinates. (MSO=Speed of Missile 0.)
In addition to the above lines, we will need these lines in our missile
move routine:
• According to line 320, w here will control pass if the joystick is pushed
forward? (Hint: the number 14 is returned when you push the stick
forward .)
ANSWER
ANSWER
We decrement MYO, and the effect is that our missile wi ll move up the
screen. (The smaller MYO, the higher wi ll be the position of the missile on
the screen.)
Error Routine / 101
Then, save and then run the program. If all went well, your player can
now fire the missile in anyone of six directons!
ERROR ROUTINE
Having played around a bit firing missiles, you are probably tired of seeing that
error message pop up. You know, the one that comes up every time you fire a
missile off the screen. That's fairly easy to fix. Let's write an error correction
routine for it.
Once again, let's begin our program with a TRAP statement at line 1:
Whenever an error occurs, program control will branch to line 3000. I've
used a high line number so that the trap routine is out of the way of our main
loop. Now when an error occurs, control will pass to an error correction routine
at line 3000. The error correction routine will check for various error conditions
and then correct them. I know, we did this in a previous chapter, but this time
the correction routine will be a bit more detailed.
First let's handle the situation where the player moves off the screen too
farto the right. Horizontal coordinate 210 isjust off the screen to the right. So if
the XO coordinate is greater than 210 let's reset XO to 210. The statement IF
XO>21 0 THEN XO=210 will do that nicely.
In the same way we can reset the other XO and YO values if they move
too far off the screen. Like this
3035 Z=O
That takes care of our player. Now she ca n hide off the screen-even move
around off-screen and then come back.
Let's fix the missile, too. Here's a simple way to do it for now: reset the XO
and YO coordinates whenever an error occurs. Reset them to what? Well, let's
simply reset them to the player's coord inates, like this:
3040 MXO=XO:MYO=YO
Also, we need to turn off the miss ile sound when an error occurs. We can
do that simply by setting 01 to zero:
3050 01 =0
Next, we need to turn off the miss ile routine, so it doesn't continue to
adjust the MXO and MYO coordinates. We do that by setting FIREO to zero:
3060 FIREO=O
Add these lines. Then yo u'll be able to fire missiles from an ambush
position-while the player is hiding off the screen!
Our missile move routine is now pretty much finished. But let's add a few
embellishments. First, let's add sound to the firing of the missile.
Add line 300 as follows:
Also, remove the RETURN from line 10060 and put RETURN at line 10900.
Now we can use variable 01 to set the volume of our missile sound. A
good place to do this is on the first pass through the missile loop. If we set the
volume to maximum on the first pass and then decrement it on each successive
pass, we can create an explosive type sound that gradually fades away. We
can set the volume to maximum by writing 01 =15.
ANSWER
At line 315 where we test to see if we are on the first pass through the
missile routine. So add 01 =15 to the end of line 315.
ANSWER
Add line 330. Save the program and run it. You will now hear an explosive
sound whenever you fire a missile.
Now let's play with the miss ile size register. That's a register that lets us instantly
increase or decrease the width of a missile. We can set a missile's size to nor-
mal, double, or quadruple width. The missile size register, at location 53260,
controls the size of all miss iles.
104 / Missiles
Here's a chart showing the proper numbers to poke in For various missile
sizes.
Missile
Number Normal Double Quadruple
0 0 3
I 0 4 12
2 0 16 48
3 0 64 192
Important: iF you want to set the size of two or more missiles at once,
then add the proper values For each missile depending on the desired size.
Then poke the total into location 53260.
For example, to set missile 3 to quadruple size and missile I to double
size, you wou ld poke 196 into 53260. (192 gives quad size For missile 3, and 4
gives double size For missile I. We get 196 by adding 192 and 4.)
• Suppose you wanted to set missile 0 to quad size and missile I to double
size? What number would you poke into 53260?
ANSWER
7(3+4=7)
ANSWER
POKE 53260,5
To make our program easier to read, let's set up a variable called SIZEM
(size of missiles) at line 10070, like so: SIZEM=53260.
We can create a nice eFFect by poking a random number into SIZEM. First
(also at line 10070) let's set up a variable called RANDOM. RANDOM =53770.
Location 53770 is constantly being updated by Atari's operating system with a
random number. So a quick way to get a random number is to "peek" into
location 53770.
Complete Usting / 105
• Write a statement to poke a random number into the size register for
missiles.
ANSWER
Try it. Be sure to initialize SIZEM and RANDOM at line 10070. Then add
POKE SIZEMPEEK(RANDOM) to line 300.
You'll now see the missile randomly expand to various widths as it sails
across the screen. Notice the different effect produced by firing the missile
vertically versus firing it horizontally.
COMPLETE LISTING
Here is a complete listing of the missile program that we have developed in
this chapter. Again, I have circled the lines that are to be changed or added. Be
sure to save it to disk or tape. You'll need it. Remember, each chapter will build
on the previous program in some way.
In the next chapter, you learn how to create single-line resolution PMG!
10050 JOYSTICK=632:HPOSPO=53248:PRIOR=
623:MOVELEGS=30:SP=I:PR=8:BUTTONO=644:
SETSOUND=1000:SO=53760
10060 BUTTONO=644:SETSOUND=10~):SO=537
0900
10999 REM PMG SETUP ROUTINE
11000 DIM FILLER1$(I)~FILLER2$«INT(AD
R(FILLER1$)/I024)+I)*1024-ADR(FILLER1$
) -1)
11010 DIM BUFFER$(384),MISSILES$(128),
PLAYERO$(128),PLAYER1$(128)~PLAYER2$(1
28),PLAYER3$(128)
11020 BUFFER$=CHR$(O)
11030 BUFFER$(384)=CHR$(0)
11040 BUFFER$(2)=BUFFER$
11045 MISSILES$=BUFFER$:PLAYERO$=BUFFE
R$:PLAYER1$=BUFFER$:PLAYER2$=BUFFER$:P
LAYER3$=BUFFER$
11050 DIM LEGS1$(171,LEGS2$(17),LEGS3$
(17)
11060 FOR 1=1 TO 17:READ A:LEGS1$(I,ll
=CHR$(Al:NEXT I
11065 FOR 1=1 TO 17:READ A:LEGS2$(I,I)
=CHR$(A):NEXT I
108 / Missiles
So far we have been dealing strictly with double-line resolution. Since double-
line resolution is easier to handle and takes less memory I'll continue to use it
for most of the examples in this book. But our little player is so cute in single-
line resolution! IJust couldn't resist introducing him to you.
Be sure to save copies of the previous double-line resolution programs,
since future programs will be based on them-not on the program in this chap-
ter. In fact. I suggest you just read over this chapter without typing in any of the
examples. Then after you've mastered double-line resolution, come back and try
out the program in this chapter. (Whatever. You'll do it your way, anyway.)
At the end of this chapter is a complete listing of a program that does
essentia lly the same thing as the program in the previous chapter-the only
difference is that it is in single-line reso lution. The program is called SLRES.SAV-
short for "single-line resolution. " Here is a summary of the changes you' ll need
to make to MISSILE.SAV to produce SLRES.SAV:
LINE 11000
This is the " filler" line that makes sure that PM memory starts on a 2K boundary.
The only change is that while the number 1024 appeared in the previous
program, 2048 appears in this program (1024=1K: 2048=2K).
109
110 / Single-Une Resolution
LINE 11010
In the previous program I had a string ca lled BUFFERS dimensioned to 384
bytes. Well, in sing le-lin e resolution, this string needs to be twice as many
bytes: 384*2 or 768.
Instead of dimensioning BUFFERS to 768 bytes, I broke it down into three
strings of 256 bytes each: ERASES, F/LLER3S, and F/LLER4S. (Notice that it works
out to be the same thing since 3*256=768.) Also, notice that each of the other
strings are now 256 bytes long instead of 128-the way they were in double-
line resolution. And notice that I omitted the dimensioning of PLAYER1S,
PLAYER2S, and PLAYER3S.
Notice the zeros in the missile image data at line 11330. These zeros erase
the missile as it moves vertically. Using this arrangement I found that I didn't
need the statement "MISSILESS=ERASE$" at line 335.
LINE 11085
This is important. Here I specify single resolution by adding 16 to the 46 that is
to be poked into location 559, the direct memory access control register. I'll
explain this more later. (See the "Odds and Ends" chapter if you can't wait.)
LINES 5 THROUGH 14
Here I use SY to adjust YO, where previously I used SP. SY refers to "speed of Y
(up/down) movement." In single-line resolution, remember, there are twice as
many vertical locations. So to get approximately the same vertical speed, we
have to move the player 2 bytes instead ofjust 1. Consequently, SY is initialized
to 2 in line 10070 and SP is still initialized to 1. Horizontal movement is no
different in single- versus double-line resolution.
A similar change could also be made for the missile coordinate adjust-
ment routine at lines 60 through 75. When you get this program running,
notice how the missiles don't go exactly as you might expect when you fire
them in a diagonal direction. That's because in single-line resolution there are
about 224 vertical positions, but only 150 horizontal ones.
LINE 10070
In line 10070 I initialized SY to 2 as I just mentioned.
LINE 315
To line 315 I added:
MYOS=MYO
MYOS is short for MYOSAVE. Here I am saving the vertical coordinate for the
missile. Notice that I am doing this when the missile's vertical coordinate is first
set. I use this saved value later in the error correction routine (which begins at
line 3000) to help me erase the missile from the screen.
112 / Single-Une Resolution
73 MYO=MYO+MSO:RETURN
74 MYO=MYO-MSO:RETURN
199 REM MRIN LOOP
200 GOSUS PEEK(JOYSTICK):GOSUS MOVELEG
S
260 REM
270 REM
280 REM
290 REM
300 POKE SD1,Pl:POKE DV1 , Dl:POKE SIZEM
,PEEK(RANDOM)
301 IF PEEK(SUTTONO)=O AND PEEK(JOYSTI
CK)< >15 THEN MOVEO=PEEK(JOYSTICK):FIRE
O=FIREO+l
305 IF FIREO=O THEN GOTO 200
315 IF FIREO=1 THEN MXO=XO+3:MYO=YO+7:
DIRO=MOVEO:FIREO=FIREO+l:Dl=15{f1YOS=MY
::w320 IF FIREO } 1 THEN GOSUS DIRO+60
330 DI-Dl-1:IF Dl ( 1 THEN DI-0
3~5 POKE HPOSMO,MXO : MISSILES$(MYO)=MIM
AGEO$
499 GOTO 200
600 GRAPHICS O:TRAP 610:FOR 1=1 TO 128
:':) I;" ";ASC(PLAYERO$(I» :NEXT I:STOP
610 END
1999 REM SETUP ROUTINES FOLLON:
2000 GOSUS 10000:REM MISC. INITIRLI-
ZRTHIN
2005 GRAPHICS 5 : REM SET GR . MODE
BEFORE PMG SETUP!
2010 GOSUS 11000:GOSU8 11045:REM PMG
SETUP
2015 GOSUS 12000:REM DRRN PLRYFIELD
2020 GOSUS 13000:REM PLRYER COLOR RND
SCREEN POSITION
2025 GOSUS 14000 : REM DI S PLRY MESSRGE
2130 RETURN
2999 REM ERROR CORRECTION ROUTINE
3000 IF XO >210 THEN XO=210:REM CORRECT
PLRYER COORDINRTES
3010 IF XO <39 THEN XO= 3 9
3020 IF YO< l THEN YO=1
114 / Single-Une Resolution
11047 PLAYERO$=CHR$(0):PLAYERO$(256)=C
HR$(0):PLAYERO$(2)=PLAYERO$
11050 GS1$(17)~LEGS2$(17)~LEGS3$
( 17>
11060 FOR 1=1 TO 17:READ A: LEGS 1 $ ( I , I )
=CHR$(A):NEXT I
11065 FOR 1=1 TO 17:READ A: LEGS2$ ( I , I )
=CHR$(A):NEXT I
11067 FOR 1=1 TO 17:READ A: LEG!:;3$ ( I , I )
=CHR$(A):NEXT I
Unes 3000 through 3080 / 115
TURN ON PMG
Missile Collisions
117
118 / Detecting Collisions
Player Collisions
*Later. though, you may wish to go back to using constants (such as 53260, 53261, etc.l. That's
because Atari BASIC only allows you 128 variable names. Also, statements with constants actually
execute slightly faster than those using a corresponding variablel (This is not true with other
computers such as the PET and Apple, where variables execute 10 to 40 times faster than con-
stants.II'd like to thank B. B. Garrett for claritying this in his informative article "Atari Times" in the
May, 1983 issue of Compute!
Reading Collision Registers / 119
ANSWER
If you have the program from the previous chapter loaded into memory,
you might want to initialize POPF and MOPF right now by adding these state-
ments to line 10070:
POPF=53252:
MOPF=53248
COLLISION=PEEK(POPF)
Ok, try this one. Suppose yo u draw a line on the screen with these
statements:
GRAPHICS 7:
SETCOLOR 2,3,4: COLOR 3:
PLOT 0,0: DRAWTO 159,0
COLLISION=PEEK(POPF)
• What value will be in COLLISION if player a is touching the line you drew?
120 / Detecting Collisions
ANSWER
MULTIPLE COLLISIONS
Once a co llision occurs, the co llision register retains the number that was
placed in it. If a second collision occurs, the next number is added to the
number that already exists there.
• Suppose player a collides w ith a playfield drawn w ith COLOR I and then
collides w ith a playfield drawn w ith COLOR 3. What va lue wi ll be the
co llision register? (Carefu l now, this one is a bit tricky.)
ANSWER
5 (the 1 From the First collision wi ll be added to the 4 From the second
co llision).
Since the collision registers retain the values put in them w hen a collision
occurs, it's important to reset them. This is almost as easy as taking ca ndy from
a baby. All you do is poke a 1 into the HIT CLEAR reg ister at location 53278.
I suggest you use a va riable for the HIT CLEAR register. Let's call it HITCLR.
At line 10070 insert this statement:
HITCLR=53278
ANSWER
You're right if you said "a. A ll col lision registers are cleared."
ANSWER
GOSUB PEEKIPOPFj+40
ANSWER
We need a subroutine at line 44. Tha t's because POPF will co ntain a 4 if
player 0 hits a COLOR 3 playfield.
DRAWING A PLAYFIELD
Now let's use some of these techniques in a PMG program. First. let's draw a
playfield. We'll make it a maze so that in a later chapter we can expand the pro-
gram into a full-fledged game.
*In this book, a COLOR I p layfield is simp ly a playfield drawn with COLOR 1. The
term "playfie ld I," as used in the Atari technical manual, is not synonymous with the
term "COLOR I playfield."
122 / Detecting Collisions
Also, let's revise lines 2010 and 201 5 so that line 2010 becomes 2015 and
2015 becomes 2010. It seems that PMG works better w hen the playfield is
draw n before the PMG setup is executed.
And at line 2005 change GRAPHICS 5 to GRAPHICS 7 since our new
play field requires that graphics mode.
? "POPF=";PEEK(POPF),
"MOPF=";PEEK(MOPF)
P/ayer-P/ayfie/d Collisions / 123
Next also at line 200, let's ca ll for the execution o f the two co llision detection
subroutines, one for POPF and one for MOPF. And let's arrange things so that if
there is no co llision, w e immediately return from each subroutine. We'll let the
POPF subroutine start at line 40 and the MOPF subroutine start at line 50.
Here's the ca ll to the MOPF subroutine
GOSUB PEEK(MOPF)+40:
ANSWER
200? "POPF=";PEEK(POPF),
" MOPF=";PEEK(MOPF):
GOSUB PEEK(MOPF)+40:
GOSUB PEEK(POPF)+50
PLAYER-PLAYFIELD COLLISIONS
Simple right? Now all we need to do is decide w hat w e want to happen w hen
a co llision occurs. For now, let's fix things so that our player cannot wa lk
through the maze wa lls. Here's how we' ll do it. At the beginning o f line 201
we'll save the XO and YO coordinates by inserting the statement XOA=XO and
YOA=YO :
Then w hen our player hits a maze wa ll, we 'll reset XOand YO back to what they
w ere before the co llision. Got it?
Suppose our player hits a COLOR 1playfield. Then POPF w ill contain a " I,"
and control w ill pass to line 41 (as a res ult o f GOSUB PEEK(POPF) +40) Then at
line 41 all we need to do is:
124 / Detecting Collisions
1. Set the YO and XO coordinates to what they were before the collision.
2. Clear the co llision registers by poking a 1 into HITCLR.
ANSWER
41 XO=XOAYO=YOAPOKE HITCLR,IRETURN
We also need this same subroutine at line 42. That's because POPF wi ll
contain a 2 if our player hits a COLOR 2 playfield.
If our player hits a COLOR 3 playfield, POPF wi ll contain a 4 (strange as
this may seem).
ANSWER
44 (Since 40+4=44.)
ANSWER
Let's look at the playfield detection statement more close ly. It is: GOSUB
PEEK(MOPF+40) .
• If the player does not hit anything, POPF w ill conta in a zero. So where will
control pass when the playfield detection statement is executed?
ANSWER
• What code would be appropriate for line 407 (Hint: we don't really need
to do anything since no collision has occurred. All we need to do is get
back to the main loop.)
ANSWER
All we need is a RETURN statement at line 40. This will return control to the
main loop.
MISSILE COLLISIONS
The missile collision subroutines sta rt at line 50 since the calling routine is
GOSUB MOPF+50. If no miss ile-play field collision has occurred, we won't need
any specific action.
ANSWER
50 RETURN
• Move the missile off the screen by poking zero into HPOSMO.
• Turn off the missi le sound.
• Turn off the missile move indicator (FIREO).
• Clear the collision registers.
• Since we will have to do this whenever a missile hits a wall, let's put it into
a subroutine at line 190. See iF you can write the code:
ANSWER
FIREO=O
POKE HITCLR, I .
RETURN
• Now if a miss ile hits playfield 1. to which line w ill control pass?
ANSWER
ANSWER
We'll need line 52 and line 54. (Remember, if a miss ile hits playfield 3 then
the collision registe r w ill contain a 4)
Line 190 contains the commands that we want executed if a miss ile hits a
wall so at line 52 all we need is:
52 GOSUB 190:RETURN
53 GOSUB 190:RETURN
54 GOSUB 190:RETURN
TRY IT
Make all the changes I've discussed so far to MISSILE.SAV. Also, change line 2
to:
SAVE "D:MISSCOL.SAV":STOP
5 XO=XO+SP:YO=YO+SP:RETURN
6 YO=YO-SP:XO=XO+SP:RETURN
7 XO=XO+SP:RETURN
9 XO=XO-SP:YO=YO+SP:RETURN
10 XO=XO-SP:YO=YO-SP:RETURN
11 XO=XO-SP:RETURN
13 YO=YO+SP:RETURN
14 YO=YO-SP:RETURN
15 POP :PLAYERO$(YO)=LEGS1$:GOTO 300
29 REM MOUE PLAYER~S LEGS
30 Z=Z+1:POKE HPOSPO,XO:IF Z<4 THEN PL
AYERO$(YO)=LEGS1$:RETURN
31 I F Z<7 THEN PLAYERO$(YO)=LEGS2S:RET
URN
32 PLAYERO$(YO)=LEGS3S:IF Z=9 THEN Z=O
: RETURN
33 RETURN
40 RETURN
41 XO=XOA:YO=YOA:POKE HITCLR~I:RETURN
44 XO=XOA:YO=YOA:POKE HITCLR~1:RETURN
260 REM
270 REM
280 REM
290 REM
300 POKE SD1,Pl:POKE DV1,Dl:POKE SIZEM
~ PEEf::: (RANDOM)
301 IF PEEK(BUTTONO)=O AND PEEK(JOYSTI
CK) <> 15 THEN MOVEO=PEEK(JOYSTICK):FIRE
0=FIREO+1
305 IF FIREO=O THEN GOTO 200
315 IF FIREO=1 THEN MXO=XO+3:MYO=YO+7:
DIRO=MOVEO:FIREO=FIREO+1:D1=15
320 IF FIREO>1 THEN GOSUB DIRO+60
330 Dl=Dl-1:IF Dl ( 1 THEN Dl=O
335 MISSILES$=BUFFER$:POKE HPOSMO~MXO:
MISSILES$(MYO)=MIMAGEO$
499 GOTO 200
600 GRAPHICS O:TRAP 610:FOR 1=1 TO 128
:'7 I;" ";ASC(PLAYERO$(I»:NEXT I:STOP
610 END
1999 REM SETUP ROUTINES FaLLOH:
2000 GOSUS 10000:REM MISC. INITI~LI
Z~T.lO
-
2005 GRAPHICS 7:REM SET GR. MODE
BEFORE PMG SET I I
2010 GOSUB 12000:REM DR~H PLRYFIELD
2015 GOSUB «(:REM PMG SETUP
2020 GOSUB 13000:REM PLRYER COLO. ND
SCREEN POSITION
2025 GOSUB 14000:REM DISPLRY MESSRGE
2130 RETURN
2999 REM ERROR CORRECTION ROUTINE
3000 IF XO >210 THEN XO=210
3010 IF XO<39 THEN XO=39
3020 IF YO<1 THEN YO=1
3030 IF YO>128 THEN YO=128
Try It / 129
3035 Z=O
3040 MXO=XO:MYO=YO
3050 01=0
3060 FIREO=O
3080 TRAP 3000:GOTO 300
10000 REM MISC. INITIRLIZRTION
10050 JOYSTICK=632:HPOSPO=53248:PRIOR=
623:MDVELEGS=30:SP=I:PR=8:BUTTONO=644:
SETSOUND=1000:S0=53760
10060 BUTTONO=644:SETSOUND=1000:S0=537
60:DVO=53761:HPOSMO=53252:HPOSMO=53252
100 7 0 P1=10:Dl=0:SD1=53762:DV1=53763:S
IZEM=53260:RANDOM=53770:POPF=53252:MOP
F=53248:HITCLR=53278:POKE HITCLR~1
10900 RETURN
10999 REM PffG SETUP ROUTINE
11000 DIM FILLER1$(1)~FILLER2$«INTCAD
RCFILLER1$)/I024)+1)*1024-ADRCFILLER1$
) -1 )
11010 DIM BUFFER$(384)~MISSILES$(128),
PLAYERO$(128)~PLAYER1$(128)~PLAYER2$(1
28)~PLAYER3$(128)
11020 BUFFER$=CHR$CO)
11030 BUFFER$(384)=CHR$CO)
11040 BUFFER$(2)=BUFFER$
11045 MISSILES$=BUFFER$:PLAYERO$=BUFFE
R$:PLAYER1$=BUFFER$:PLAYER2$=BUFFER$:P
LAYER3$=BUFFER$
11050 DIM LEGS1$(17),LEGS2$(17)~LEGS3$
( 17>
11060 FOR 1=1 TO 17:READ A:LEGS1$(I,I)
=CHR$(A):NEXT 1
11065 FOR 1=1 TO 17:READ A:LEGS2$(I,I)
=CHR$(A):NEXT I
11067 FOR 1=1 TO 17:READ A:LEGS3$(I~I)
=CHR$(A):NEXT I
11070 DIM MIMAGEO$Cl):MIMAGEO$=CHR$(3)
Save the program and then run it. Note I suggest you push the RESET
button each time before you run the program; this wi ll ensure that the PMG
image appears correctly when the program first starts. As you move the player
against the various wa lls of the maze, notice the va lues that appear in POPF
Next try firing the missile in various directions. Notice that sometimes the
missile w ill hit a wa ll. When this happens, the missi le sound stops and the
missile disappears. The player can now immediately fire another missile.
Sometimes the missi le wi ll go right "through a wa ll." That's because the
missile is moving in increments of 6. Actually, the missile is " hopping over the
wa lls" -it really never touches the wa ll-hence there is no co llision. This could
be fixed by making the wa lls thicker or the missile bigger. Or the miss ile
coord inates could be adjusted by I instead of 6. Of course, then the miss ile
would probably move too slowly for most purposes.
Yet another approach would be to use an assembly language routine to
move the miss ile. * In the programs in this book we'll simply let the miss ile pass
through walls. In a game situation, this effect is good because you never know
w hen one o f your miss iles w ill be "super-charged" and capable of passing
through a wall.
'Watch for my next book on advanced PMG techniques. In it 1'/1 show you how to use machine
language subroutines to speed up your PMG programs.
132 / Detecting Collisions
But with player-missile graphics, once we have come this far, it's easy to add
even more " features. "
41 XO=175:YO=80:
GOSUB 400:
POKE 704,PEEK(RANDOM):
PLAYERO$=BUFFER$:
POKE HPOSPO,XO:
POKE HITCLR,1:
RETURN
Also change line 499 to line 390 so that line 390 reads "GOTO 200."
As you can see the subroutine at line 400 rapidly moves different values
into player O's color register. This causes him to "glow." In the same loop we
also include a nice sound effect with the aid of a couple of SOUND statements.
(I used SOUND statements, here, rather than poking audio control registers,
because SOUND statements are easier to use. Remember, speed is not so
important here since we are not in the main loop. When a player is zapped, it's
Adding More Features / 133
natural for the action to stop. All attention is focused on the zapped player,
anyway.)
There you have it. Collision detection complete with a fancy routine to
zap a player and move him back to his starting location if he hits a specific kind
of playfield.
In the next chapter we'll pull together everything you've learned so far
and create "MAZEDUEL," a racing game in which two players compete for a
dangerous but valuable "crystaL"
Programming a Game
In this chapter I'll show you how to use the techniques you've learned to write
an arcade-style game. It doesn't have the speed of a machine language pro-
gram, but thanks to Atari's PMG it contains a lot of action-packed features:
animated players, sound effects, missiles, lasers, collision detection, and flash-
ing colors. And best of all, since you've come this far, you'll be able to mOdify it
to your liking. Before you know it. you'll be creating your own original gamesl
MAZEDUEL
Let's call the game "Mazeduel" since two players will be fighting it out as they
chase each other around a maze. I'll go over the rules of the game first and
then discuss the programming techniques.
Winning a round. The game will have rounds (sort of like a boxing match) .
In the upper right corner of the maze you'll see a magic Clystal. If a player
touches the crystal, an alarm will sound as the screen flashes different colors.
The player who touches the crystal wins the round and is awarded five points.
Both players will then be moved back to the starting box.
135
136 / Programming A Game
A player can also win a round by hitting the crystal with a missile. In this
case, however, that player gets only one point.
Firing missiles. Players can fire missiles at each other. Missiles contain a
strange substance that causes players to instantly expand to double size if they
are hit. If a player expands to double size, he stays that way until the other
player gets zapped.
If you are hit by a missile you will be zapped back to the starting box and
enlarged to double size. You get one point for hitting another player w ith a
miss ile.
Maze walls. You must exercise extreme caution when moving around the
maze. If you touch a maze wa ll, you are also zapped back to the starting box
and en larged to double size. In addition, the other player will gain a point.
Selecting colors. At the beginning of each game, you can select the color of
the playfield by pressing the SELECT key. Just keep pressing it (or hold it down)
until you get a co lor you like. When you're ready to start the game, press the
START key.
To se lect colors for players, press the OPTION key.
As usual, the complete listing appears at the end of this chapter. You may
wish to load the program from the previous chapter, MISSCOL.SAV, and then
mOdify it to produce MAZEDUEL.SAV I've made a lot of modifications, how-
ever, and it may be just as easy to type it in from the start.
Checking For Collisions / 137
For maximum execution speed, don't type in any of the REM statements.
I included them to help you understand the program (and to help myse lf keep
track of what I was doing).
Again, the subroutine beginning at line 2000 takes care of calling the
various setup subroutines. Here are the setup subroutines along with their
beginning line numbers:
Note that line 10000 is no longer a REM statement. If it were, the GOSUB
10000 statement at line 2000 would produce an error if you were to delete the
REM statements.
In the 13000 subroutine, at line 1345, I poke PLA YER1 S with the data in
LEG1S. Remember, PLAYER1S is the PM memory area for our second player.
PLAYEROS is the memory area for our first player. To simp lify the programming, I
made both players have exactly the same image. (They are easy to tell apart,
because each has its own COlor.)
Notice that in the subroutine starting at line 5000, I move the players onto
the screen and disp lay a message in the text window Location 53279 tells me
which of the console keys have been pressed. When 53279 contains a 6, I
know the user has pressed the START key and it's time to return from this
subroutine.
Control then returns to the "executive" setup subroutine at line 2000. I
call the subroutine at line 2000 an "executive" because it controls other sub-
routines rather than carrying out any direct action of its own. After the last
subroutine within the executive setup subro utine, control returns to line 1. From
there we jump to the main loop at line 200.
GOSUB PEEK(POPF)+100
ANSWER
So at line 100 we put a RETURN statement. Now, the magic crystal was
drawn using COLOR 2. So the magic crystal is considered a "COLOR 2 play-
field ."
ANSWER
The other collision detection subroutine calls work the same way Slick,
huh? And much faster than IF-statementsl *
MOVING LEGS
At line 204 we check to see if joystick 0 has been moved. JO is now a variable
initialized to 632, the memory location that contains the value forjoystick O. If JO
is not equal to 15 (uprightjoystickL then I add I to z. Z will now be equal to I. At
this point I GOSUB line 35 (34+Z will equal 35). Line 35 moves LEGl $ data into
PLAYEROS. The next time through the main loop, line 204 will call the sub-
routine at line 36 (since Z will now be equal to 2).
This is similar to the earlier leg movement routine. I modified the earlier
routine to make it easier to handle the movement of two separate players.
If the joystick is not moved, then control will pass to line 205. At line 205 I
simply move the "standing still" image of player 0 into PLA YEROS. I do a similar
thing for player I at lines 206 and 207.
* I'd like to thank my son, Dan Seyer, for suggesting this COllision detection method.
Missile Move Routine / 139
Suppose both missiles happen to occupy the same byte in missile memory.
(This will happen whenever MYO=MY1.j
ANSWER
Missile 0 will disappear! That's because the zeros in the far right bit position
of missile 1 will take the place of the I's that were there before.
Missile 0: 00000011
Missile 1: 00001100
ANSWER
Now if MYO does not equal MY1, the missiles are not destined to occupy
the same byte in missile memory. Consequently, I move the missile data for
each missile with separate statements in line 340.
Yes, the IF-statements do slow things down. You're right if you're think-
ing that this is a good place for a machine language subroutine. (Look for it in
my next book on PMG. j
After the missile data is moved into the proper byte of MISSILES, control
returns to line 200, the first line of the main routine.
Typing in the Program / 141
1. Make the crystal more interesting by creating him with PLA YER2S. You
can put PLAYER2S right on top of (or underneath) a playfield.
2. You could create a three-colored crystal by combining PLAYER2S with
PLAYER3S (see the next chapter for details) .
3. If you make the crystal with PMG, then you can make it glow by
poking different values into the appropriate color registers. You could
also easily animate it or change its size, with just a few statements. If
you do this at line 450 (the laser firing routine). you won't slow down
the main loop. That's because line 450 executes only when a laser is
fired by the crystal.
4. Using the other players, you might want to have various alien crea-
tures pop up in the maze and block the movement of the main two
players.
5. You may wish to experiment with changing the players to different
sizes at different times. Here are the size registers:
Value to Poke
Player Size into Register
Normal Oor2
Double 1
Quadruple 3
So for normal player size, poke the appropriate register with zero or 2.
For double player size, poke it with 1. For quadruple player size, poke it
with 3.
6. For faster action, you might want to try your hand at converting part of
the program to machine language. MAZEDUEL is written entirely in
BASIC. Again, look for my next book on PMG for hints on how to do
this! In the meantime, I suggest you keep reading your favorite maga-
zine for ideas. My favorites (in alphabetical order) are: .Analog, Antic.
Byte, Compute, Creative Computing, and Micro.
Happy hacking.
Congratulations. You've just about finished this book. By now, you've
mastered most of the fundamental s of PMG-one of the most powerful and
least understood features of the Atari computer.
In the next chapter, I'll wrap things up (at least for now). by discussing a
few additional PMG odds and ends.
25 Yl=Yl-SP:RETURN
26 RETURN :REM POP :PLAYERO$(YO)=LEGSl
$:POKE DVO~O:GOTO 210
29 REM MOVE LEGS OF PLRYER 0
35 PLAYERO$(YO)=LEGS1$:RETURN
36 PLAYERO$(YO)=LEGS2$:RETURN
37 PLAYERO$(YO)=LEGS3$:Z=0:RETURN
49 REM MOVE LEGS OF PLRYER 1
55 PLAYER1$(Yl'=LEGS1$:RETURN
56 PLAYER1$(Yl)=LEGS2$:RETURN
57 PLAYER1$(Yl'=LEGS3$:W=0:RETURN
65 MXO=MXO+MSO:MYO=MYO+MSO:RETURN
66 MYO=MYO-MSO:MXO=MXO+MSO~RETURN
67 MXO=MXO+MSO:RETURN
69 MXO=MXO-MSO:MYO=MYO+MSO:RETURN
70 MXO=MXO-MSO:MYO=MYO-MSO:RETURN
71 MXO=MXO-MSO:RETURN
73 MYO=MYO+MSO:RETURN
74 MYO=MYO-MSO:RETURN
84 REM RDJUST MISSILE 1
85 MX1=MX1+MSO:MY1=MY1+MSO:RETURN
86 MY1=MY1-MSO:MX1=MX1+MSO:RETURN
87 MX1=MX1+MSO:RETURN
89 MX1=MX1-MSO:MY1=MY1+MSO:RETURN
90 MX1=MX1-MSO:MY1=MY1-MSO:RETURN
91 MX1=MX1-MSO:RETURN
93 MY1=MY1+MSO:RETURN
94 MY1=MY1-MSO:RETURN
98 REM COLLISIONS
99 REM PLRYERO TO PLRYFIELD
100 RETURN
101 Sl=Sl+I:GOSUB ZAP:PLAYERO$=BUFFER$
:PLAYERO$(YO)=LEGS1$:GOSUB 5500:RETURN
102 SO=SO+5:GOTO 660:REM PLRYERO HITS
CRYSTRL/
103 Sl=Sl+1:GOSUB ZAP:PLAYERO$=BUFFER$
:PLAYERO$(YO'=LEGS1$:GOSUB 5500:RETURN
104 RETUF,N
105 RETURN
106 RETURN
107 Sl=Sl+1:GOSUB ZAP:PLAYERO$=BUFFER$
:PLAYERO$(YO)=LEGS1$:GOSUB 5500:RETURN
144 / Programming A Game
140 RETURN
141 RETURN
142 RETURN
170 MISSILES$=BUFFER$:DO=O:Dl=O:RETURN
:REM ERRSE MISSILE RND SOUND
199 REM MRIN LOOP
200 GOSUB PEEKCPOPF)+100:GOSUB PEEKCPl
PF)+109:GOSUB PEEKCMOPF)+118:GOSUB PEE
KCMIPF)+125
201 GOSUB PEEKCMIPL)+131:GOSUB PEEKCMO
PU +137
202 POKE HITCLR~I:YIA=Yl:XIA=XI:XOA=XO
:YOA=YO:REM CLERR COLLISION REGISTERI
SRVE PLRYER COORDINRTES
203 GOSUB PEEKCJO):GOSUB PEEKCJ1)+11:P
aKE HPOSPO~XO:POKE HPOSP1~Xl:REM .
RDJUST COORDINRTESIPOKE HOR. POSITION
10020 XO=52:YO=78:SP=3:Xl=67:Yl=78:MXO
=6:MYO=61:MX1=O:MYl =71:MOPL=53256:SDO=
53760:DVO=53761 : SD1 =53762:DVl=53763
10025 PO=50:Pl=53
10030 REM POKE 53248~XO:PLAYERO$(YO)=L
EGS1$:POKE 53249~Xl:PLAYER1$(Yl)=LEGSl
$
10040 POKE 53252~0 : POKE 53253~X1+3
10050 JO=632:J1=633:HPOSPO=53248:HPOSP
1=53249: HPOSMO=53252:HPOSMl=53253: BUTT
ONO=644
10055 BUTTON1=645:MSO=8
10060 RANDOM=53770:SIZEM=53260
10100 HITCLR=53278:POKE 53278~1:POPF=5
3252:PIPF=53253: MOPL =53256: MOPF=53248:
MIPL=53257:MIPF=53249
10110 PRIOR =623:ROUND=1:DIM STRING$(12
8):ZAP=500:ZAP2=530:0FF=170
10200 POKE HITCLR~l:REM CLERR S
COLLISIOC REGISTERS
10998 RETURN
11000 DIM FILLERl$(I)~FILLER2$«INT(AD
R(FILLERl$)/1024)+1).1024-ADR(FILLERl$
) - 1)
11010 DIM BUFFER$(384)~MISSILES$(128),
PLAYERO$(128) ,PLAYERl$(128) ,PLAYER2$(1
28),PLAYER3$(128)
11020 BUFFER$=CHR$(O)
11030 BUFFER$(384)=CHR$(0)
11040 BUFFER$(2)=BUFFER$
11045 MISSILES$=BUFFER$:PLAYERO$=BUFFE
R$:PLAYERl$=BUFFER$:PLAYER2$=BUFFER$:P
LAYER3$=BUFFER$
11050 DIM LEGS1$(17),LEGS2$(17),LEGS3$
( 17>
11055 RESTORE 11300
11060 FOR 1=1 TO 17:READ A:LEGS1$(I,I)
=CHR$(A):NEXT I
11065 FOR 1=1 TO 17:READ A:LEGS2$(I,I)
=CHR$(A):NEXT I
11067 FOR 1=1 TO 17:READ A:LEGS3$(I,I)
=CHR$(A):NEXT I
11069 DIM MIMAGEO$(I) : MIMAGEO$=CHR$(3)
150 / Programming A Game
Great! You've mastered the fundamentals of PMG and have seen how it can be
used to develop a two-player, arcade-style game. In this chapter you 'll learn
some additional programming kinks .
FIVE PLAYERS'
So far I've said that you can create up to four players and that each player has a
missile. Well, as you'll soon see, it's poss ible to have five players.
There is a trade-off, though: you have to give up all of your missiles. In
other words, if you want, you can use the missile memory area as a fifth player.
To do that you simply add 16 to the value you would normally poke into the
priority register.
Using the Priority Register. Remember the priority register? It is location 623.
You set various display priorities by poking either aI, 2, 4, or 8 into location 623.
(To review, see "Setting Display Priorities" in Chapter 5.)
Suppose you want all players to appear in front of all playfields. To set up
this display priority, you would normally poke a 1 into location 623. But if you
want to turn the missiles into a fifth player, you would poke 17 into 623 (1 +16).
153
154 / Odds and Ends
To help you keep track of what you're doing you might want to write the code
like this:
PRIOR=623
POKE PRIOR,1 +16
ANSWER
Setting the Fifth Player's Color. To specify the color you want for the fifth
player, poke a number from 0 to 254 into location 711. (To review, see " Specify-
ing Player Color" in Chapter 4.)
Moving the Fifth Player. Although some PMG programmers may have
problems with vertical movement it will be easy for you! Just use the same
method you learned earlier. Here's an example:
MISSILES$(Y4)=LEGS1 $
This statement will cause the image contained in LEGSI S to appear on
the screen at whatever vertical location is specified by Y4. (Remember YO goes
with player 0, YI with player I, Y2 with player 2, and so on. Remember, too, that
the fifth player is called Player 4 .)
POKE HPOSMO,X4
POKE HPOSM1 ,X4+2
POKE HPOSM2,X4+4
POKE HPOSM3,X4+6
Graphic Shape Registers / 155
All those POKEs add up and slow down the animation loop. So here's another
case where a machine language routine might come in handy, but that's the
subject of my next book.
Even though these separate horizontal position registers pose a speed
problem, you still might use them to good effect. For example, you might
"blow up" the fifth player and scatter his pieces all over the screen. Or you
might mysteriously create the fifth player by gradually moving his various
pieces together.
MULTICOLORED PLAYERS
So far each player has only one color But if you want. you can overlap player 0
with player I (or player 2 with player 3) In the area of overlap, a third co lor will
be produced. In effect. then , you can have a three-colored, animated object. To
make this work, you must first add 32 to the va lue that you would otherwise
poke into the priority register (location 623).
• Let's try a problem to clarify that. Suppose you want your players to have
priority over playfields. Normally. you'd poke I into 623. But let's say you
want a fifth player and you also want to combine player 0 and player I to
create a multicolored spaceship. How would you code the poke into
location 6237
ANSWER
to contain the PM shape data. And as you w ill recall , we told ANTIC where this
PM memory area was by poking the address of BUFFER into location 54279.
(To review, see "PMBASE" in Chapter 4.)
Also, we set up what is called "direct memory access" by poking location
559 with an appropriate va lue. In addition, we specified the type of resolution
we wanted by poking location 53277.
Well, if you use the graphic shape registers, you can bypass ANTIC, and
you don't have to poke anything into locations 54279, 559, or 53277. Conse-
quently, your PMG setup is greatly simplified.
But the graphics shape registers are not so great for animation. That's
because each can contain only one byte of data . They are useful, though,
when you want to display a player image the entire length of the screen. You
might want to do this to highlight textual material or to create a special
boundary for a playfield.
Here are the graphics control registers for each of the players:
The graphics shape register for all of the miss iles is at location 53265.
Even though each graphics shape register holds on ly one byte of image data,
that byte runs the entire length of the screen. You'll see an example of these
registers in action in a moment, but first I'd like to expand on DMACTL, the
direct memory access control register at location 559.
DMACTL
You can specify different options using this register. In the chart below,just add
up the options you want. Then poke the total into location 559. But note that
you must pick on ly one of the first four options:
Value to Poke
Option into 559
No playfield , , , , , . .... ... , . , . , . ,0
Narrow playfield . , , , , . , ........ , 1 (pick one)
Standard playfield ....... , ..... , .2
Wide playfield .... , . .......... .. 3
Sample Program / 157
Note: you won't be able to see the edges of the wide playfield unless
you scroll off the usual screen.
SAMPLE PROGRAM
As usual I will end this chapter w ith a sa mple program. The program illustrates
the use of:
1 GOTO 4
2 SAVE "D:GRAFP.SAV":STOP
4 ? CHR$(125):REM CLE~R SCREEN
5 POKE 752,1:REM TURN OFF CURSOR
7 GOSUB 500:REM SIMPLIFIED PMG SETUP
10 POSITION 2,10:? "In this e:<ample,"
20 ? "we ar-e NOT using"
25 ? "ANTIC or- Dir-ect"
30 ? "Memor-y Access"
? "to fetch PI ayer's "
33 ? "or- Missiles."
35 GOSUB 900:REM Wait for user to pres
s a key.
36 ? CHR$(125):REM CLE~R SCREEN
40 POSITION 24,9:? "Notice how easy"
42 POSITION 24,10:'7 "it. is to add"
158 / Odds and Ends
Player LocatIon
o 704
1 705
2 706
3 707
4 (miss iles ) 711
Co lor Number
Gray 0
Gold 16
Orange 32
Red 48
Pink 64
Vio let 80
Purpl e 96
163
164 / Appendix
Blue 11 2
Blue 128
Light Blue 144
Turquoise 160
Blue-Green 176
Green 192
Yellow-Green 208
Orange-Green 224
Light Orange 240
These numbers are starting numbers. To any given number you can add
an even number from 0 to 14 to change the lightness of the color.
PO KE 54279,ADR(BUFFER$)
Choose the options you want and add up their values . Poke the total into 559.
Option Value
No playfield 0
Playfield size:
Narrow 1
Standard 2
Wide 3
Turning on:
Missiles only 4
Players on ly 8
Missiles and p layers 12
Single-line resolution 16
Double-line resolution 0
Turn on DMA 32
Horizontal Coordinates / 165
53248 o
53249
53250 2
53251 4
Location Missile
53252 o
53253 1
53254 2
53255 3
Horizontal Coordinates
r i
i
I
I:i • • .. -,
II t ,f.
iI ti:l
II I ! I
50 80 1.20 .160 200
I
l______ _
HORIZONTAL
COORDINATES
166 / Appendix
Joystick Reading
Peek into these locations to read joystick values.
634 2
635 3
Joystick Values
This diagram shows the values produced when you move the joystick in
various directions. Note that if yo u do not move the joystick, a value of )5 is
produced.
.10 .14
.13
Sound Registers
Note: before using pokes to create sound, initialize the sound system
with:
POKE 53768,0
POKE 53775,3
(Or simply code: SOUND 0,0,0,0)
Location 53768 can be used to control the quality of sound. For example,
you can filter out certain frequencies or combine two channels to improve pitch
range and accuracy. See the book De Re Atari for details. (Available from Atari
Program Exchange.)
Missile Collisions
Player Collisions
Location Collision Shown
53260 Player 0 to player
53261 Player 1 to player
53262 Player 2 to player
53263 Player 3 to player
53252 Player a to playfield
53253 Player 1 to playfield
53254 Player 2 to playfield
53255 Player 3 to playfield
168 / Appendi x
Option Value
Combine missiles to make a 5th player. 16
Overlap players to make a third color. 32
169
-
....,
Index /171
A
Animation 47, 65 Images
B Defining 65
Binary numbers 10 How stored 6, 67
Boundary J
One K 21 Joystick control 51, 53
Two K 109 L
C Lasers 139
Chords 79 Leemon, Sheldon
Clearing strings 28 article on using strings 19
Collisions Legs, making move 65
Detecting 137 M
Registers 117 Machine language 131
Multiple 120 MAZEDUEL,SAV 142
Player 123 MISSCOL,SAV 126
Missiles 125 Missile
Reading 119 Horizontal position 92
COLOR 1 playfield 121 Image 89
Colors, selecting 136 Move routine 93
D Size register 103
Decimal numbers 15 Moving two players 138
Designing images 8 Multicolored players 43
Diagonal movement 50
DMACTL 38,156 o
Double line resolution 20 One K boundary 21
E ONSCREEN,SAV 43
Error routine 101 P
Errors, trapping 73 Pixel 6
F PM data, look at 61
Filler code 22 Priorities 55
Five players 153
G R
Game Programming 135 Random numbers
Garrett, B. B, in a game 139
on execution speed 118 missile size 104
GRACTL 39 Reading collisions 119
GRAFP.SAV 157 S
Graphic shape registers 155 Seyer, Dan
H collision detection
Highlighting text with PMG 157 routine of 137-138
Horizontal movement 49 Shadow register 55
HPOSPO 40 Simplified PMG setup 157
Index / 173