0% found this document useful (0 votes)
49 views

Atariplayermisslegraphicsinbasic

PMG allows for easy creation of custom graphic images called "players" that can be animated and have their own colors independently of the screen, enabling effects like 3D movement and animation with multiple colors that would be difficult on other computers. This book aims to make PMG accessible by walking the reader through everything needed to know to create sophisticated graphic effects with it.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views

Atariplayermisslegraphicsinbasic

PMG allows for easy creation of custom graphic images called "players" that can be animated and have their own colors independently of the screen, enabling effects like 3D movement and animation with multiple colors that would be difficult on other computers. This book aims to make PMG accessible by walking the reader through everything needed to know to create sophisticated graphic effects with it.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 196

ATARI® Player-Missile Graphics

ATARI® Player-Missile Graphics


in BASIC

Philip C. Seyer

A Reston Computer Group Book


Reston Publishing Company. Inc.
A Prentice-Hall Company
Reston, Virginia
LIbrary of Congress Cataloging In Publication Data

Seyer, Philip C.
Atari player missile graphics in BASIC.

"A Reston computer group book."


1. Computer games. 2. Atari computer-Programming.
3. Basic (Computer program language) 4. Computer
graphics. I. Title.
GV1469.2.S49 1984 794.8'2 83-21223
ISBN 0-8359-0112-2

©1984 by Reston Publishing Company, Inc.


A Prentice-Hall Company
Reston, Virginia 22090

All rights reseNed. No part of this book may be


reproduced, in any way or by any means, without
permission in writing from the publisher.

ATARI ® is a registered trademark of Atari, Inc., a Warner


Communications Company, Sunnyvale, California

10 9 8 7 6 5 4 3 2 1

Printed in the United States of America.


I would like to dedicate this book to my brother,
Mark and my dad, Herman, both of whom gave me
much encouragement and support.
Acknowledgments

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

This book is a self-instruction course in how to design and animate screen


images on the ATARI Computer. The book centers around what is ca lled
"Player-Missi le Graphics (pMG)".
The course will take you step-by-step through all of the fundamentals of
PMG and give you "progress checks" so that you can check your understand-
ing of the material presented. When you see a black square in the margin (like
this .), you will know I am about to ask you a question. Since the correct
answer is given immediately below the question, you may wish to cover it up
with a separate sheet of paper before you continue reading.
You will get the most from this book if you answer each question and
then compare your response with the one given. If your answer is incorrect. I
suggest you reread the material preceding the question and then answer it
again. When you're sure you understand, go on to the next section.
Most chapters end with a sample program. I suggest you enter each
program and save it under a unique name. Successive programs build on the
previous ones, so when preparing a new program, first enter the one you
typed in previously and then modify it.
Have fun! The programs all work. The one in Chapter 11 is quite involved
and may contain some hidden bugs. I invite your help. If you find any bugs or
come up with improvements, I would be delighted to hear from you. Write to
me in care of Reston Publishing Company. Inc. Reston, Virginia.

ix
-

-.
Contents

Chapter 1: Introducing PMG, 1


Easy Image Creation, I
Extra Colors, I
Three-Dimensional Effects, 2
Animation, 2
Not Just for Games, 2
Learning to Use PMG, 2
OveNiew of PMG Setup, 3

Chapter 2: Designing Player Images, 5


How Images are Stored, 6
One- and Two-Dimensional Images, 7
Designing a Player Image, 8
Lighting Up Pixels, 10
Converting the Image to Decimal Numbers, 15
More Practice, 16

Chapter 3: Dimensioning Strings for PMG, 19


Dimensioning Strings for PMG, 19
The Buffer String, 20
I K Boundary, 21
Starting on a I K Boundary, 22
Understanding the Filler Code, 22
Setting Up PM Memory, 24
Player Numbering, 25

xi
xii I Contents

Chapter 4: Getting a Player on the Screen, 21


Main Programming Tasks, 27
PMBASE,35
HPOSPO,40
Trying It Out, 42
An Assignment, 45

Chapter 5: Animating Your Player, 41


Animation Without a Joystick, 47
Joystick Control. 51
Modifying the Program, 53
Setting Display Priorities, 55
Changing Speed, 58
Looking at PM Data, 61

Chapter 6: Making Your Player Dance, 65


Defining Images, 65
Initializing the Image Strings, 67
An Experiment, 69
Trapping Errors, 73

Chapter 1: Adding Sound, 11


The Sound Statement, 77
Chords, 79
Poking Sound Parms, 80
Sound Registers, 81
More Experiments, 81
Using a Loop, 83
Using Pokes, 84
Adding Variety, 85

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

Chapter 9: Single-line Resolution, 109


Line 11000, 109
Line 11010, 110
Lines 11020 through 11040, 110
Lines 11045 and 11047, 110
Lines 11070 and 11330, 110
Line 11085, 111
Lines 5 through 14, 111
Line 10070, 111
Line 315, 111
Lines 3000 through 3080, 112

Chapter 10: Detecting Collisions, 117


Collision Detection Registers, 117
Assigning Variable Names, 118
Reading Collis ion Registers, 119
Multiple Collisions, 120
Clearing Collision Registers, 120
Using Collision Registers, 121
Drawing a Playfield, 121
Revising the Main Loop, 122
Player-Playfield Collisions, 123
Missile Collisions, 125
Try It, 126
Slow Player Movement, 131
Adding More Features, 132

Chapter 11: Programming a Game, 135


Mazeduel, 135
Checking for Collisions, 137
Moving Legs, 138
Crystal Defense System, 139
Miss ile Move Routine, 139
Typing in the Program, 141

Chapter 12: Odds and Ends, 153


Five Players!, 153
Multicolored Players, 155
Graphic Shape Registers, 155
xiv I Contents

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.

EASY IMAGE CREATION


Once you know how, you can easi ly create your own "custom made" graphic
images. Thanks to Atari 's special direct memory access system (OMA), it's
almost as easy as shading in squares on a piece of graph paper

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).

NOT JUST FOR GAMES


Atari first developed PMG to simplify game programming. But you can use
PMG anywhere that animation or special screen images and colors are useful.
For exa mple, in an educational program you could grab the learner's attention
with an animated arrow. The arrow could point out various parts of a diagram.
In a music program you could use players for notes and have them dance
across the screen along with the music. In a program that displays textual
material, you could use players to highlight important words or sentences.
Normally this is not so easy. Without PMG, graphic images cannot appear on
the same line with text.
PMG could be useful in business programs, too. For example, you could
design an animated warning routine to catch an operator's attention when a
crucial entry was required. It might even make the job more fun and cut down
on data entry errors.

LEARNING TO USE PMG


You may be saying to yourself: " If PMG is so great. why aren't more people
using itT Well for one reason, it has been really hard to learn-that is, up until
now. PMG is perhaps the most powerful, yet least understood, feature of the
Atari computer.
But relax. In this book we will take you step by step through everything
you need to know to create sophisticated graphic effects far beyond the reach
of most other micros.
OveNiew of PMG Setup / 3

OVERVIEW OF PMG SETUP


Here are the major programming tasks needed to set up PMG. (Don 't try to
understand all this right now. It's just an oveNiew. Details will come later.)

• 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:

1. Layout a player image on graph paper.


2. Figure out the binary data required in memory to create a player.
3. Calculate the decimal numbers needed to create a player image.
4. Sketch out the player images that would be created by various kinds of
data in memory.
5. Explain what distinguishes player-missile (PM) memory from ordinary
memory.

Let's begin by taking a look at the way graphic images are stored in
memory.

5
6 / Designing Player Images

HOW IMAGES ARE STORED


As you probably know, your Atari has several different graphics modes. In this
discussion, I will be referring to graphics modes 3 through 8. These modes are
for displaying pictures rather than words or letters.
An important graphics term is pixel, short for "picture cell." (Think of
"pic-cell .") A pixel is the smallest picture element possible. The size of a pixel
depends on the graphics mode you are in. This next illustration shows the
approximate size of a pixe l in graphics mode 3.

~-----------------------------------~
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 :

10 GRAPHICS 5:7 "WHAT GRAPHICS MODE WO


ULD YOU LIKE? ... (ENTER A NUMBER BETWE
EN 3 AND 8)"
20 INPUT GM:IF GM(3 OR GM)S THEN 10
30 GRAPHICS GM
40 COLOR 3
50 PLOT 30~18
60 ? "THIS IS A PIXEL IN GRAPHICS MODE
";GM
70 FOR PAUSE=1 TO lOOO:NEXT PAUSE
80 GOTO 10

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.)

ONE- AND TWO-DIMENSIONAL


IMAGES
Notice that image "A" above is not yet really a two-dimensional image. It has a
horizontal dimension, but no vertical dimension. Actually. it isjust a stubby line.
Let's make it into a two-dimensional image by turning on some pixels directly
beneath it on lines two and three .

....IL+<-E-- LINE 2
. - . or;: LINE 3

Now we have a two-dimensional image. It has height and width. In


ordinary RAM it would be hard to display this image. We would have to do a
8 / Designing Player Images

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 )

On the other hand, screen images are two-dimensional. They have a


horizontal and a vertical dimension. Fortunately, the Ata ri engineers simplified

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:

BVTE.1 BVTE2 BVTE3!


II
!
I!
4.JL ......... -+---(-
~(------------------------~

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.

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

Next make an image by shading in se lected squares on the grid. (Actu-


ally. each square on your grid represents a pixel on the display screen.) Here's
an example:

• 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

This number-000lll00-is called a binary number. Notice that it is com-


posed of just ones and zeros. As you may know, a binary 00011100 is not at all
the same as eleven thousand , one hundred (11 ,100).1'11 explain this shortly if you
don't understand binary numbers. For now,just remember that we are translat-
ing each row of our player into a binary number.

• 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)

• Now would you like to do the rest?

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

• So a binary 11 represents a decimal 3 since 2 + 1 = 3. What, then , would this


binary number represent?

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.

So this binary "111" represents a decimal 7 since 4 + 2 + 1 = 7.

• 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

This binary number is equa l to 255 since:

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,)

(.128) (64) (32) (.16) (8) (4) (2) U :' )

.11.1.1. .11J. 011.1 ,, !I I


Converting the Image to Decimal Numbers / 15

ANSWER

253 (It isjust two less than the previous example. Notice we now have a
"0" in the "2 box" instead of a"/."

• How about this one?

U.28) (64) (32) (16) (8) (4) (2) (1)

o 0011101J.loo. ! i i i !

// 16+4 = _ __

ANSWER

20

• Try one more.

(128) (64) (32) (16) (8) (4) (2) U .)

10IolJ.I~JI.110 0 0
II i
i
II !: I !
.--1..'_ _-,-I_ _~_-''--_ _

ANSWER

40 (32+8=40)

CONVERTING THE IMAGE TO


DECIMAL NUMBERS
Now you're ready to convert your own player image to decimal numbers.
Before you do that. however, you may wish to practice on some examples.
16 / Designing Player Images

• 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:

001 1 1 100 (4+8+16+32) a. 60


0001 1 1 00 (16+8+4) b. 28
o0 0 0 1 0 0 0 (8) c. 8
00011100 d.
00111010 e.
01011001 f.
00011000 g.
00101000 h.
01001100 i.
01 0 00100 j.
01000100 k.

ANSWER

a. 28 g. 24
b. 28 h. 40
c. 8 i. 76
d. 28 j. 68
e. 58 k. 68
f. 89

If you'd like mo re practice in ca lculating decimal numbers, yo u may wish


to try thi s next one. Otherwise, o n to the next chapter. I ca n't wa it to show you
a new, little-known method for allocating PM memory!

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.

DIMENSIONING STRINGS FOR PMG


Using this approach, you dimension a separate string at the beginning of your
program for each of your "players." Also, you dimension one string for the
missile area. In dimensioning these string s, there are certain rules yo u must
keep in mind .

'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

THE BUFFER STRING


One rule is that the beginning of PM memory is not used to display graphic
images directly. That is, data in this beginning area are not automatically
displayed on the screen. In this book, we will call this beginning area of PM
memory a buffer.
If you want you can store player image data in the buffer and then move
it to the display area whenever you want to. Here's a diagram that shows the PM
memory area ., See if you can distinguish between the buffer and display areas.

PLAYER 3
PLAYER 2
PLAYER 1. ! 128 BYTES

PLAYER 0
H3 I H2 I H1 I HO

BUFFER 384 BVTES

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).

• Study the diagram. Then answer these questions.

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

3. Where does the PM display area start?


a. 384 bytes past the beginning of the PM memory area .
b. At the very beginning of PM memory area.
c. Neither a nor b.

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.

• Which of these are on a 1K boundary?


a. 4096
b. 3073
c. 3072

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."

UNDERSTANDING THE FILLER CODE


Since you're so interested in the filler code, I'll rewrite it for you in a slightly
different way so it's easier to understand:

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.

20 BOUNDARY = INT(ADR(FILLER1$) / 1024 + 1)*1024

In line 20 we calculate the address of the next 1K boundary above the


address of FILLER1S. We do this by dividing the address of FILLER1S by 1024,
Understanding the Filler Code / 23

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)

In line 30 we simply subtract the address of FILLERI S from the 1K boun-


dary and then subtract 1 from that. We subtract 1 because we want FILLER2S to
fill up space right up to (but not over) the lK boundary.
We still need to find the length of our second string, namely FILLER2S. If
we subtract the address of FILLERI S from the next 1K boundary, we would get
8, since 2048 - 2040 = 8. But to get the proper length for FILLER2S, we need to
subtract 1 from 8 (since we want to take up space just up to the 1K boundary).
Look at this diagram:

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

BUFFER 384 BVTES

• 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

• Actually, line 20 isn't finished yet. Can you explain why?

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.

• With this in mind, see if you can finish line 20:

20 DIM BUFFERS(384)

ANSWER

20 DIM BUFFERS(384), MISSILESS(128) . PLAYER I 5(1 28), PLAYER2S(l28),


PLAYER3S(l28)

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

4608 (4480+I * 128=4608)


26 / Dimensioning Strings for PMG

• 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:

• Write the code needed to get a player on the screen.


• Put the player anywhere you want by specifying horizontal and vertical
coordinates.
• Make the player any desired color.
• Use double-line resolution.

To start with, let's go over the main programming tasks required to get a
player on the screen.

MAIN PROGRAMMING TASKS


I. Define filler strings so that the PM strings area can start on a 1K
boundary.

2. Allocate space for the PM memory area.

27
28 / Getting A Player on the Screen

3. Set the PM memory area to zeros.

4. Dimension a separate string for holding our player image data.

5. Put our player data into that string.

6. Specify the co lor of our player.

7. Specify the location of PM memory.

8. Specify double-line resolution.

9. Turn on PMG.

10. Specify the desired horizontal location of the player.

11 . Put player image into the desired vertical location.

You have already learned to write the code for steps 1 and 2, so let's go
on to step 3.

Setting the PM Memory Area to Zeros


When you run a program, the data in the string area is not automatically
cleared out. That's why we need to explicitly set the PM memory area to zeros.
Let's start with BUFFERS. Here's a quick way to set it to zeros:

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:

11010 DIM BUFFER$(384)


11020 BUFFER$="X"
Main Programming Tasks / 29

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

Now, change line 11020 so that it reads:

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

Zeros, of course! Remember. in memory. a bit always contains either a one


or a zero.
30 / Getting A Player on the Screen

To see the zeros in BUFFERS, try running this program:

11060 FOR 1=1 to 384


11070 ? ASC(BUFFER$(I))
11080 NEXT I

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

Player Image String


Besides dimensioning the PM memory area and setting it to zeros, we need to
dimension a string to hold our player image data. We'll call it "IMAGE1S,"
meaning " image one for player one." As you will see later, we will want to
have more than one image for each of our players so that we can do things like
make their legs move.
Dimensioning the string is easy:

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."

Referencing Specific Bytes


In Atari BASIC, you can refer to specific sections of a string variable by numbers
in parentheses after the name of the string. The first number gives the starting
Main Programming Tasks / 31

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)

• How would you refer to byte 15 of STORAGES?

ANSWER

STORAGES(15.15)

Putting Data into IMAGE1S


To get out player image data into the string we use a "FOR-NEXT" loop. Our
first statement in this loop is:

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

When we created our player, we had 15 rows in our matrix. We had a


number for each row. These numbers will first be stored in data state-
ments. Each time through the loop we will read a number and then put it
into IMAGEIS. Since we will be adding two rows of zeros at the top of the
matrix and two rows at the bottom, we have 15 numbers altogether.

Here is the complete loop for putting all 15 numbers into IMAGEI $:

FOR 1 = 15:READ A: IMAGE1$(I,I) = CHR$(A):NEXT I

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.

IMAGE1SfUI=CHRSfAI This statement puts the number into successive bytes


of IMAGEI $. Note the (1,1). The first time through the loop the variable I will be
set to I. So the statement will be equivalent to:

IMAGE1 $(1,1 )=CHR$(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)

• What does this mean?

ANSWER

Set the second byte of IMAGEI $ to the contents of A.

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.

• What do you think would happen if we simply wrote:

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.

Specifying Player Color


You can eas ily control the color of a player by putting a number into a memory
location. Here are the locations for each of the players:

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.

• Would 48 give you a bright red or dark red color?

ANSWER

Dark

• What number would you use for a light red?

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.

Poking the Color Number


You can use the Poke command to specify the player's co lor. To specify a dark
gold color for player 0, you might write:

POKE 704,16

• Write a command to set player 2's color to dark violet.

ANSWER

POKE 706,80 (You might also use 82, 84, or 86 for dark violet. The lower the
number, the darker the color.)

Specifying Start of PM Memory


The Atari microprocessor ca lled ANTIC automatically takes care of displaying
PM images on the screen. But before ANTIC can do that we have to tell it
where PM memory starts. To do that we simply POKE the proper address into
location 54279. Since our PM memory area is string memory, we can use the
PMBASE / 35

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

BUFFERS (Remember this area? It's sort of a multipurpose PMG storage


area. Data stored here does not display on the screen).

• 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

POKE 54279,ADR(BUFFERS) (We poke the address of BUFFE;RS into 54279


because the address of BUFFERS is the sa me as the address of the start of
the PM memory area.)

PMBASE

Location 54279 is known as the Player-Missile Base Register (PMBASE). If you


initialize a variable called PMBASE to 54279 at the beginning of the program
like this

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:

• Which kind of resolution gives you a more "blocky" looking character?


Which one looks more "detai led"?

ANSWER

Double-line resolution results in a more "blocky" looking player. You get a


more detailed looking figure with single-line resolution.

• 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

If we were to use single-line resolution we would need twice as many


bytes for each player because each bit in memory on ly lights up one pixel.

• How many bytes would each player need in single resolution?

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:

If you want: Then:


Missiles only POKE 53277,1
Players only POKE 53277,2
Players and missiles POKE 53277,3

• Suppose you want to use players and missiles. How do you specify this
with the GRACTL register?
PMBASE / 39

ANSWER

POKE 53277.3

Using Register Abbreviations


If you want you can also initialize the variable GRACTL to 53277 at the begin-
ning of your program like this:

GRACTL=53277

Then, to turn on PMG with both players and missiles, you could write:

POKE GRACTL,3

• Can you think of a disadvantage in doing it this way? An advantage?

ANSWER

It takes a little more memory to initialize GRACTL to 53277. Also, it uses up


a variable. In Atari BASIC you are limited to 128 variables. The advantage is
that your code is somewhat easier to read.

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:

• Write a statement to put player 0 at the:

1. Left edge of the screen.


2. Right edge of the screen.
3. Center of the screen.
HPOSPO / 41

ANSWER

I. POKE 53248,50 or POKE HPOSO.50


2. POKE 53248.200 or POKE HPOSO.200
3. POKE 53248.120 or POK E HPOSO.120

• Where do you think the horizontal position register is for:


1. player 1
2. player 2
3. player 3

ANSWER

1. HPOSPI=53249 (one more than 53248)


2. HPOSP2=53250
3. HPOSP3=5325 1

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:

POKE 53248,H1 or POKE HPOSO,H1

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.

• If we wanted to position our player at vertica l position 80, we would poke


the image data into the 80th byte of the player string. Altogether our player
string has 128 bytes, so how many vertical positions do we have available?

ANSWER

128 (since each player string has 128 bytes) .

• 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

1 GOSUB 2000:REM SETUP ROUTINES


2 GOTO 200:REM JUHP TO MRIN ROUTINE
3 SAVE "D:ONSCREEN.SAV":STOP :REM DISK
30
199 REM MRIN ROUTINE
200 FOR KOLORO=O TO 254 STEP 2
210 POKE 704,KOLORO
220 ? "PLAYER COLOR NUMBER=";KOLORO
230 GOSUB DELAY
240 NEXT KOLORO
250 END
260 REM
270 REM
280 REM
290 REM
1999 REM SETUP ROUTINES FOLLON~
2000 GOSUB 10000:REM MISC. INITIRL-
IZRTION
2005 GRAPHICS 5:REM SET GR. MODE
BEFORE PHG SETUP!
2010 GOSue 11000:REM PMG SETUP
2015 GOSUB 12000:REM DRRW PLRYFIELD
2020 GOSue 13000:REM PLRYER COLOR RND
SCREEN POSITION
2130 RETURN
5000 FOR PAUSE=1 TO 500:NEXT PAUSE:RET
URN
10000 REM MISC. INITIRLIZRTION
10050 DELAY=5000:RETURN
10999 REM PHG SETUP ROUTINE
11000 DIM FILLER1$(I),FILLER2$«INT(AD
R(FILLER1$)/I024)+1)*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 IMAGE1$(15)
44 / Getting A Player on the Screen

11060 FOR 1=1 TO 15:READ A: IMAGE1S(I,I


)=CHRS(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.

11090 POKE 53277 , 3 : REM TURN ON PMG


11095 RETURN
11300 DATA 0 , 0 , 28,28,8,28,58 , 89,24,40,
76,68,68,0,0,
11999 REM DR~M PL~YFIELD
12000 SETCOLOR 4,16,2:COLOR 1
12010 PLOT 0,20:DRAWTO 40,20
12020 COLOR 3 :DRAWTO 60, 3 5 : COLOR 2:DRA
WTO 79,35
12030 RETURN
12999 REM SET PL~YER COLOR ~ND
POSITION
13000 XO=175:REM HORIZONT~L PL~YER
POSITION .
13010 YO=73:REM VERTIC~L PL~YER
POSITION
13020 POKE 704,0:REM INITI~LIZE PLRYER
COLOR TO ZERfJ
13030 POKE 53248,XO:REM POKE HORI-
ZONT~L VRLUE INTO HORIZONTON~L
POSITION REGISTER.
13040 PLAYEROS(YO)=IMAGE1S:REM PUT
IM~GE INTO PROPER BYTE OF PL~YERO. YO
DETERMINES VERTIC~L POSITION
13050 RETURN

Line 1: GOSUB 2000 As you ca n see I start the program by "calling" a


subroutine at line 2000. The purpose of this subroutine is to take care of w hat
are sometimes called " housekeeping routines." These are routines that you
usually only need to do once at the beginning o f the prog ram . By using high
line numbers for these setup routines, I leave space at the beginning of the
program for the main routine . This is preferable because routines requiring
transfer of contro l (GOTOs or GOSUBs) execute faster if they are placed at the
beginning. This w ill become more important later w hen our main routine
becomes more compl ex.
An Assignment / 45

Notice that the subroutine at line 2000 calls these additional setup
routines:

10000 Miscellaneous Initialization


11000 PMG Setup
12000 Drawing of Playfield
13000 Beginning Player Color and Screen Position

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 3: SAVE "D:ONSCREEN.SAV":STOP I use this line to save the pro-


gram to disk after I've made changes to it. It's really quite handy. After I've
finished editing the program, Ijust type G.3 and the program starts saving itself!
(Atari understands that "G." is an abbreviation for "GOTO.") Notice the com-
mand "STOP" at the end of line 3. This keeps the program from continuing to
execute after it saves itself.

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.

ANIMATION WITHOUT A JOYSTICK


Once you have a PMG setup routine working, it's quite easy to produce
different results with minor program changes. In the program in the previous
chapter we establ ished the position of our player with the statements "XO=175"
and "YO=75." We used XO to specify the horizontal position and YO to specify
the vertical. In our new animation program, we will still use these statements to
tell where we want the player first positioned. But after that we will set up a
loop in which we will either increase or decrease the values in XO and YO. (We
will use XO for the horizontal position of player 0 since "X" in mathematics
tradiitionally refers to the horizontal plane. Similarly, "Y" usually refers to the
vertical plane. So I use YO to control the vertical position of the player.)

47
48 / Animating Your Player

Main Program Loop


Here is the start of the main loop of our new program.

• As you examine this code, see if you ca n tell which statement puts the
program into a never-ending loop.

1 GOSUB 200:GOTO 190


2 SAVE "D:MOVE.SAV":STOP
190 SP=1
200 POKE 53248,XO
220 PLAYERO$(YO)=IMAGE1 $
230 GOTO 230

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

I. Delete lines 2,3,200,210,220,230,240, and 250


2. Change lines 1 and 13020 to read as follows:

1 GOSUB 2000:GOTO 190


13020 POKE 704,88

3. Add these lines:

2 SAVE " D :MOVE1 .SAV" :STOP


190 SP=1
200 POKE 53248 ,XO
220 PLAYERO$(YO)=IMAGE1$
225 YO=YO-SP
230 GOTO 200

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

Here's one way of doing it:


200 POKE 53248,XO
220 PLAYEROS(YO) =IMAGEIS
225 YO=YO+SP
227 XO=XO+SP
230 IF YO>45 THEN YO=45
235 IF XO>125 THEN XO=125
240 GOTO 200

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

To control the movement of a player with a joystick, you need to:

• Read the joystick,


• Figure out the position that the stick has been moved to,
• Change the value of XO or YO accordingly.

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)

Forjoystick 1 we would use "PEEK(633)," forjoystick 2, "PEEK(634)" and so on.

Now, to handle the joystick value without "IF-statements," we will


simply use a GOSUB command. A powerful feature of Atari BASIC is that you
can use a PEEK command in combination with a GOSUB statement.

• 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

Now suppose we write this statement:

GOSUB PEEK (632)

• To which subroutine will the program go if you pull back on thejoystick?

ANSWER

It will go to the subroutine starting at line 13 (since location 632 will contain
a 13 when the JOystick is pulled backward)

MODIFYING THE PROGRAM


Now let's mOdify our program again. At line 10050 let's initialize a variable
called "JOYSTICK" to 632. And while we're at it, let's initialize HPOSO to 53248,

*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

and SP to 1 also at line 10050. Then we ca n peek into "JOYSTICK" to determine


w hich subroutine to execute. Line 10050 w ill then read:
10050 JOYSTICK=633:
HPOSPO=53248:
SP=1 :
RETURN
Our main loop w ill then look like this:

200 GOSUB PEEK(JOYSTICK):


POKE HPOSPO,XO :
PLAYERO$(YO)=IMAGE1 $:
GOTO 200

Now we also need something at lines 5, 6,7,9,10,11,13,14, and 15. Here


are lines 5, 6, 7, 9, and 10:

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:

1 GOSUB 2000:GOTO 200

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.

SETTING DISPLAY PRIORITIES


Another nice feature of PMG is that you can make players hide behind certain
playfield objects, yet come out in front of others. This is called setting display
priorities (or often simply "picking a priority option"). When you are program-
ming in BASIC, you'll use memory location 623 as the priority register. * (This
register is also used for other purposes, but one thing at a time!)
You can set various display priorities by poking either I, 2, 4, or 8 into
location 623. If you poke 1 into location 623, players will show up in front of all
playfields. Furthermore, player 0 will appear in front of player I, player I will
appear in front of player 2, and so on.
If you poke 2 into location 623, then players 2 and 3 will appear behind
all playfield Objects. Players 0 and I will still appear in front of all playfield
Objects.
If you poke 4 into location 623, then all playfields will appear in front of
all players.
If you poke 8 into location 623 , then players will go behind some
playfields and in front of others. In our sample program players will go behind

*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

1 GOSUB 2000:GOTO 200


2 SAVE "D:MOVE1.SAV":STOF' :REM DIS!; 30

4 REM ADJUST HORIZONTAL & VERTICAL


COORDINfHES
5 XO=XO+SF':YO=YO+SF':RETURN
6 YO=YO-SP:XO=XO+SF':RETURN
7 XO=XO+SF':RETURN
9 XO=XO-SF':YO=YO+SF':RETURN
10 XO=XO-SF':YO=YO-SF':RETURN
11 XO=XO-SF':RETURN
13 YO=YO+SF':RETURN
14 YO=YO-SF':RETURN
15 RETURN
199 REM MAIN LOOP
200 GOSUB F'EEK(JOYSTICK):POKE HPOSPO~X
0:PLAYERO$(YO)=IMAGE1$:GOTO 200
260 REM
270 REM
280 REM
290 REM
1999 REM SETUP ROUTINES FOLLON:
2000 GOSUB 10000:REM MISC. INITIALI-
ZATION
2005 GRAPHICS 5:REM SET GR. MODE
BEFORE PHG SETUP!
2010 GOSUB 11000:REM PHG SETUP
2015 GOSUB 12000:REM DRAM PLAYFIELD
2020 GOSUS 13000:REM PLAYER COLOR AND
SCREEN POSITION
2130 RETURN
10000 REM MISC. INITIALIZATION
10050 JOYSTICK=632:HPOSPO=53248:SP=1:R
ETURN
10999 REM PHG SETUP ROUTINE
11000 DIM FILLER1$(1)~FILLER2$«INT(AD
R(FILLER1$)/l024)+1)*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$
Setting Display Priorities / 57

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.

11090 POKE 53277~3:REM TURN ON PMG


11095 RETURN
11300 DATA 0~0,28,28,8,28,58,89,24~40,
76~68,68,0,0
11999 REM DR~W PL~YFIELD
12000 SETCOLOR 4,16,2:COLOR 1
12010 PLOT 0,20:DRAWTO 40,20
12020 COLOR 3:DRAWTO 60~35:COLOR 2:DRA
WTO 79,35
12030 RETURN
12999 REM SET PL~YER COLOR ~ND
POSITION
13000 XO=52
13010 YO=12
13020 POKE 704,88
13030 POKE 53248,XO:REM POKE HORI-
ZONT~L V~LUE INTO HORIZONTON~L
POSITION REGISTER.
13040 PLAYERO$(YO)=IMAGE1$:REM PUT
IM~GE INTO PROPER BYTE OF PL~YERO. YO
DETERMINES VERTIC~L POSITION
13050 RETURN

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

I. Change line I so that it reads :

GOSUB 4000:GOSUB 2000:GOTO 200

2. Add this subroutine starting at line 4000:

4000 ? "What number would you like to poke into the


priority register?":INPUT PR

4020 RETURN

3. At line 10050 set the variable PRIOR to 623.


4. Delete the RETURN statement at line 11095.
5. Add line 11110 as follows:

POKE PRIOR,PR

6. Put a RETURN at line I I 299.


7. Change line 2 to:

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 .

Experiment with Different Speeds


To experiment with different speeds, try adding line 4010 as follows :
Changing Speed / 59

?"ENTER A NUMBER BETWEEN 1.0 AND 2.0 TO SET


SPEED OF PLAYER.":INPUT SP:RETURN

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:

0,0,28,28,8,28 ,58 ,89,24,40,76,68,68,0,0

• Notice that the first two bytes of IMAGEI $ contain zeros. What do the last
two bytes contain?

ANSWER

They conta in zeros also.

*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 $

The diagram below shows what will be in each byte of PLAYEROS

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

We would need to dimension IMAGEIS for 17 bytes. Then we would need


to make bytes 1- 3 and bytes 15- 17 zeros. IMAG EI Swould then contain this
data:

0,0,0,28 ,28 ,8,28 ,58 ,89 ,24,40,76,68,68,0,0, °


To make this change, we wo uld need to change line 11300, so the data
matches that given above. We wo uld also need to change line 11050 so that it
reads:

11050 DIM IMAGE$(17)

And line 11060 should be

11060 FOR 1=1 TO 17:


READ A:
I MAGE1 $(I ,I)=CHR$(A):
NEXT I

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.

600 GR.O:TRAP 610 : FOR 1=1 to 128:


? I;" ";ASC (PLAYERO$(I)) :
NEXT I:STOP
610 END

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.

1 GOSUB 4000:GOSUB 2000:GOTO 200


2 SAVE ID:MOVE2.SAV":STOP :REM DISI( 30

4 REM RDJUST HORIZONTRL & VERTICRL


COORDINRTE S
5 XO=XO+SP:YO=YO+SP:RETURN
6 YO=YO-SP:XO=XO+SP:RETURN
7 XO=XQ+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 F~ETURN
199 REM MRIN LOOP
200 GOSUB PEEKCJOYSTICK):POKE HPOSPO,X
O:PLAYERO$CYO)=IMAGE1$:GOTO 200
26',) REM
270 REM
280 REM
290 REM
600 GRAPHICS O:TRAP 610:FOR 1=1 TO 128
:7 I; " ";ASCCPLAYERO$CI»:NEXT I:STOP
Looking at PM Data / 63

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

10000 REM MISC. INITIRLIZRTION


10050 JOYSTICK=632:HPOSPO=53248:PRIOR=
623: RETURN
10999 REM PMG SETUP ROUTINE
11000 DIM FILLER1$(1),FILLER2$«INTCAD
R(FILLER1$)/I024)+I)*1024-ADRCFILLER1$
) -1)
11010 DIM BUFFER$(384),MISSILES$(128),
PLAYERO$(128),PLAYER1$(128),PLAYER2$(1
28),PLAYER3S(128)
11020 BUFFER$=CHR$(O)
11030 BUFFER$(384)=CHR$CO)
11040 BUFFER$(2)=BUFFER$
11045 MISSILES$=BUFFER$:PLAYERO$=BUFFE
R$:PLAYER1$=BUFFER$:PLAYER2$=BUFFER$:P
LAYER3$=BUFFER$
11050 DIM IMAGE1$CI7)
11060 FOR 1=1 TO 17:READ A:IMAGE1$(I,I
)=CHR$CA):NEXT I
11080 POKE 54279,ADRCBUFFERS)/256:REM
DTELL ANTIC WHERE START OF PM MEMORY I
S
11085 POKE 559,46:REM DOUBLE LINE RES.

11090 POKE 53277,3:REM TURN ON PMG


11110 POKE PRIOR,PR
64 / Animating Your Player

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«'

And here's the second image with accompanying data.

/
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

INITIALIZING THE IMAGE STRINGS


Now that we've designed the images, we need to initialize our player image
strings. Remember how we do it? To initialize our First image, we use a line like
this

11060 FOR 1=1 TO 17 :READ A:


LEGS1 $(I,I)=CHR$(A):NEXT 1

• The data For this w ill appear on line 11300 like this

11300 DATA 0,0,0,28,28,8,28,58,89,24,60,36,36, 102,0,0,0

Notice that we added


And three trailing zeros.
three leading ze ro s.

• Why did we do that7


68 / Making Your Player Dance

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:

11065 FOR 1=1 TO 17:READ A:


LEGS2$(I,I)=CHR$(A):NEXT I

Of course we also need to add the data for LEGS2$. We do that on line 11310:

11310 DATA 0,0,0,28,28,8,28,58,89,


24,40,76,68,68,0,0,0

• Your turn again. Write the lines needed to initialize the third player image.
I'll supply the line numbers.

11067
11320

ANSWER

11067 FOR 1=1 to 17READ A:


LEG53S (I,lj =CHRS(Aj
NEXT I

11320 DATA 0,0,0,28,28,8,28,58,89,


24,56,72,132,130,0,0,0

Oh yes, another thing. We need to dimension our new strings. We can


easily do this on line 11050:

11050 DIM LEGS1$(17), LEGS2$ (17), LEGS3$(17)

• 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:

11050 DIM LEGS1$(17), LEGS2$ (17), LEGS3$ (17)

3. Add lines 11060, 11065, and 11067:

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

4. Add these data lines:

11300 DATA 0,0,0,28,28,8 ,28,58 ,89,


24 ,60 ,36,36 ,1 02,0,0,0

11310 DATA 0,0,0,28,28,8,28,58,89 ,


24,40,76 ,68,68,0 ,0,0

11320 DATA 0,0,0,28,28,8,28,58,89,


24,56,72,132 ,130,0,0,0
70 / Making Your Player Dance

5. Change line 200 so it reads like this:

GOSUB PEEK(JOYSTICK):
GOSUB MOVELEGS:GOTO 200

6. Insert at line 10050:

MOVELEGS=30:
SP=1:
PR=8

7. Add a subroutine at line 30 as follows:

30 POKE HPOSPO, XO:


PLAYERO$(YO)=LEGS1 $:
PLAYERO$(YO)=LEGS2$ :

31 PLAYERO$(YO)=LEGS3$ :
RETURN

8. Change line 13040 so it reads:

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 :

Z=Z+1 :POKE HPOSPO,XO:


IF Z<4 THEN PLAYERO$(YO)=LEGS1 $:
RETURN

Notice the "RETURN" statement that sends control back to the main loop at
line 200.

• Suppose we want image two to be displayed during loop passes 4


through 6. Code the two statements needed to make that happen. Use
line 31.

ANSWER

31 IF Z< 7 THEN PLAYEROS[YO) =LEGS2S


RETURN

Following the same pattern, we might want to display image three


during loops 7 through 9. W e don't need an IF-statement this time. If Z is 7 or
greater, control will simply pass to line 32. At line 32 we simply set PLAYEROS to
the third image. However, w hen X=9, we will want to reset Z to 0 so that next
time image one will be displayed.

• See if yo u can code the statements for line 32.

ANSWER

Here's how I did it:

32 PLA YERO$(YO) =LEGS3 $:


IF Z=9 THEN Z=O:
RETURN

• 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.

Try it Make sure lines 30 through 33 read like this:

30 Z=Z+1 :POKE HPOSPO,XO:


IF Z< 4 THEN PLAYERO$(YO)=LEGS1$:
RETURN

31 IF Z< 7 THEN PLAYERO$(YO)=LEGS2$ :


RETURN

32 PLAYERO$(YO)=LEGS3$:
IF X=9 THEN X=O:
RETURN

33 RETURN

• Try this out What additiona l prob lem is there?

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:

1. Change line 1 so it reads like this


1 TRAP 3000:GOSUB 2000:GOTO 200

2. Add line 3000:

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.

• What do you think line 3000 says?

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!

1 TRAP 3000:GOSUB 2000:GOTO 200


2 SAVE "D: LEGS. SAV": STOF' : REM DIS!; 30
4 REM RDJUST HORIZONTRL & V£RTICRL CO-
I}RDINRT£S
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 200
29 REM MOVE PLRY£R"S LEGS
30 Z=l+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 MRIN LOOP
200 GOSUB PEEK(JOYSTICK):GOSUB MOVELEG
S:GOTO 200
260 REM
270 REM
2'80 REM
290 REM
Trapping Errors / 75

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 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

11085 POKE 559,46:REM DOUBLE LINE RES.

11090 POKE 53277~3:REM TURN ON PMG


11110 POKE PRIOR,PR
11299 RETURN
11300 DATA 0,0,0,28,28,8,28,58~89~24~6
0,36,36~102,O,0,0
113~0 DATA 0,0,0,28,28,8,28,58,89,24,4
0,76,68,68,0,0,0
11320 DATA 0,0,0,28,28~8,28,58,89,24,5
6,72,132,130,0,0,0
11999 REM DR~N PL~YfIELD
12000 SETCOLOR 4~16,2:COLOR 1
12010 PLOT 0,20:DRAWTO 40,20
12020 COLOR 3:DRAWTO 60,35:COLOR 2:DRA
WTO 79,35
12030 RETURN
12999 REM SET PL~YER COLOR ~ND
PI}SITION
13000 XO=52
13010 YO=12
13020 POKE 704,88
13030 POKE 53248,XO:REM POKE HORIZON-
T~L V~LUE INTO HORIZONTON~L POSITION
REGISTER.
13040 PLAYERO$(YO)=LEGS1$:REM PUT
IM~GE INTO PROPER BYTE Of PL~YERO.
·13050 RETURN
Adding Sound

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.

THE SOUND STATEMENT


Most Atari BASIC programs use the SOUND statement. It's a powerful state-
ment because it enables you to control the pitch, distortion, and volume for
each of four "voices."
Yes, Atari has four voices. Before we get into the details of the SOUND
statement, let's consider what is meant by the term "voice." Think of a four-
voice choir. In such a choir there are four separate groups of singers. Each

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:

Name of Voice Range


Soprano (Usually sings highest notes)
Alto (Next to the highest notes)
Tenor (Next to the lowest notes)
Bass (Lowest notes)

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

Middle C. (121 is the value for Middle C. remember.)

Try it Then enter this command:

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

Yes. The volume parms add up to exactly 32 (8+8+8+8=32).

POKING SOUND PARMS


Because of its ease of use, you may choose to use the SOUND command in
your programs. But if you are coding an animation sequence for, say. a game or
other simulation, then it may be better to poke sound parms directly into
memory. SOUND statements execute more slowly than direct pokes.
Here's how you poke sound parms. To set the pitch of voice 0, simply
poke a number into memory location 53760 . To set the distortion and volume,
first multiply the desired distortion number by 16 and add it to the value for
volume. Then poke this one number into 53261.
For example, instead of writing SOUND 0,121,10,8, you would write:

POKE 53760,121
POKE 53761,168

(We poked 168 into 53761 because 16*10+8=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)

(Try these out. Enter them directly without line numbers.)


More Experi ments / 81

SOUND REGISTERS
So far I've shown you only two sound contro l reg isters: 53760 and 53761. Here
is a more complete list:

Location Used to Control


53760 Pitch of voice 0
53761 Distortion and vo lume of voice 0
53762 Pitch of vo ice 1
53763 Distortion and volume of voice 1
53764 Pitch of voice 2
53765 Distortion and vo lume of voice 2
53766 Pitch of voice 3
53767 Distortion and vo lume of vo ice 3
53768 Pitch of all voices
(More on this later)

• 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

Notes on the Sound Demo


Line 60: POKE SO,PO This is where I specify what pitch to make the sound.
SO is the pitch control regi ster for voice O. (J initialized SO to 53760 in the
subroutine at line 1000.) PO will be some value between 1 and 255. That's
because you are asked to enter such a number at line 20.

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.

50 FOR PO=1 TO 255 STEP ST This is the beginning of a FOR/NEXT loop.


Note the part that says "STEP ST." This command tells the computer how much
to increment PO at each pass through the loop. ST is set at line 30 in response to
the prompt "ENTER GLIDING SPEED. " If ST is set to, say, 5 then PO will be set to
1 the first time through the loop, but 6 the second time (since 1+5=6) .

• 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:

75 FOR PAUSE=1 to 100:NEXT PAUSE


Another idea would be to print the value of PO on the screen so you
could obseNe the values being poked into SO.

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:

30 Z=Z+1 :S0UND 0,Z,10,8:


IF Z< 4 THEN PLAYERO$(YO)=LEGS1$ :RETURN

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

• What would SO stand for? DVO?

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

30 Z=Z+1 :POKE SO,Z:POKE OVO, 168:


IF Z <4 THEN PLAYERO$(YO) =LEGS1$:
RETURN

(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:

POKE Sa,Z*TONE:POKE DVa

With this code, different sounds wi ll be produced depending on the value of


TONE. For example if TONE=20 then the first time through the loop Z*TONE
will equal 20; the second, 40; the third 60; and so on. The bigger the value in
TONE the bigger the Jump in pitch that will occur on each pass through the
MOVELEGS routine.
At the end of this chapter is'a program that will let you experiment with
different "traveling sounds" for your player. It is similar to the LEGS program
from the previous chapter. I have circled lines that need to be added or
changed.
As you will probably notice, the addition of sound to the program slows
down the player somewhat. That's one of the trade-offs. The more features you
86 / Adding Sound

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

1015 ? CHR$(125):POKE 752,0:7 "Press t


he fire button to change sound."
()'?( RETURN
1999 REM SETUP ROUTINES FOLLON:
2000 GOSUB 10000:REM MISC. INITIRLIZR-
TION
2005 GRAPHICS 5:REM SET GR. MODE
BEFORE PMG SETUP!
2010 GOSUB 11000:REM PMG SETUP
2015 GOSUB 12000:REM DRRN PLRYFIELD
2020 GOSUB 13000 : REM PLRYER COLOR RND
SCREEN POSI nON
2025 GOSUB 14000:REM DISPLRY MESSRGE
2130 RETURN
2999 REM ERROR CORRECTION ROUTINE _
3000 PLAYERO$=BUFFER$:YO=128:XO=80:Z=0
:TRAF' 3000:GOTO 200
10000 REM MISC. INITIRLIZRTION
10050 • YSTICK=632:HPOSPO=53248:PRIOR=
623:MOVELEGS=30:SP=I:PR=8:BUTTONO=644:
ETSOUND=:L000:SO=53760 ~
10060 BUTTONO=644:SETSDUND=1000:S0=537
60:DVO=53761:RETURN
10999 REM PMG SETUP ROUTINE
11000 DIM FILLER1$(1),FILLER2$«INT(AD
R(FILLER1$)/1024)+1)*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$
88 / Adding Sound

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.

11090 POKE 53277,3:REM TURN ON PMG


11110 POKE PRIOR,PR
11299 RETURN
11300 DATA O,0,O,28~28,8,28,58,89,24,6
0,36,36,102,0,0,0
11310 DATA 0,0,0,28,28,8,28,58,89,24,4
0,76,68,68,0,0,0
11320 DATA 0,0,0,28,28,8,28,58,89,24,5
6,72, 132, L~O, 0, 0, 0
11999 REM DR~W PL~YFIELD
12000 SETCOLOR 4,16,2:COLDR 1
12010 PLOT 0,20:DRAWTD 40,20
12020 COLOR 3:DRAWTO 60,35:COLOR 2:DRA
WTD 79,35
12030 RETURN
12999 REM SET PL~YER COLOR ~ND
POSITION
13000 XO=52
13010 YO=12
13020 POKE 704,88
13030 POKE 53248~XO:REM POKE
HORIZONTRL VRLUE INTO HORIZONTON~L
POSITION REGISTER.
13040 PLAVERO$(YO)=LEGS1$:REM PUT
IM~GE INTO PROPER BYTE OF PLRY£RO.
13050 RETUR
14000 ? "To cI'"eate sound, push fire bu
tton . ";:RETURN
Missiles

As I mentioned earl ier, Atari Player-Missile Graphics was originally designed to


simplify the creation of arcade-style games . These games often include little
creatures who fire missiles (or bullets) at each other. In this chapter you'll learn
to create and animate these missiles. Keep in mind that missiles can also seNe
other purposes they can highlight text in graphics mode 0, for example.

DEFINING THE MISSILE IMAGE


There are four missiles available in PMG. All four missiles are stored in a sing le
byte in "missile memory."

• 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

Let's look at a map of a single byte of the missile memory area:

(1.28) (64) (32) (1.6) (8) (4) (2) (1.)

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:

(1.28) (64) (32) (1.6) (8) (4) (2) (1.)

! !

10
l
0 0 01J.1J. 0/01 I :
---...--
MISS ILE 1

• What would be the decimal number needed to turn on missile I? (Re-


member how we calculated those decimal numbers for players? We do
the same thing with missiles. The bit on the far right is worth I; the next bit
to the left is worth 2; the next bit to the left, 4; and so on. Each successive
bit to the left is worth twice as much as the previous bit.)

ANSWER

We need a decimal 12 to create the necessary binary data in missile mem-


ory since a binary 00001100 =a decimal 12.

• If we wanted a thinner miss ile I, what binary data might we use?

ANSWER

We could use either 00000100 or 00001000.


Defining the Missile Image / 91

So if we wanted a thin miss ile J, we might use a decimal 4 or 8 to put the


proper binary data into missile memory.

• 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

The binary number would be 00000011 ; the decimal number. 3.

• 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

You'd need a binary 00001111 or a decimal 15.

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

Here's one way:


11070 DIM MIMAGEO$(1):MIMAGEO$= CHR $(3)

(I suggest you enter SQUNDRUN.SAV-the program From the previous


chapter-and add the new statements as you read along.)

HORIZONTAL POSITION REGISTER


Let's initialize another va riable for the horizontal position register for missile O.
We'll ca ll it HPOSMO. So at line 10060, we add this statement:

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.

REVISING THE MAIN LOOP


Since we will be using the joystick button to fire missiles, we need to delete line
200 from the SOUNDRUN program. After deleting line 200, renumber line 204
so that it now becomes 200. Line 200 w ill now read:

200 GOSUB PEEK (JOYSTICK) :GOSUB MOVELEGS:


GOTO 200

Also, let's delete these pokes from line 30

POKE SO,X*TONE
POKE DVO,DO

since we won't be including player trave ling sounds this time.


Building A Missile Move Routine / 93

• In a moment we are going to add a routine to move our missile. We want


line 200 to fall through to this new routine. So what change do we need
to make to our new line 200 shown above?

ANSWER

We need to delete GOTO 200; otherwise control will not fall through to
our new routine.

BUILDING A MISSILE MOVE ROUTINE


As you know, we have set up our player move routine so that our player can
move in anyone of the eight joystick directions (up, down, left, right plus the
four diagonal directions) . Wouldn't it be nice if our player could also fire a
missile in anyone of those directions?
To make this work, let's make a rule that a player must be moving w hen
she fires a missile. Furthermore, the miss ile wi ll go in the same direction as the
player. Now, how do we write the code to accomplish this?
First we need to identify when the fire button is pressed whi le the stick is
also being deflected from its upright position. If that happens, we will set a
variable ca lled MOVEO to the stick va lue. For example, if the stick is moved to
the left wh ile the fire button is pressed, we wi ll set MOVEO to 11. (The stick
va lue for left is 11.) Also we will increment an " indicator"-a variable that we
will ca ll FIREO. This variable will help the routine remember that the Joystick
was pressed. Also, it wi ll serve as a counter. It wi ll count the number of passes
that have been made through the missile move routine. We need this because
we need to do different things on the first pass through the loop than on
successive passes.

• Got all that? See if you can write the code for it.

ANSWER

Here's how I did it:

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:

305 IF FIREO=O THEN GOTO 200

Positioning the Missile


The first time through the missile move routine, we need to plop the missile
down on the screen "underneath" our player so that when the missile is
moved on subsequent passes through the loop, the miss ile will appear to be
coming from him.

• How does the routine detect the first pass?

ANSWER

With a statement such as IF FJREO=l THEN ..

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

Here's one way:

315 IF FIREO=1 THEN


MXO=XO+3 :
MYO=YO+7 :
DIRO=MOVEO:
FIREO=FIREO+1

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.

Putting the Missile on the Screen


• Now we're ready to put the missile on the screen! We simply erase the
data in MISSILESS, POKE HPOSMO w ith MXO, and set MISSILESS(MYOj
equal to our missile image string. Can you w rite the code?

ANSWER

335 MISSILESS=BUFFERS
POKE HPOSMO,MXO:
MISSILESS(MYOj =MIMAGEOS

Also, we'll need to make these changes:


Add this to line 10060:

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

Add line 11070:

11070 DIM MIMAGEO$(1 ):MIMAGEO$=CHR$(3)

Change lines 13000 and 13010 to

13000 XO=120
13010 YO+43

Change line 2 to:

SAVE "D:MISSILE.SAV":STOP

Change line 14000 to:

14000 ? "To fire missile , move joystick and push fire


button." :RETURN

Change line 15 so it reads

15 POP:PLAYERO$(YO) =LEGS1 $:
GOTO 300

Delete lines 1000 through 1020.


Now (finally ) we're about ready to take a pre liminary test run of our
missile routine. (Ass uming you've typed in all of the preceding lines along the
way. ) But first. in line 315 change MXO=XO+3 to

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,

1 GOSUB 2000:GOTO 200


2 SAVE "D:MISSILE.SAV":STOP :REM DISK
3)
4 REM ~DJUST HORI ZO NT~L & V£RTIC~L
COORDIN~T£S
5 XO=XO+SP:YO=YO+SP:RETURN
Building A Missile Move Routine / 97

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

;60~ ~ nGoTo a..OO"


270 REM
280 REM
290 REM
300 REI"!
301 IF PEEK(BUTTON01=0 AND PEEK(JOYSTI
CK1<>15 THEN MOVEO=PEEK(JOYSTICK):FIRE
O=I=- I REO+ 1
305 IF FIREO=O THEN GOTO 200
315 IF FIRE O=1 THEN MXO=XO-10:MYO=YO+7
:DIRO=MOVEO:FIREO=FIREO+l
335 MISSILES$=BUFFER$:POKE HPOSMO~MXO:
MISSILES$(MY01=MIMAGEO$
34() cTOF'
600 GRAPHICS O:TRAP 610:FOR 1=1 TO 128
:-::' 1;" ";ASC(PLAYERO$(I»:NEXT I:STOP

61 0 EN~ I 000 t:Iv-to~ IOJ,{)


d.d.eiL
1999 REM SETUP ROUTINES FOLLO~:
2000 GOSUB lOOOO:REM MISC. INITIRLI-
UH ION
2005 GRAPHICS 5:REM SET GR . MODE
BEFORE PMG SETUP'
2010 GOSUB 11000:REM PMD SETUP
98 / Missiles

2015 GOSUB 12000:REM DR~W PL~YFIELD


2020 GOSUB 13000:REM PL~YER COLOR RND
SCREEN POSITION
2025 GOSUB 14000:REM DISPLRY MESSRGE
2130 RETURN
2999 REM ERROR CORRECTION ROUTINE
3000 PLAYERO$=BUFFER$:YO=128:XO=80:Z=0
:TRAP 3000:GOTO 200
10000 REM MISC. INITIRLIZRTION
10050 JOYSTICK=632:HPOSPO=53248:PRIOR=
623:MOVELEGS=30:SP=1:PR=8:BUTTONO=644:
SETSDUND=1000:S0=53760
10060 BUTTONO=644:SETSOUND=1000:S0=537
60:DVO=53761:HPOSMO=53252~HPOSMO=53252)
: RETURN
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$=BUFFERS: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)
=CHRS(A) :NEXT I
11067 FOR 1:= 1 TO 17:READ A:LEGS3$(I,I)
=CHRS(A):NEXT I
11070 DIM MIMAGEOS(I):MIMAGEOS=CHRS(3)

11080 POKE 54279,ADR(BUFFERS)/256:REM


DTELL ANTIC WHERE START OF PM MEMORY I
S
11085 POKE 559,46:REM DOUBLE LINE RES.
Building A Missile Move Routine / 99

11090 POKE 53277,3:REM TURN ON PMG


11110 POKE PRIOR~PR
11299 RETURN
11300 DATA 0,0,0,28,28,8,28,58,89,24,6
0,36,36~102,0,0,0
11310 DATA 0,0,0,28,28,8,28~58,89,24,4
0,76,68,68,0,0,0
11320 DATA 0,0,O,28~28~8,28,58,89,24,5
6, 72, 132, 130, 0, 0, 0
11999 REM DR~W PL~YFIELD
12000 SETCOLOR 4,16,2:COLOR 1
12010 PLOT 0,20:DRAWTO 40,20
12020 COLOR 3:DRAWTO 60,35:COLOR 2:DRA
WTO 79,35
12030 RETURN
12999 REM SET PL~YER COLOR ~ND

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.

Moving the Missile


Now let's get on with animating that missile. For now, delete the TRAP state-
ment from line 1. Now, remember lines 5 through 157 Let's review. We used
them to adjust the coordinates for the player's position. If the stick reading is 7
100 / Missiles

(right), then we GOSUB 7. Line 7 is a "minisubroutine" that increments XO and


immediately returns. We can use that same approach to move our missiles. To
do that; we will write a similar routine that starts at an offset of 60 from the first
one. That is, instead of beginning at line 5, our new missile subro utine will start
at line 65 (5+60). Instead of adjusting XO and YO, we will adjust MXO and MYO,
the missile coordinates. Here is the complete missile coordinate adjustment
routine:

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:

320 IF FIREO> 1 THEN GOSUB DIRO+60


449 GOTO 200

• 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

Control wi ll pass to line 74 (14+60).

• What happens at line 74?

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

Let's try it. In summary:

1. Add lines 65 through 75 above.


2. Add line 320.
3. In line 10060 initialize MSO to 6 (MSO=6).
4. Delete line 340.
5. Add line 499.
6. Delete the TRAP statement from line 1.

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:

1 TRAP 3000:GOSUB 2000:GOTO 200

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

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
102 / Missiles

In addition, we need to reset the leg movement counter Z. We can do


that with the statement Z=O. Let's add it at line 3035:

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

Finally. we need to include another TRAP statement so that if another


error occurs control will once aga in return to line 3000. Then we can jump back
to line 300 in the main routine :

3080 TRAP3000:GOTO 200

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:

300 POKE S01 ,P1:


POKE OV1,01

At line 10070 initialize PI , 01 , SOl, and OVI as follows:

P1 =10 (Pitch for sound)


01 =0 (Oistortion/Volume)
SD1 =53762 (Pitch Register)
DV1 =53763 (Distortion/Volume Register)
Missile Size Register / 103

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.

• Where would be a good place to insert that statement?

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.

Now we still need to decrement 01 . Let's do that at line 330. We can


decrement 01 easily enough with 01 =01 - 1. But that's not enough, because that
way 01 will eventually become a minus value and we will get an errror
message.

• How can we avoid that? Write the code.

ANSWER

Here's how I did it:


330 01=01-1:IF 01 < 1 THEN 01=0

Add line 330. Save the program and run it. You will now hear an explosive
sound whenever you fire a missile.

MISSILE SIZE REGISTER

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)

• How wou ld you set missiles 0 and I to double size?

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

Here's one easy way:


POKE SIZEM,PEEK(RANDOM)

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!

1 TRAP 3000:GOSUB 2000:GOTO 200


2 SAVE "D : MISSILE.SAV":STOP :REM DISf(
30
4 REM RDJUST HORIZONTRL & UERTICRL
COI}RDINRT£S
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)=LEGS1S:GOTO 300
29 REM MOUE PLRYER"S LEGS
30 Z=Z+1:POKE HPOSPO,XO:IF Z<4 THEN PL
AYERO$(YO)=LEGS1$:RETURN
106 / Missiles

31 IF Z< 7 THEN PLAYERO$(YO)=LEGS2$:RET


URN
32 PLAYERO$(YO)=LEGS3$:IF Z=9 THEN z=o
: RETURN
33 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
199 'M M~IN LOOP
200 GOSUB PEEK(JOYSTICK):GOSUB MOVELEG
S
260 REM
270 REM
280 REM
290 REM
300 POKE SD1,Pl:POKE DV1,Dl:POKE SIZEM
,PEEK(RANDOM)
~01 K(BUTTONO)=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:D = 5
320 IF FIREO>1 THEN GOSUB DIRO+60
330 D1=01-I:IF 01 <1 THEN 01~0 ,
335 MISSILES$=BUFFER$:POKE HPOSMO,MXO:
~~""""'''''''''~I..!.M!;.!Y..:.:(I ) =MI MAGE (I $
A ,J /J_...J-:. -::l u..
GOTO 200 ~ .:J,O
rcs O:TRAP 610:FOR 1=1 TO 128
:? I;" ";ASC(PLAYERO$(I»:NEXT I:STOP
610 END
1999 REM SETUP ROUTINES FOLLOH:
2000 GOSUB 10000:REM MISC. INITI~LI-
l~TION
2005 GRAPHICS 5:REM SET GR. MODE
BEFORE PMS SETUP'
2010 GOSUB 11000:REM PHG SETUP
2015 GOSUe 12000:REM DR~H PL~YFIELD
Complete Usting / 107

2020 GOSUB 13000:REM PLRYER COLOR RND


SCREEN POSITION
2025 GOSUB 14000:REM DISPLRY MESSRGE
2130 RETURN
2999 REM ERROR CO . C n
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
3035 Z=O
3040 MXO=XO:MYO=YO
3050 Dl=O
3060 FIREO=O

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

11067 FOR 1=1 TO 17:READ A:LEGS3$(I~I)


=CHR$(A):NEXT I
11070 DIM MIMAGEO$(1):MIMAGEO$=CHR$(3)

11080 POKE 54279~ADR(BUFFER$)/256:REM


DTELL ANTIC WHERE START OF PM MEMORY I
S
11085 POKE 559,46:REM DOUBLE LINE RES.

11090 POKE 53277~3:REM TURN ON PMG


11110 POKE PRIOR,PR
11299 RETURN
11300 DATA 0,0,0,28~28,8,28,58~89,24,6
0,36,36~102,0,0,0
11310 DATA 0,0,0,28,28,8,28,58,89,24,4
0,76,68,68,0,0,0
11320 DATA 0,0,0,28,28,8,28,58,89,24,5
6,72,132,130,O~0,0
11999 REM DR~W PL~YFIELD
12000 SETCOLOR 4~16~2:COLOR 1
12010 PLOT 0,20:DRAWTO 40~20
12020 COLO~ 3:DRAWTO 60,35:COLOR 2:DRA
WTO 79, ::~5
12030 RETURN
12999 REM SET PL~YER COLOR ~ND
POSITI/JN
13000 XO=120
13010 YO=43
13020 POKE 704,88
13030 POKE 53248,XO:REM POKE HORI-
ZONT~L U~LUE INTO HORIZONTONRL
POSITION REGISTER.
13040 PLAYERO$(YO)=LEGS1$:REM PUT
IM~GE INTO PROPER BYTE OF PL~YERO. YO
DETERMINES UERTIC~L POSITION
13050 RETURN
14000? "To fire missile .• move Joystic
k and push fire button.":RETURN
Single-line Resolution

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.

LINES 11020 THROUGH 11040


Here I am setting ERASES to binary zeros. Notice the RETURN at the end of line
1040. I broke the PMG setup routine into two parts. (For some unknown reason
BASIC likes it better this way.)
Lines 11045 through 11095 make up the next part of the PMG setup. I
made these lines into another subroutine, which is called immediately after the
subroutine starting at line 11000. (See the "executive" subroutine beginning at
line 2000, which ca lls the various setup routines.)

LINES 11045 AND 11047


Here I am initializing MISSILESS and PLAYEROS in a slightly different way. This is
necessary because of an apparent bug in Atari BASIC. It seems that a statement
such as MISSILESS=ERASES won't work if MISSILESS is 256 bytes or more.
In the previous program, line 335 contained the statement MISSILESS
=BUFFERS, which served to "erase" data from the missile memory area. (Actual-
ly it fills MISSILESS with zeros.) I had to take this statement out when converting
the program to sing le-line resolution. That's because of the apparent bug in
Atari BASIC that I just mentioned.
So to accomplish vertical missile movement, I had to find another way to
erase the missile. I did that by rewriting lines 11070 and 11330.

LINES 11070 AND 11330


At line 11 070 I dimensioned the missile image string to 13, instead of 1. Why?
Because I wanted to have the missile erase itself with trailing zeros during
vertica l movement.
Une 315 / 111

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

LINES 3000 THROUGH 3080


The error correction ro utine at lines 3000 through 3080 needed quite an over-
haul because of the differences in vertica l coord inates in singl e-line reso lution.
Also the manner in w hich I erase a miss ile is different. I now need to reference
spec ific bytes in MISSILESS w hen erasing the missile. I ca n no lo nger merely
code M ISSILESS=BUFFERSto set the missile memory area to zeros. Again, this is
necessary because of an appa rent bug in Atari BASIC.
That does it. The complete listing for firing mi ss iles in single- line reso lu-
tion fo llows. To make the required changes easy to see, I have circled them.
Notice that in line 2, I made a com ment to myself that I saved the program on
disk 30. I suggest you revise th is REM statement so it reminds you w here you
saved the program. In the next chapter, we' ll put our player in a maze and add
co llision detection I

1 TRAP 3000:GOSUB 2000:GOTO 200


2 SAVE "0: SLRES. SAV": STOP : REM DISr;' 30

4 REM ADJUST HORIlONTAL & VERTICAL


COORDINATES
5 XO=XO+SP:YO=YO+SY:RETURN
6 YO=YO-SY:XO=XO+SP:RETURN
7 XO=XO+SP:RETURN
9 XO=XO-SP:YO=YO+SY:RETURN
10 XO=XO-SP:YO=YO-SY:RETURN
11 XO=XO-SP:RETURN
13 YO=YO+SY:RETURN
14 YO=YO-SY:RETURN
15 POP :PLAYERO$(YO)=LEGS1$:GOTO 300
29 REM MOVE PLAYER'S LEGS
30 Z=Z+l: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
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
Unes 3000 through 3080 / 113

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

C3030 I F YO >245 THEN YO=245)


~035 Z-O
3040 IF M O{l OR MYO>240 THEN MYO-l
3042 IF MXO{40 OR MXO}210 THEN MXO=40
3045 MISSILES$(MYOS)=ERASES
3050 D1-0: 'EM TURN OFF MISSILE SOUND
3060 FIREO=O:REM TURN OFF FIRE FLRG
3080 TRAP 3000:GOTO 300
10000 REM MISC. INITIRLIZRTION
10050 JOYSTICK=632:HPOSPO=53248:PRIOR=
623:MOVELEGS=30:SP=1:PR=8:BUTTONO=644:
SETSOUND=1000:S0=53760
10060 BUTTONO=644:SETSOUND=1000:S0=537
60: DVO=53761:HPOSMO=53252:HPOSMO=53252
:MSO=6
10070 Pl=10:D1=0:SD1=53762:DV1=53763:S
I ZEM=53260: RANDOM=53770 :~
10900 RETURN
10999 REM PMG SETUP ,OUTINE
11000 DIM FILLER1$(1)~FILLER2$«INT(AD
R(FILLER1S)/2048)+I)*2048-ADR(FILLER1$
) -1)
11010 DIM ERASE$(256),FILLER3$(256),FI
LLER4$(256)~MISSILES$(256),PLAYERO$(25
6)
11020 ERASE$=CHR$(O)
11030 ERASE$ (256) =CHR$ (,.(-.:,)_ _"",
11040 ERASE$(2)=ERASE$ ETURN
11045 MISSILES$=CHR$(O):M LES$(256)
=CHR$(O):MISSILES$(2)=MISSILES$

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

11070 M MIMAGEO$(13):FOR I~l TO 13:R


EAD A:MIMAGEO$(I.I)~CHR$(A):NEXT I
11080 POKE 54279~ADR(ERASE$)/256:REM D
TELL ANTIC WHERE START OF PM MEMORY IS

11085 POKE 559~46+16:REM SINGLE LINE

TURN ON PMG

11300 DATA 0~0,0,28,28,8,28,58,89,24~6


0~36~36~102,0~0,0
11310 DATA 0,O~0,28,28,8,28,58~89~24,4
0,76,68,68,0,0,0
11320 DATA O,0~0,28,28,8,28,58,89,24~5
6,72,132,130,0,0,0
11330 DATA O~O 0.0.0.0 3,0,0,0~0,0,0
11999 REM DR~~ PL~YFIELD
12000 SETCOLOR 4~16,2:COLOR 1
12010 PLOT 0,20:DRAWTO 40,20
12020 COLOR 3:DRAWTO 60,35:COLOR 2:DRA
WTO 79,35
12030 RETURN
12999 REM SET PL~YER COLOR ~ND
POSI TItJN
13000 XO==120
13010 YO=43
13020 POKE 704,88
13030 POKE 53248,XO:REM POKE HORI-
ZONT~L V~LUE INTO HORIZONTON~L POSITIO
N REGISTER.
13040 PLAYERO$(YO)=LEGS1$:REM PUT
IM~GE INTO PROPER BYTE OF PL~YERO. YO
DETERMINES VERTIC~L POSITION
13050 RETURN
14000 ? "To f i J"e 11) iss i 1 e. 11)0 ~f~ )0'1 s tic
,1.;' and push fire button.":RETURN
-
Detecting Collisions

Suppose a player fires a missile at an alien attacking space craft. Wouldn't it be


nice to have a simp le way to tell when there is a collision between the missile
and alien ship? Or suppose you're making a maze game. Would you like to be
able to detect when a player touches a maze wall?

COLLISION DETECTION REGISTERS


You can. Collision detection is easy w ith PMG! The Atari engineers wisely
provided several collision detection reg isters for this purpose. Here they are:

Missile Collisions

Memory Location Shows:


53248 Missile 0 to playfield collision
53249 Missile I to playfield collision
53250 Miss ile 2 to playfield collision
53251 Missile 3 to playfield collision

117
118 / Detecting Collisions

53256 Missile 0 to player collision


53257 Missile 1 to player collision
53258 Missile 2 to player collision
53259 Miss ile 3 to player collision

Player Collisions

Memory Location Shows:


53260 Player 0 to player collisions
53261 Player 1 to player collisions
53262 Player 2 to player collisions
53263 Player 3 to player collisions
53252 Player 0 to playfield
53253 Player 1 to playfield
53254 Player 2 to playfield
53255 Player 3 to playfield

ASSIGNING VARIABLE NAMES


To simplify your programming task, I recommend that you assign a variable
name to each collision regi ster you need to use. It's a lot easier to keep track of
variable names than all those memory locations. *
Atari recommends variable names such as these:

MOPF (missile 0 to playfield collision)


M1 PF (missile 1 to playfield collision)

In the demonstration program in this chapter we will be using two


collision registers MOPF and POPF.

• What regi ster do you think POPF refers to?

*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

Player 0 to playfield collision 153252)

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

READING COLLISION REGISTERS


You can read a collision register with a peek command. For example:

COLLISION=PEEK(POPF)

After this statement executes, COLLISION will contain either 0,1,2, or 4.


In our sample program you w ill find that:

• If POPF contains a zero, then there was no collision.


• If POPF contains a I, then PLAYER a collided with that part of the
playfield drawn with COLOR I.
• If POPF contains a 2, then PLAYER I collided with that part of the
playfield drawn with COLOR 2.
• If POPF contains a 4, then PLAYER I collided with that part of the
playfield drawn with COLOR 3.

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

Furthermore, suppose you read a collision register like this:

COLLISION=PEEK(POPF)

• What value will be in COLLISION if player a is touching the line you drew?
120 / Detecting Collisions

ANSWER

4 (a 4 shows a collision with a playField drawn with COLOR 3).

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).

CLEARING COLLISION REGISTERS

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

Often we think of clearing something by poking zeros in it. But this is


different; here we are turning on the hit clear switch. That's w hy we poke it
with 1 rather than O.

• When we poke a 1 into HITCLR what do yo u think happens?

a. All collision registers are cleared.


b. Only selected registers are cleared.
Drawing A Playfield / 121

ANSWER

You're right if you said "a. A ll col lision registers are cleared."

USING COLLISION REGISTERS


Often programmers peek at the collision registers and then use a series of
IF-statements to decide on w hat action to take. But there's a much better way.
Remember, in Atari BASIC yo u can GOSUB a va riable or even GOSUB a
PEEKED va lue! We did this in our joystick routine, and we can also do it with
collision registers.

• Suppose we want to execute a subroutine that starts at line 41 if player 0


collides with a COLOR 1 playfield. * Write a statement to make that
happen. fGOSUB the va lue in POPF plus an offset.)

ANSWER

GOSUB PEEKIPOPFj+40

• Now suppose player 0 hits a COLOR 3 playfield. At what line number


must we have a subroutine to handle this poss ibility?

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

We've already reseNed lines 12000-13000 for drawing a playfield, so let's


put our new playfield subroutine there. (Note that we need to delete the
previous playfield, w hich was co ntained in lines 12000, 12010, 12020, and
12030.)
Here are the lines for the new playfield subroutine. I suggest you enter
them now.

11999 REM DRn~ PLRYFIELD


12000 SETCOLOR 2~3~4:COLOR 1
12010 PLOT O,O:DRAWTO 159~0:DRAWTO 159
~79:DRAWTO 0,79:DRAWTO 0~0
12015 COLOR 2
12020 PLOT 80,61:DRAWTO 80,79:PLOT 0,6
O:DRAWTO 30,60:DRAWTO 30,79
12025 COLOR 3
12030 PLOT 52,60:DRAWTO 5 2, 45:DRAWTO 1
10~45:DRAWTO 110~60:DRAWTO 137,60:DRAW
TO 137~45:DRAWTO 110,45 : PLOT 159,32
12040 DRAWTO 110,32:PLOT 80,45:DRAWTO
80,20:PLOT 130, 16:DRAWTO 13 0, 14:DRAWTO
127, 14:DRAWTO 127, 16:DRAWTO 130,16
12050 PLOT 43 , 0:DRAWTO 43,30:PLOT 52,4
5:DRAWTO 22,45:DRAWTO 22,13:PLOT 103,0
:DRAWTO 103,17:POKE 559,34:RETURN

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.

REVISING THE MAIN LOOP


Now let's revise the main loop of our program so that it detects when our
player touches the sides of the wa lls. First. change line 200 into line 201. Do this
so that we can create some new co llision detection routines at line 200.
Now at the beginning o f line 200, let's simply print the contents of the
co llision register-just so we ca n see w hat they co ntain when various Objects
co llide. This is easy to do, like so

? "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:

• Now you w rite the ca ll to the POPF subroutine

ANSWER

GOSUB PEEKIPOPF) +50

Altogether then, line 200 w ill look like this

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 :

201 YOA=YO :XOA=XO:


GOSUB PEEK(JOYSTICK) :
GOSUB MOVELEGS

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.

• See if you can write the code for line 41 :

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).

• So what line will be executed if our player hits a COLOR 3 playfield?

ANSWER

44 (Since 40+4=44.)

• So what code do we need at line 44?

ANSWER

44 XO=XOA:YO=YOAPOKE HITCLR,1 :RETURN

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

Control wi ll pass to line 40 (0+40=40) .


Missile Collisions / 125

• 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.

• What wi ll the code be for line 507

ANSWER

50 RETURN

If a missile hits a wall. we will want to do these things:

• 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

190 POKE HPOSMO.O


DI =O:
126 / Detecting Collisions

FIREO=O
POKE HITCLR, I .
RETURN

• Now if a miss ile hits playfield 1. to which line w ill control pass?

ANSWER

51 (MOPF w ill contain L 1+50=51)

• What additional line numbers w ill we need for playfields 2 and 3?

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

Similarly, at lines 53 and 54 we' ll use the sa me code

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

All the changes are summarized in the listing that follows:


1 TRAP 3000:GOSUB 2000· TO 200
2 SAVE "D:MISSCOL.SAV":STOP :REM DISK
~ )
4 REM ADJUST HORIZONTAL & VERTICAL
CO{)RDINATES
Try It / 127

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

42 XO=XOA:YO=YOA:POKE HITCLR~ 1:RETURN

44 XO=XOA:YO=YOA:POKE HITCLR~1:RETURN

49 REM MISSILE 0 TO PLRYFIELD


50 RETURN
51 GOSUB 190:RETURN
52 GOSUS 190:RETURN
53 GOSUB 190:RETURN
54 GOSUS 190:RETURN
60 REM END OF COLLISIONS
65 MXO-MXO+MSO:MYO- O+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
MYO=MYO-MSO:RETURN
190 'm:::E HPOSMO, 0: D1 =0: F I REO=O: POKE HI
TCLR.1:RETURN
199 REM MRIN LOOP
128 / Detecting Collisions

200 ? "POPF="; PEEI< (POPF) , "MOPF=" ; PEEK (


MOPF):GOSUB PEEK(POPF)+40:GOSUB PEEK(M
OPF)+50
201 YOA=YO:XOA=XO:GOSUB PEEK(JOYSTICK)
:GOSUB MOVELEGS

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)

11080 POKE 54279~ADR(BUFFER$)/256:REM


DTELL ANTIC WHERE START OF PM MEMORY I
S
11085 POKE 559,46:REM DOUBLE LINE RES.
130 / Detecting Collisions

11090 POKE 53277~3:REM TURN ON PMG


11110 POKE PRIOR~PR
11299 RETURN
11300 DATA 0,0,0,28,28,8,28,58,89,24,6
0,36,36,102,0,0,0
11310 DATA 0,0,0,28,28,8,28,58,89,24,4
0,76,68,68,0,0,0
11320 DATA 0,0,0,28,28,8,28,58,89,24,5
6,72,132,130,0,0,0
11999 REM DR~W PL~YFIELD
12000 SETCOLOR 2,3,4:COLOR 1
12010 PLOT O,O:DRAWTO 159,0:DRAWTO 159
,79:DRAWTO 0,79:0RAWTO 0,0
12015 COLOR 2
12020 PLOT 80,61:0RAWTO 80,79:PLOT 0,6
O:DRAWTO 30,60:DRAWTO 30,79
12025 COLOR 3
12030 PLOT 52,60:DRAWTO 52,45:DRAWTO 1
10,45:DRAWTO 110,60:DRAWTO 137,60:DRAW
TO 137,45:DRAWTO 110,45:PLOT 159,32
12040 DRAWTO 110,32:PLOT 80,45:DRAWTO
80,20:PLOT 130,16:DRAWTO 130,14:DRAWTO
127, 14:DRAWTO 127, 16:DRAWTO 130,16

12050 PLOT 43,O:ORAWTO 43,30:PLOT 52,4


5:DRAWTO 22,45:DRAWTO 22, 13:PLOT 103,0
:DRAWTO 103 17:POKE 559 34:RETURN
12999 REM SET PL~YER COLOR ~ND
liC'ITION
XO=175
YO=80
13020 POKE 704,88
13030 POKE 53248,XO:REM POKE HORI-
ZONT~L V~LUE INTO HORIZONTON~L
POSITION REGISTER.
13040 PLAYERO$(YO)=LEGS1$:REM PUT
IM~GE INTO PROPER BYTE OF PL~YERO. YO
DETERMINES VERTIC~L POSITION
13050 RETURN
14000? "Collision Demo.":FOR PAUSE=1
TO 100:NEXT PAUSE:RETURN
Slow Player Movement / 131

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.

SLOW PLAYER MOVEMENT


Notice that the player moves rather slowly. That's mainly because we are
co nstantly peeking at and printing the va lues contained in the co llision regis-
ters. You can speed up the player's movement co nsiderably by deleting
?POPF=";PEEKfPOPF) and ?MOPF="; PEEK(MOPF) in line 200.
Of co urse part of the reduction in the player's speed results because the
main loop is becoming more comp licated. Remember, we are doing quite a bit
in this little BASIC program. We have created:

• Vertical , horizontal, and diagonal movement


• Leg animation
• Miss ile firing and movement in eight directions
• Random missile-size se lection
• Exp losive miss ile sound
• Player and miss ile collison detection.

'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. "

ADDING MORE FEATURES


Let's try something a little different. Let's pretend that the COLOR 1 playfield has
an electrical charge that will zap our player if he touches it. To produce the
"zapping effect." let's produce a strange sound and flash several colors through
the player when he touches playfield 1. Furthermore, let's set our player to a
random new color and then put him back to his starting location. The code to
do this is relatively simple and won't slow down the main action. That's
because the code will not be in the main loop but in subroutines that will
execute only when a collision occurs.
Here's the new code to "zap" the player when he touches the COLOR 1
playfield. Change line 41 to:

41 XO=175:YO=80:
GOSUB 400:
POKE 704,PEEK(RANDOM):
PLAYERO$=BUFFER$:
POKE HPOSPO,XO:
POKE HITCLR,1:
RETURN

And add lines 400 and 410:

400 FOR 1=0 to 100 STEP 2:


POKE 704,1:
SOUND 0,1,10,15:
SOUND 1,1+50,10,15:
NEXT I
410 SOUND: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.

Beware of the crystal. The crysta l is harmless-unless you try to win a


round by touching it. When the crysta l's defense system is activated, it may
send out a storm of laser-type missiles. If you are quick enough though, you
may be able to avoid the lasers. But if you don't you will again be expanded to
double size and zapped back to the starting box. Another penalty is that the
other player wi ll gain one point. The lasers destroy any part of the maze that
they hit but only stun players. As the maze starts to break up more and more,
you wi ll find it easier to sneak up on the crysta l.
It's possible for a player to escape from the maze and sneak up on the
crysta l whi le "off screen." (I won't tell you how.) Be alert when hiding behind
maze walls. Missiles fired by players sometimes penetrate wa lls! To fire a
missile, move the player in the direction you want the missile to go and press
the fire button. The first player to get ten or more points wins. You can start a
new game by pressing your fire button.

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:

10000 Initialize Constants


12000 Draw Playfield
11 000 Set up PMG
13000 Specify player colors and initial position (off screen )
5000 Allow users to select colors

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.

CHECKING FOR COLLISIONS


Lines 200 and 201now check for the various collisions. Notice how easy this is.
We simply call various subroutines. The subroutine called depends on the
contents of the appropriate co llision register. For example, look at the first
statement in line 200:
138 / Programming A Game

GOSUB PEEK(POPF)+100

• If the player 0 to playfield collision register (POPF) contains a zero, meaning


no collision, which subroutine will be executed?

ANSWER

The one at line 100 (0+100=100) .

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 ."

• Suppose player 0 touches the crystal. Which subroutine will be executed?

ANSWER

The one at line 102 (2+100=102) .

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

CRYSTAL DEFENSE SYSTEM


Control now passes to the crystal defense system at line 210. Notice that I am
using the random number generator at location 53770. (RANDOM is initialized
to 53770.) If RANDOM contains a number greater than 220 then we check to
see if either of the players has entered the crystal 's attack zone. We know a
player is in the crystal 's attack zone if its X coordinate is greater than 142 and its
Y coordinate is less than 34. During game development, you can easily discover
the coordinates for a specific location by positioning a player where you want
him, hitting the break key. and then printing the coordinates.
Why the check of the random number? Well, this way the crystal's
defense system isn't perfect. Sometimes a player will be able to sneak past it
and reach the crystal before it starts wildly firing lasers in all directions. By
changing 220 to some other number, you can increase or decrease the proba-
bility that a player w ill be able to sneak in and touch the crystal. The higher the
number (up to 255) the better the player's chances will be. (By the way.
location 53770 generates a random number between 0 and 255.)
If all conditions are satisfied, then the laser firing routine is activated
starting at line 450. This is a fairly simple routine, but the results are quite
dramatic. In this routine I use DRAWTO statements to create the lasers. A nice
effect is produced by drawing the various random vertical coordinates. Again I
used location 53770 to set a variable called VT to various values. VT is then
used in the DRAWTO statement as the vertical coordinate. Notice that I use
COLOR 1when drawing the laser. The collision detection routine is already set
up to detect a collision with anything drawn with COLOR 1. So if the laser hits
the player, zapo-whamo! After drawing a laser, I erase it by redrawing it using
COLOR O.
After the crystal defense check at line 210, control passes on to the missile
move routine at 300.

MISSILE MOVE ROUTINE


This routine is quite similiar to the one in the previous chapter, except that now
we have to deal with two missi les. This can present a problem when two
missiles are both fired at the same time. The binary image data for missile 0 is:

00000011 (or 3 in decimal)

For missile 1, the binary data is :

00001100 (or 12 in decimal)


140 / Programming A Game

Suppose both missiles happen to occupy the same byte in missile memory.
(This will happen whenever MYO=MY1.j

• What if we move 00000011 into byte 22 of MISSILES and then immediately


move 00001100 into that same byte of MISSILES? What will be the effect on
missile O?

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.

Look again at the binary data :

Missile 0: 00000011
Missile 1: 00001100

This can be solved with a machine language subroutine that addresses


specific bits. That is, if we wanted to turn on missile 0, we would turn on only
the two bits on the far right. But we would not move zeros into the other bits.
In BASIC we cannot address specific bits. That is, we cannot move data
only into certain bits, but not others. In BASIC we must deal in bytes.
My solution to the problem was to "turn on" both missiles whenever
both missiles happened to occupy the same byte in missile memory. I did this
by initializing a variable called BMISSS to 15. Then at line 335 I check to see if
MXO=MX1. If MXO=MX1, Ijump to line 400 where I move 15 into MISSILES.

• Why does putting a decimal 15 into MISSILESS turn on both missilesS7

ANSWER

Because in binary, 00001100 + 00000011 =00001111 and 00001111 =a decimal


15.

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

TYPING IN THE PROGRAM


The program listing appears at the end of this chapter. It may look long, but
remember, a lot of it is a duplication of the code from the previous chapter.
As I mentioned earlier, it's probably a good idea to omit all REM state-
ments when typing in the program. It will require less memory this way and
run faster. The program will fit into a 16K cassette system or a disk drive system
with 24K.
Since this program was designed for instructional purposes, more line
numbers are used than actually needed . You can speed up the program
somewhat by combining some lines. For example, line 330 could be combined
with 335. But be careful in doing this. For example, don't try to combine two
IF-statements. If you do, then the second IF-statement won't execute unless the
first condition is true. For best results, I suggest you type in the program exactly
as is. Then after you've saved a working copy, you can do your thingl Have fun .
Here are some revision suggestions :

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:

Player Number Size Register


o 53252
53253
2 53254
3 53255

To set a player's size, poke the appropriate register with 0,1,2, or 3 as


follows:
142 / Programming A Game

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.

1 TRAP 3000:GOSUB 2000:80TO 200


2 SAVE "D:MAZEDUEL.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 RETURN :REM POP :PLAYERO$(YO)=LEGSl
$:POKE DVO~O:GOTO 210
16 X1=X1+SP:Y1=Y1+SP:RETURN
17 Y1=Y1-SP:X1=X1+SP:R ETURN
18 Xl=X1+SP:RETURN
20 X1=X1-SP:Y1=Y1+SP:RETURN
21 X1=X1 - SP:Y1=Yl-SP:RETURN
22 X1=X1-SP:RETURN
24 Yl=Yl+SP:RETURN
Typing in the Program / 143

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

108 REM PLRYERl TO PLR YFIELD


109 RETURN
110 SO =SO+l:GOSUB ZAP2 : PLAYER1$=BUFFER
$:PLAYER1$(Yl) =LEGS1$:GOSUB 5500:RETUR
N
111 Sl=Sl+5:GOTO 660:R EM PLRYERl HITS
CRYSTRLl
112 SO=SO+l:GOSUB ZAP2 : PLAYER1$=BUFFER
$:PLAYER1$(Yl)=PlIMAGE 1$:GOSUB 5500:RE
TURN
113 RETURN
114 RETURN
115 RETURN
116 SO=SO+l:GOSUB ZAP2:PLAYER1$=BUFFER
$:PLAYER1$(Yl)=LEGS1$: GOSUB 5500:RETUR
N'
117 REM MISSILE 0 TO PLRYFIELD
118 RETURN
119 FIREO=O:GOSUB OFF: MXO=O:RETURN
120 FIREO=O:GOSUB OFF: MXO=O:POKE HITCL
R,O:SO=SO+l:GOTO 660:REM MIS S ILE HITS
CRYSTRLl
121 RETURN
122 RETURN :GOSUB ZAP2:RETURN
124 REM MISSILE 1 TO PLRYFIELD
125 RETURN
126 FIRE1=0:GOSUB OFF:MX1=O:RETURN
127 FIREO=O:GOBUB OFF: MX1=O:POKE HITCL
R,0:Sl=Sl+1:GOTO 660:REM MISSILE HITS
CR'ISTRL.'
128 RETURN
129 RETURN :GOSUB ZAP:RETURN
130 REM MISSILE 1 to PLR'IER 0
131 RETURN
1 •'"..>..::.
:"'.... GOSUB ZAP:Sl=Sl+1:FIRE1=O:MX1=O:GO
SUB 5500:RETURN
133 RETURN
134 RETURN
135 GOBUB 85:RETURN
136 REM MISSILE 0 TO PL R'IER 1
137 RETURN
138 RETURN
139 GOSUB 530:S0=SO+1:F I REO=0:MXO=0:GO
SUB 5500:RETURN :REM MO HITS PLRYERI
Typing in the Program / 145

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

204 IF PEEKCJO)<>15 THEN Z=Z+I:GOSUB 3


4+Z:GOTO 206:REM MOVE LEGS
205 PLAYERO$CYO)=LEGS1$
206 IF PEEKCJ1)<>15 THEN W=W+l:GOSUB 5
4+W:GOTO 210:REM MOVE LEGS
207 PLAYER1$CY1)=LEGS1$
210 IF PEEKCRANDOM)}220 THEN IF XO)142
AND YO{34 OR Xl>142 AND Yl{34 THEN GO
SUB 450
299 REM MISSILE MOVE ROUTINE
300 POKE SIZEM,PEEKCRANDOM):POKE SDO~P
O:POKE DVO,DO:POKE SD1,Pl:POKE DV1,DO
301 IF PEEKCBUTTONO)=O AND PEEKCJO){)1
5 THEN MOVEO=PEEKCJO):FIREO=FIREO+l
302 IF PEEKCBUTTON1)=0 AND PEEKCJ1)<>1
5 THEN MOVE1=PEEKCJ1):FIRE1=FIRE1+l
305 IF FIREO=O AND FIRE1=0 THEN 200
307 POKE HPOSMO,MXO:POKE HPOSM1,MXl
315 IF FIREO=1 THEN MXO=XO+3:MYO=YO+7:
DIRO=MOVEO:FIREO=FIREO+l:DO=15:REM SET
INITIRL POSITION OF MI$,SILES
317 IF FIRE1=1 THEN MX1=Xl+3:MY1=Yl+7:
DIR1=MOVE1:FIRE1=FIRE1+1:DO=15
320 IF FIREO>1 THEN GOSUB DIRO+60
321 IF FIRE1>1 THEN GOSUB DIR1+80
330 DO=DO-2:IF DO{l THEN DO=O
146 / Programming A Game

335 IF MYO=MYI THEN 4 0 0


340 MISSILES$=BUFFER$:MISSILES$(MYO'=M
IMAGEO$:MISSILES$(MY1'=MIMAGE1$
399 GoTo 200
400 MISSILES$=BUFFER$:MISSILES$(MYO'=B
MISS$:GoTO 200:REM IMPORTRNT: TURN ON
BOTH MISSILES
450 FOR 1=15 TO 1 STEP -1:VT=PEEK(RAND
oM'/2.7:S0UND 3~I~4~1 5: COLOR l:PLOT 13
2~16:DRAWTO 90~VT
455 PLOT 132~ 16:DRAWTo 159,VT
460 COLOR O:PLOT 132~16:DRAWTo 90~VT:P
LOT 132~16:DRAWTO 159 ~ VT:NEXT I:SOUND
3~0~0~0:GoSUB 700:RET URN
499 GOTo 200
500 GOSUB OFF:MX1=0:P OKE MOPL~I : POKE M
lPL~2:FIREO=0
510 POKE DVO~O:POKE S D 1~0:FOR 1=2 TO 2
55 STEP 2:POKE 704~I: S OUND 0~I~14~14:N
EXT I:POKE 704~KOLORO
520 XO=50:YO=78:POKE 53 248,XO:PLAYERO$
=BUFFER$:PLAYERO$(YO' =LEGS1$:RETURN
530 GOSUB OFF:MXO=O:PoKE M1PL~I:POKE M
OPL,2:FIRE1=0:FIREO=0
540 POKE DVO,O:POKE S D 1~0:FOR 1=2 TO 2
54 STEP 2:POKE 705,I: SDUND 0,1~14~15:N
EXT r:PoKE 705~KOLORI
550 Xl=62:Yl=78:PLAYER1$=BUFFER$:PLAYE
Rl$(Yl'=LEGS1$ : POKE HPOSP1,Xl
560 RETURN
600 TRAP 610:FOR 1=1 TO 128: 7 1;"= ";A
SC(BMISS$(I":NEXT I: SToP :REM 60 HERE
TO LOO~ RT DRTR IN PM MEMORY.
610 END
660 FOR J=1 TO 20:FOR 1=1 TO 5:SETCOLO
R 4~J~J+l:S0UND O~I*1 0 -7,10,I*2:NEXT I
:NEXT J:POKE MOPL,2:P OKE M1PL,2
661 PLAYER1$=BUFFER$:PLAYERO$(YO'=LEGS
1$:Xl=62:Yl=78 : POKE 5 32 49~Xl : ROUND=ROU
ND+l
662 XO=50:YO=78:GoSUB 5500:PLAYERO$=BU
FFER$:PLAYERO$(YO'=LEGS1$:POKE 53248, X
O:SETCOLOR 4,HUE,LUM: RETURN
Typing in the Program / 147

700 REM CRYSTAL


710 COLOR 2:PLOT 131~15:DRAWTO 137,15:
PLOT 134~12:DRAWTO 134~18
720 PLOT 131,12:DRAWTO 137,18:PLOT 131
~18:DRAWTO 137~12:COLOR 1
730 RETURN
900 REM
910 REM
920 REM
1900 PLAYERO$=BUFFER$:YO=128:XO=80:X=0
:GOTO 190
2000 GOSUa 10000:REM INITIALIZE
CONSTANTS
2005 GRAPHICS 7:REM GR. MODE BEFORE PMG

2007 GOSUa 12000:REM DRAH PLAYFIELD


2010 GOSUB 11000:REM PMGSETUP
2030 GOSUa 13000:REM SCREEN POSITION
2040 GOSUE 5000:REM SELECT COLOR
2050 RETURN
2080 IF MY1 { 1 OR MY1 >128 THEN MY1=1:PO
KE 53253,0:FIRE1=0:SP=3:GOTO 2100
2085 IF MX1 {0 OR MX1>150 THEN MX1=10:F
IRE1=0:GOTO 2100
2087 IF MXO{O OR MXO>150 THEN MXO=10:F
IRE1=0:GOTO 2100
2090 IF MYO{1 OR MYO>128 THEN MYO=YO:P
OKE 53252,0:FIREO=0: GOTO 2100
2095 IF MY1{1 OR MY1 >128 THEN MY1=Y1:P
OKE 53252,0:FIREO=0:GOTO 2100
2099 ? "GOrJF NO. "; F'EEI< ( 195) ; "SEE LINE
NUMBER "; PEE~< ( 186) +256*F'EEI< ( 187)
2100 DO=O : TRAP 2080:GOTO 200:REM PEEK(
187)*256+PEEK(186)
3000 IF XO>210 THEN XO=2 10 :REM CORRECT
PLAYER COORDINATES
3010 IF XO <39 THEN XO=39
3020 IF YO{l THEN YO=l
3030 IF YO>128 THEN YO=128
3040 MXO=0:MYO=YO : MX1=O:MY1=Yl
3050 DO=O:Dl=O:REM TURN OFF MISSILE
SOIJND
3060 FIREO=0:FIRE1=0 : REM TURN OFF FIRE
FLAG
148 / Programming A Game

3070 Z=O:REM RESET LE G MOVEMENT


C{fUNTER
3080 TRAP 3000:GOTO 210
4000 RETURN :POKE 20~ 0
4050 ? CHR$ (125) : 7 " "
;11-Y:SOUND O~Y+PEEK( 2 0)+5~14~10:GOTO
4010
5000 7 "PRESS SELECT TO CHANGE SCREEN
COLOR~ OPTION TO CHANGE PLAYER COLOR~
S TliRT TO START GAME "
5005 XO=50:Xl=62:POKE HPOSPO~XO:POKE H
POSP1.~Xl
5015 IF PEEK(53279)=5 THEN GOSUS 5200
5020 IF PEEK(53279)=3 THEN GOSUB 5300
5025 IF PEEK(53279)=6 THEN SETK=SETK:R
ETURN
5030 GOTO 5015
5199 REM CH~NGE SCREE N COLORS
5200 LUM=LUM+l
5210 IF LUM>14 THEN LUM=0:HUE=HUE+1
5220 IF HUE}15 THEN HUE=O:LUM=O
5230 SET COLOR 4~HUE~LUM
5299 REM CH~NGE PLRYER COLOR
5300 KOLORO=KOLORO+2: KOLOR1=KOLOR1+2:I
F KOLORO}254 THEN KOLORO=O
5305 IF KOLOR1}254 THEN KOLOR1=0
5310 POKE 704,KOLORO:POKE 705~KOLOR1:R
ETURN
5500 7 CHR$ (125) :? " ROUND #
";ROUND:7 :7 "PLAYER 1 = ";SO;"
PLAYER 2 ::: ";Sl:S0UND 0~255~1.4~1.5
5510 IF SO>9 THEN 7 :7 "PL.AYER 1. WINS"
:GOTO 5540
5520 IF SI >9 THEN ':":' : 7 "PL.AYER 2 WINS"
:GOTO 5540
5530 RETURN
5540 POP :7 :POKE 82~ O: 7 "PRESS THE FI
RE BUTTON FOR ANOTHER GAME";:SOUND O~O
~O~O:SOUND 1,0~0~0
5550 IF PEEK(BUTTONO) =O THEN 5560
5552 IF PEEK(BUTTON1) =0 THEN 5560
5555 GOTO 5550
5560 POKE 82~2:RUN
10000 KOLORO=1.63:KOLOR1=83
Typing in the Program / 149

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

11070 DIM MIMAGE1S(I):MIMAGE1S=CHRS(12


)
11071 DIM BMISSS(I):BMISSS=CHR$(15):RE
M BOTH MISSILES uON u
11072 POKE 704,KOLORO:REM SET COLOR OF
PLRYERO
11075 POKE 705~KOLOR1:REM COLOR PLRYER
1
11080 POKE 54279,ADR(B UF FERS)/256:REM
SPECIFY STRRT OF PM MEMORY
11085 POKE 559,46:REM DOUBLE LINE RES.

11090 POKE 53277~3:REM TURN ON PMG


11100 POKE 53260~5:REM WIDTH/MISSILES
11110 POKE PRIOR,2 : REM SETS PRIORITY
REGISTER
11120 POKE HITCLR~l:REM CLERR
COLLISION REGISTERS
11290 RETURN
11300 DATA 0~0~0~28,28~8~28~58~89~24~6
0~36,36,102,0,0,0
11310 DATA 0~0~0~28,28,8~28,58,89,24,4
0,76,68,68,O,0~0
11320 DATA O,O~0,28, 2 8, 8~2 8,58,89,24,5
6,72,132,130,0,0~0
11330 DATA O,O,O~ 120,56~16~56,116~176,
48,50,60,64 , 192~0,0,O
11999 REM DRRW PLRYFIE LD
12000 POKE 752,1:SETCOLOR 4,7,6
12005 '/ " MRZEDUEL"
12010 COLOR l:PLOT O~O: D RAWTO 159~0:DR
AWTO 159~79:DRAWTO 30,79
12015 COLOR 3:DRAWTO 0~79:DRAWTO 0,60:
REM STRRTING BOX
12017 COLOR l:DRAWTO 0,0
12020 PLOT 80,61:DRAWTO 80~79
12025 COLOR 3:PLOT 1~60 : DRAWTO 30,60:D
RAWTO 30,78:COLOR l:REM STRRTING BOX
12030 PLOT 52~60:DRAWTO 52,45:DRAWTO 1
10,45:DRAWTO 110~60:DRAWTO 137~60:DRAW
TO 137,45:DRAWTO 110~45 : PLOT 159,32
12040 DRAWTO 110~32:PLO T BO,45:DRAWTO
80~20
12041 GOSUB 700:REM DRRW CRYSTRL
Typing in the Program / lSI

12050 PLOT 43,0:DRAWTO 43,30:PLOT 52,4


5:DRAWTO 22~45:DRAWTO 22~13:PLOT 108,0
:DRAWTO 108, 17:POKE 559,34:RETURN
13000 XO=O:X1=0:REM HORIZ.PL~YER POS.
13010 YO=78:REM UERTIC~L PLAYER POS.
13015 Yl=78
13020 POKE 704,KOLORO:POKE 705,KOLOR1:
REM INITI~L COLOR
13025 POKE MOPL~O:POKE M1PL~0:REM SET
MIDTH OF PLAYERS
13030 POKE 53248~XO:POKE 53249~Xl:REM
SET HORIZONTAL POSITION OF PLAYERS
13040 PLAYERO$(YO)=LEGS1$:REM PUT DATA
IN PM MEMORY
13045 PLAYER1$(Yl)=LEGS1$:REM PL~YER2
13050 RETURN
\
Odds and Ends

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

• Suppose you want your normal player (players 0 through 3) to appear


behind all playfields. The usual practice would be to poke 4 into location
623. But suppose you want a fifth player. Assuming PRIOR is initialized to
623, how would you code this?

ANSWER

POKE PRIOR,4+16 (or POKE PRIOR,20)

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 .)

Horizontal Movement. Horizontal movement of the fifth player is not so


easy. Each missile still keeps its own horizontal position register. So to move the
fifth player horizontally (in one piece) you have to poke all four horizontal
position registers. Assuming that you have all missiles set to normal width, you
might do it like this:

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.

Col/lslon Detection. Another consideration is collision detection. Each mis-


sile still has its own collision detection register. That could be interesting. For
example, you might specify that your player is vu lnerable only if he is hit in the
right arm. (He couldn't be hit by a missile, of course, but he might be hit by a
" laser" created with a DRAWTO statement. Or he might be hit by another
player.)

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

POKE 623, 1+16+32 (or POKE 623.49)


l
GRAPHIC SHAPE REGISTERS
Now let's turn to another topic: the graph ic shape registers. So far we haven't
needed these registers. That's because we allocated a special area in memory
156 / Odds and Ends

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:

Player Number Location


a 53261
1 53262
2 53263
3 53264

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

Missiles ........... . ..... .. .... 4


Players .. . ........ .. .... .. .... . 8
Single-line resolution .. ... ..... . 16
Double-line resolution .. ..... . .. 32

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:

PMG in graphics mode 0


The fifth player
Priority selection
Playfield size selection
Overlapping of players to get multicolored objects
A simplified PMG setup (using the graphics shape registers)

If you have w ritten programs in graphics 0, you may want to consider


spicing them up with some of the techniques demonstrated in this program.
Happy hacking!

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

44 POSITION 24~11:? " Color to "


46 POSITION 24~12:? "Graphics Mode 0."

50 DELAY=300:GOSUB 700:REM PAUSE FOR A


MOMENT
60 POSITION 24,16:? "Like this!":DELAY
=50:GOSUB 700
62 POKE 53248~176:POKE 53249~144:REM P
UT PLAYERS ON SCREEN
65 DELAY=100:GOSUB 700
70 POSITION 24,18:7 "It's also easy"
80 POSITION 24,19:? " t o change that"
81 POSITION 24·~20:? " c olor. ":DELAY=200
:GOSUB 700
85 FOR 1=0 TO 254 STEP 10:X=5 A 3:POKE 7
04~I:POKE 705,I:NEXT I:REM X=5 3 is ad
A

ded here simply to add a pause


90 POKE 704,BO:POKE 705~80
100 GOSUB 700
102 ? CHR$(125':POSITION 2,3
105 ? "And it's easy t o"
106 ? "go back to the regular"
107? "playfield color."
lOB GOSUB 900
110 POKE 5324B~0:POKE 53249,0:REM MOUE
PLAYERS OFF SCREEN
115 GOSUB 700
117 ? CHR$(125':? :? : POSITION
120? "You can also f i ll"
125 ? "the entire screen"
130? "with all 5 players."
135 DELAY=400:GOSUB 700
140 ? : ? "Li ke so:": X=X""3
150 GOSUB 1000:REM MOUE ALL 5 PLAYERS
ONTO SCREEN
230 GOSUB 700:? CHR$( 125):POSITION 2,3

232 ? "The playfield i s now hiding"


234? "behind the players.":? :?
235 DELAY=250:GOSUB 700
236? "Now I'll put it in front"
238? "of the players."
239 DELAY=100:GOSUB 700:POKE 623~4+16
240 DELAY=500:GOSUB 700:? CHR$(125):PO
Sample Program / 159

SITION 2,10: 7 "Ne:·~ t, when you press a


key,"
241 7 "I'll shrink the playfield"
242 ? "for a moment by poking ":7 "Loc
ation 559 with 33."
243 GOSUB 900:7 CHR$(125):POKE 559,1+3
2:DELAY=200:GOSUB 700:POKE 559,2+32
244? :? :7 "Ne}~t, let's set each play
er"
245 ? "to a different cellor."
246 GOSUB 900:POKE 559,2+32
247 POKE 704, 16:POKE 705,64:POKE 706,9
6:POKE 707, 144:POKE 711,192:REM SET PL
~YERS TO DIFFERENT COLORS
248 7 CHR$(125):GOSUB 700
250 POSITION 2,3:7 "Not.ice that player
s "
252 ? "(1-3 are behind the playfield"
254 7 "but Player 4 (at right)"
255 7 "is in front of the playfield."
260 GOSUB 900
265 7 CHR$(125):POKE 623,4+16:REM SET
PRIORITIES ~ND EN~BLE 5TH PL~YER
270 POSITION 2,3:7 "As you can see, PI
ayer 4"
272? "(the one made up of missiles)"
274 ? "always displays in front of"
276 7 "all playfields.":GOSUB 900:7 CH
R$(125):POSITION 2,3
277 7 "Let's get rid of the ":7 "playf
ield again. ":GOSUB 900:7 CHR$(125) :pm~
E 623,1+16:POSITION 2,9
2787" Playfield now hiding.":GOSUB
900
280 7 CHR$(125):POKE 623,4+16:POSITION
2,3
282 7 "In conclusion, here's an"
283 7 "e:{ amp 1 e of how you can"
284 7 "overlap players to create"
286? "a multicolored object."
290 GOSUB 900:? CHR$(125)
292 POKE 623,1+16+32:REM SET PRIORITY.
EN~BLE 5TH PL~YER. CRE~TE MULTICOLORED
OBJECT NHEN PL~YERS OUERL~P
160 I Odds and Ends

299 REM SET PLRYERS 0 RND 1 TO OVERLRP

300 pm:::E 53248~48:REM PLRYER 0


310 F'OKE 53249~48+16:REM OVERLRP
32c) POKE 53250~0:REM MOVE OFF SCREEN
350 POI<E 53251~O
360 POKE ~53252, ()
370 pm:::E 53253,0
380 F'OI<:E 53254~O
390 POKE 53255,0
400 POSITION 18, 10:? "The thr-ee color-s
"
410 POSITION 18~11:? "at left wer-e "
420 POSITION 18,12: ? "pr-oduced by"
425 POSITION 18,13: ? "Players 0 g~ 1. "
430 POSITION 1E3~ 15:? "You can use the"

432 POSITION 18,16:? "same idea to"


434 POSITION 18~17:? "make a multi-"
436 POSITION 18~18:? " c olor-ed flying"
438 POSITION 18~19:'":' "spacecr-aft!"
440 POSITION 18~22:? "END OF PROGRRM"
499 GOTO 499
500 POKE 623,1+16:REM DISPLRY PLRYERS
IN FRONT OF PLRYFIELD. ENRBLE 5TH PLRY
ER
505 POKE 53256~3:POKE 53257,3:POKE 532
58,3:POKE 53259,3:REM S ET RLL PLRYERS
TO QURDRUPLE NIDTH
507 POKE 53260~192+48+12+3:REM SET RLL
MISSILES TO QURRUPLE NIDTH
510 POKE 704~80:REM SET PLRYER 0 COLOR

512 POKE 705,80:REM PLRYER 1 COLOR


514 POKE 706~80:REM PLRYER ...r, COLOR
516 POKE 707~80:REM PLRYER 3 COLOR
518 POKE 711~80:REM PLRYER 4 COLOR
559 REM POf:E DRTR TJIR ECTLY INTO THE T
HE PLRYER GRRPHIC REGI S TERS
560 POKE 53261,255:REM IMRGE FOR PLRYE
RO
570 POKE 53262,255:REM PLRYERl
575 POKE 53263~255:REM PLRYER 2
580 POKE 53264,255:REM PLRYER 3
Sample Program / 161

582 POKE 53265,255:REM PLRYER 4!


699 RETURN
700 FOR 1=1 TO DELAY:NEXT I
710 RETURN
800 IF PEEK(764){>255 THEN POKE 764~25
5:RETURN
810 GOTO 800
900 POSITION 2~22:':' "TAP ANY KEY":':' "T
o CONTINUE":GOSUB 800
910 POSITION 2~21:? " ":?
" "
920 RETURN
999 REM MOVE RLL PL~YERS ON SCREEN
1000 POKE 53248~48:REM HOR. POS. PO
1010 POKE 53249~48+32
1020 POKE 53250~48+2*32
1030 POKE 53251,48+3*32
1040 POKE 53252~48+4*32
1050 POKE 53253,48+(4*32)+8
1060 POKE 53254,48+(4*32)+16
1070 POKE 53255,48+(4*32)+24
1080 RETURN
Appendix

Player Color Location

Player LocatIon
o 704
1 705
2 706
3 707
4 (miss iles ) 711

A guide for designating your player's color:

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.

Player Missile Memory

To te ll ANTIC where the start of PM memory is we simply poke the proper


address into location 54279, the player-miss ile base register. Example:

PO KE 54279,ADR(BUFFER$)

Location 559, DMACTL

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

Location 53277, The Graphics Control


Register (GRACTL)
Use this location along with 559 to "turn o n" the PMG system.

If you want: Then:

Missiles on ly Poke 53227,1


Players only Poke 53277.2
Players and Miss iles Poke 53277.3

Horizontal Position Registers


Location Player

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.

Location Joystick Number


632 o
633 )

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

Location Used to Control


53760 Pitch of voice 0
5376) Distortion and volume of voice 0
53762 Pitch of voice )
53763 Distortion and volume of voice )
53764 Pitch of vo ice 2
53765 Distortion and volume of voice 2
Player Collisions / 167

53766 Pitch of voice 3


53767 Distortion and volume of voice 3
53768 Pitch of all voices

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

Memory Location Shows:


53248 Missile 0 to playfield collision
53249 Missile 1 to playfield collision
53250 Missile 2 to playfield collision
53251 Missile 3 to playfield collision
53256 Missile 0 to player collision
53257 Missile 1 to player collision
53258 Missile 2 to player collision
53259 Missile 3 to player collision

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

Location 53278, Hit Clear Register


To clear all collision registers, poke a 1 into HITCLR (l ocation 53278).

Location 623, Priority Register

Display Priority Value to Poke into 623


All players in front of all playfields.
Players 2 and 3 behind playfields;
players 0 and 1 in front of
playfields. 2
All playfields in front. 4
Players in front of some play-
fields, but behind others. 8

Suggestion: Experiment! Move your players over various playfield objects


to discover the effect of various priority settings.

Other Options for Location 623


Pick the desired options and add up the va lues. Poke the total into location 623.

Option Value
Combine missiles to make a 5th player. 16
Overlap players to make a third color. 32

Graphics Shape Registers


Player Number Location
a 53261
1 53262
2 53263
3 53264
All missiles 53265
Index

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

Single line resolution 109 Speed, changing 58


SLRES.SAV 112 Strings
Sombrio, Robert Storing images in 6, 67
Joystick routine of 53 T
Sound Two K boundaIY 109
Demo 81
Registers 81 V
Statement 77 Variable names 118
Traveling 84 Vertical position 41
SOUNDRUN.SAV 86
-

You might also like