Animations
Simulations
Language
Pogo
BY JIM KENT
START CONTRIBUTING EDITOR
If you think there's nothing new in programming languages, then think again. Premiere ST programmer Jim Kent has created a great new "creature-oriented" language. It has features of C, Logo and even C + + and SmallTalk. It's Pogo and it's on the START disk this month. You'll need a color monitor to run Pogo.
Learn creature programming with POGO.ARC and POGOSRC.ARC on your START disk.
Pogo has its origins in the computer language Logo, which Seymour Papert created in part as a teaching tool for programming. Graphics in Logo employs the metaphor of a turtle with a pen tied to its tail; you move the turtle around the screen and it can leave a trail of where its been. You can tell the turtle to move forward or backwards, turn left or right, lift up or put down the pen and change the pen colors. A function to draw a circle using turtle graphics might look like this:
to circle()
{
for i = 1 to 36
{
forward(5)
right(10)
}
}
Turtle graphics programs are fun to write and easy to debug because
the results are immediately visible on the screen. I've seen eight-year-olds
write beautiful snowflake generators and intricate software spirographs
in the time it takes their parents to reach the bottom line of their income
tax spreadsheet.
Pogo, like Logo, uses turtle graphics. Pogo also has built-in animation features and a simple but effective approach to multiprocessing. Most of Pogo's syntax looks like C, but I borrowed a few things from BASIC. Even if you're a beginning BASIC or C programmer you should have no trouble writing Pogo code after studying some of the sample programs on disk.
Running Pogo
Pogo is an interpreted language. Pogo programs must be in ASCII format
to run. To get started with Pogo, copy the files POGO.ARC and ARCX.TTP
onto a blank, formatted disk and un-ARC POGO.ARC following the Disk Instructions
elsewhere in this issue. (The Aztec C and assembler source code to Pogo
is in the file POGOSRC.ARC.)
Pogo is a TTP (TOS Takes Parameters) program, which means that when
you double-click on POGO.TTP you will see the TOS Open Application dialog
box. Type in the name of the Pogo program you wish to run; if you omit
the file extension Pogo will use P0G.
Pogo in Action! This is one of several simple graphics demos on your STARIT disk. Built-in Pogo graphics functions make drawing lines, circles, disks and rectangles a snap. Archive File: POGO.ARC Filename: L1NES.POG Related programs: CIRCLES.POG, DISKS.POG |
You can install also Pogo as an application. From the Desktop, click once to highlight the POGO.TTP icon and select Install Application from the Options menu. Under document type enter POG and click on OK. Now all you have to do is double-click on a POG file to run it. If you'd like to install Pogo as an application permanently, you must save your Desktop before shutting off your computer.
All Pogo programs run in low resolution; however; you can run Pogo from either a low or medium resolution Desktop. You can exit from any Pogo program by pressing [Control]-[C].
Creature Comfort
The main thing that sets Pogo apart from traditional programming languages
is its unique approach to multiprocessing. Traditional systems simulate
multiprocessing on a single processor using a method known as time-slicing.
A peripheral clock chip is programmed to interrupt the CPU at regular intervals.
On receiving a clock tick, the current process is halted and the next process
on the ready list is started. However, communicating between processes
requires elaborate synchronization safeguards so that one process doesn't
read data that another process hadn't finished updating when the clock
interrupt was received.
Pogo in Action! By defining a snowflake creature once, you can simulate a snowy evening simply by spawning and evolving snowflakes inside a loop. A more ambitious program could draw more complex snowflake shapes. Archive File: POGO.ARC Filename: SNOWING.POG |
Pogo, on the other hand, uses a technique I borrowed from the world of video games. In an arcade game, for example, the program must manage aliens, asteroids and one to four or five human players and each of these processes should appear to be happening at once. In Pogo, such processes are called creatures.
Each creature has its own code and private data and can take care of
moving and displaying itself. Pogo has built-in routines for a creature
to find its closest neighbor; so a creature can be responsible for killing
whoever it collides with as well.
Pogo in Action! This ecological simulation features fountains that create green dots, creatures that eat the green dots and creatures that eat the creatures that eat the green dots. Watch this fascinating demonstration to see which species survive! Archive File: POGO.ARC
|
Tell Me That It's Evolution
A typical Pogo program consists of a main section of code which creates
the various creatures. The program then executes the creatures using the
Evolve() function; usually this statement is inside a loop. Finally the
program might print some status when the creatures are done.
Once you've written the code for a single Pogo creature you can spawn multiple instances (copies) of it as easily as spawning one. For example, to fill the screen with stars you would first define a star creature as a flickering point of light, and then generate many stars in the loop:
for i = 1 to 64
spawn(star,random(320),
random(200),0,0)
Once creatures have been spawned, it is only necessary to use an Evolve() statement to have the program execute the star's code. Similarly, a single Evolve() statement will execute the code of all creatures that have been spawned as of that point.
This is a key feature of Pogo, one that places it closer to the class of object-oriented languages such as C+ + or Smalltalk than BASIC, C or assembly language.
See the sidebar take-apart of the Warblers program for a complete example of creature-oriented programming in action.
And That's Not All.
We've included several sample Pogo programs on your START disk; they
are all in the file POGO.ARC. LINES.POG, CIRCLES.POG and DISKS.POG are
all graphic demos. BUSH.POG draws a pretty turtle graphics recursive bush;
and the screen is saved to disk as a DEGAS .PC1 file.
FOLLOW.POG is a simple video game. Move the disk with the mouse and try to avoid the little circles that come out of the upper left corner and go into orbit around you. If you get hit by a circle your disk grows, making it that much harder to avoid other circles. Eventually your disk gets so big you blow out and the game is over. The longer you stay alive the higher your score.
ECOLOGY.POG is an ecological simulation that really shows off the power
of Pogo. The world contains fountains which generate green dots; red circles,
blue circles and "purplers" all use green dots for food. When a green dot
comes into range of a red, blue or purpler that creature gets a little
bigger Each of these creatures approaches survival in its environment a
little differently. For example, purplers actively chase dots, whereas
reds stake out a good position early in their lives and stay put.
Pogo in Action! This video game forces you, the large disk, against a host of smaller circles who follow you about. Use the mouse to control the disk: if one of the little circles touches you you grow even larger! Archive File: POGO.ARC Filename: FOLLOW.POG |
The Ecology world also has a predator creature named Harry an orange circle that hunts down reds, blues and purplers; when Harry encloses one of their center points, he gobbles them up and grows a little larger The larger the creature he eats, the larger he grows.
When a red, blue or purpler-or Harry-gets big enough, it reproduces. It will get smaller and eventually die if there isn't any food around. Purplers are the only creatures smart enough to run away from Harry; however, often their flight takes them offscreen and away from their source of energy.
Ecology's screen shows some status information; it tells how many times the creatures have evolved and how many of each there are.
Implementing Pogo
The source code for Pogo is in POGOSRC.ARC. Pogo is written in Aztec
C and assembler Much of the code is computer-independent; the files that
are specific to the ST (mostly low-level graphics and I/O) all start with
the letters ST.
Pogo is a one-pass recursive descent compiler that generates an intermediate code for a stack-based virtual machine, which currently has about 32 instructions. Most of these are to implement all the operators it has. Upon sighting a constant or variable, it pushes it onto the stack. Binary operations take the top two members of the stack and replace them with the result. Unary operations act on the top of the stack. Each instruction is six bytes long-two bytes of op-code and four for data.
If you'd like to hack a new function into Pogo (perhaps some sound or a way to save Cyber Paint sequences), look at the file PREDEFS.C. If you'd like to see how a compiler can convert something like this statement into machine code:
d = SqrRoot( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))
try studying the files EXPRESS.C and STATEMEN.C. If you just want to
know how Pogo can read in a .PC1 file so much faster than DEGAS Elite,
check out STGFX.C and STUNPACK.ASM and look for the function rpcl().
Pogo in Action! This program uses a recursive function to draw branches. This program uses turtle graphics, which is a way to program graphics by giving directions to an imaginary turtle who moves about the screen. When the program is finished, it uses a built-in Pogo function to save the screen as a DEGAS.PC1 file. Archive File: POGO.ARC Filename: BUSH.POG |
Conclusion
I've learned a lot writing the Pogo compiler. I hope you'll enjoy programming
in Pogo as much as I do. I've always liked the C language, but C tends
to crash the computer if you make a mistake. On the other hand, Pogo will
usually tell you politely where the error occurred and let you exit cleanly
without a reboot. You can break out of a hung-up Pogo program with [Control]-[C].
Pogo is not as fast as C, but most programs will spend most of their time doing graphics and other built-in functions which are in high performance machine code already. I'm not sure if Pogo is the answer to GFA BASIC 3.0, but for quick simulations and video games on a color system you'll find it hard to beat.
Jim Kent is a START Contributing Editor and the author of Cyber Paint Aegis Animator, Flicker and the Audio-Video Sequencer
Pogo at a Glance
Here is a brief overview of Pogo's syntax and built-in functions. A complete description of each function and a more thorough discussion of the language itself is in the file POGO.TXT in the POGO.ARC file. After you've un-ARCed POGO.ARC, double-click on POGO.TXT to view or print the file from the Desktop.
Comments:
Everything to the right of a semicolon is disregarded.
Variables:
Declaration (type is either string or int)
type i,j,k
type linkcount
Arrays
int bigarray[500], littlearray[16]
Numeric Constants:
Decimal constants. No floating point
5 100 -200
Hexidecimal constants
0x10 0xFF 0xabc
Character constants in single quotes.
'a' '*'
Numeric Expressions (listed in decreasing precedence):
Unary plus and minus, binary not
+5 -x ~a
Multiplication, division, modulus, binary left shift, right shift, binary
and
5 * 5 a/b 4%3 a<<b b>>c b&c
Addition, subtraction, binary or, xor
a+b x-5 a|b a^b
Comparison operators: Equal to, not equal, greater. less, etc.
a==b a!=b a>b a<b a>=b a<=b hello == "Hi Doc!"
Logical not
!a
Logical and
a && b
Logical or
a||b
(Note: Comparison and logical operations evaluate to 1 for true, 0 for false~ In conditional branches any non-zero is considered true.)
String Expressions:
A string constant enclosed in quotes
"Hello World"
A function returning a string
StrNum(100)
Two strings concatenated with a plus sign
filename = "FRAME" + StrNum(i) + ".PC1"
Assignment statements:
var = expression
Compound blocks of statements:
{
statement1
statement2
...
}
If statements:
if expression
statement1
else
statement2
Loop statements:
loop
statement
loop
{
statement1
statement2
if expression
break
statement3
}
For statements:
for var = expression to expression [step]
statement
for i = 0 to x
statement
for i = 100 to 50 step -5
statement
While statements:
while expression
statement
Goto statements:
goto label
forever:
Prints ("Hello")
goto forever
Constant declarations:
constant red = 3
Function declarations:
function say_hello()
{
Prints ("helld')
}
to add2(a,b)
{
return(a+b)
}
Function usages:
say_hello()
a = add2(5, 2*c)
Creature declarations:
creature name
{
statement
statement. . .
}
Input oriented functions:
InKey()
Keyboard()
WaitKey()
MouseX()
MouseY()
MouseLeft()
MouseRightO
Clock()
UsejoystickO
UseMouse()
Joystick() (see POGO.TXT for value
returned)
Text output functions:
Print number in decimal on a line
Print(number)
Print string and a new line
Prints(string)
Prints(NULL)
Print string without a new line
Text(string)
General-purpose graphics functions:
ToText()
ToGraphics()
PutDot(color, x, y)
GetDot(x,y)
Rectangle(color xl, yl, x2, y2)
Disk(x, y, radius, color)
Circle(x, y, radius, color)
Gtext(color, x, y, string)
Gnumber(color, x, y, digits. number)
Line(color,xl,yl,x2,y2)
ClearScreen()
SetColor(color, r, g, b)
(Note: the values for r, g and b are from 0 to 255.)
LoadPic(fllename)
SavePic(filename)
Screen-oriented graphics functions:
AllocScreen()
Pscreen()
UseScreen(screen)
CopyScreen(sscreen, dscreen)
Blit(w,h,sscreen,sx,sy,dscreen,dx,dy)
FreeScreen(screen)
Animation display functions:
PreSwap()
Swap()
DeSwap()
Vsync()
Turtle graphics:
(Note: turtle is floating point position. Not much good for real-time,
but you can do lots of LOGO tricks.)
Right(degrees)
Left(degrees)
PenUp()
PenDown()
PenColor(color)
Forward(pixels)
Reverse(pixels)
Math functions:
Random(max)
XYangle(x,y)
SquareRoot(x)
Distance(xl,yl,x2,y2)
ArcX(angle,radius)
ArcY(angle,radius)
String-oriented functions:
StrNum(number)
StrChar(char)
StrLen(string)
CharAt(string, index)
CharTo(string, index, char)
NULL
Text file functions:
Fopen(name, mode)
Fclose(f)
GetChar(f)
GetWord(f)
GetLine(f)
Creature locating functions:
ClosestCreature(id,x,y)
ClosestT(type,x,y)
NamedCreature(name)
ExistsCreacure(id)
Creature information functions:
CreatureX(id)
CreatureY(id)
CreatureAge(id)
CreatureNewBorn(id)
CreatureName(id)
value = Cread(type, var, id)
Cwnte(type, var, id, value)
Creature life and death functions:
id = Spawn(creature,x,y,dx,dy)
Evolve()
Kill(id) (Note: Kill(cid) amounts to suicide.)
KillAll()
Creature spawn parameters:
Cx
Cy
Cdx
Cdy
Other system-maintained local creature variables:
Cid
Cage
Cnew
Cname
A Sample Program-the Warblers Game
A warbler is a circle that grows and shrinks as it moves across the screen. Some warblers pulse rapidly while others grow and shrink more slowly. You have a disk which follows the motion of the mouse. The object of the game is to surround the warblers with the disk when they are smaller than you are. If your disk surrounds a warbler, you eat it and your disk gets a little bigger if the warbler surrounds your disk, it eats you and the game is over.
The warblers Pogo program is fairly simple. There are only two types
of creatures-one for the warbler circles and one for the mouse disk. (Note:
Pogo function and variable names are not case-sensitive. For clarity in
this take-apart I'll use names starting with an uppercase letter for built-in
Pogo functions and variables and lowercase for the ones defined in the
warblers program. A semicolon marks the rest of the line as a comment.)
The code starts out with a few global
variables. |
int mouseid ;The creature id of mouse so warblers
can find it.
int mouserad ;Radius of mouse. Gets bigger every other warbler you eat. int warblers ;Number of warbiers alive. If it gets down to zero you win! |
When a warbler goes offscreen it
comes back on the other side. Here are two functions that help implement this "wrap around." |
to wrapx(x)
{ if (x> 320+ 50) ; offscreen 50 to the right? x = -50; ; then move it to left of screen if (x < -50) ; offscreen 50 to the left? x = 320+ 50 ; then move it to right of screen retum(x) } to wrapy(y) { if (y> 200+50) y = -50 if(y< -50) y = 200+50 return(y) } |
Here is the code for the warbler crea-
ture. This is the brains of the program. The warbiers take care of pulsating themselves and also see if they are hav- ing a run-in with the mouse |
;The pulsating circle creature.
creature warbler { int csize ;current size int dsz ;rate of change of size int cmax ;maximum size int cmin ;minimum size int color ;color of this warbler int md ;used to hold distance to mouse |
1st time through randomly initialize
some of our variables. |
if (Cnew) ;Cnew is true only first time a warbler is Evolve()'d
{ cmin = Random(5)+2; ;min radius cmax = Random(16)+5 ;max radius dsz = Random(3)+1 ;speed of radius change if (Random(1)) ;randomly make it start out shrinking or growing dsz = -dsz; csize = (cmin + cmax )/2 ;start 1/z way through size cycle color = Random(4)+1 ;color random between 1 and 4 } |
Do stuff to figure out what size warbler
is this frame. |
if (!(Cage&31)) ;every 32 ticks increase max radius
size by 1
cmax = cmax +1 csize = csize + dsz if (csize > cmax || csize < cmin) ;if hit mm or max reverse delta radius dsz = -dsz |
Move warbler by adding its speed to its
position, and piping through a 'wrap' function in case result is off-screen. |
Cx = wrapx(Cx + Cdx) ;Cx and Cdx are passed from the 'Spawn'
call below.
Cy = wrapy(Cy + Cdy) |
Interact with the mouse creature | if (mouseid) ;if the mouse creature is still alive.
{ ;find distance to mouse md = D istance(Creaturex(mouseid ),Creaturey(mouseid), Cx, Cy) ;if inside mouse radius, suicide if (md < mouserad && csize < mouserad) { if (warblers&1) ;every other warbler increment mouse radius mouserad = mouserad+1 Kill(cid); warbiers = warblers-1 return; } |
If mouse inside our radius kill it. | if (md < csize && csize > mouserad)
{ Kill(mouseid); mouseid = 0; } } Circle(Cx,Cycsize,color) ;draw ourselves } |
The mouse creature is quite simple
since it doesn't need to figure out whether it has hit a warbler or not. It just calls the built-in Mouse functions to set its current position on the screen (Cx and Cy) and then draws a disk in color 13. |
creature mouse
{ Cx = MouseX() Cy = MouseY() Disk(Cx,Cy,mouserad,13 } |
Finally there's the main code for the game: | loop ;repeat forever (or until user doesn't want to play
again)
{ KillAll() ;Kill any creatures left from last game mouserad = 8 ;mouse starts with an 8 pixel radius mouseid = Spawn(mouse,0,0,0,0) ;make the mouse for warbiers = 0 to 12 ;make 13 warblers { int ix,iy |
Make a warbler at random position on
screen and random speed between -3and3 |
ix = Random(6)-3 ;speed
from -3 to 3
if (ix = = 0) ;don't allow 0 x speed ix=1 iy = Random(6)-3 if(iy == 0) iy = 1 Spawn(warbler, Random(320), Random(200), ix, iy) } PreSwap() ;Set up for double buffering |
Here's the main game loop. Keep going as
long as there's warbiers alive and the mouse is alive too. |
while (mouseid && warblers>0)
{ ClearScreen() ;set screen quickly to black Evolve() ;let all creatures live one tick Swap() ;swap drawing screen and viewing screen } ToText() ;back into text mode Prints(StrNum(warblers) + ' Warblers left"); if (warblers <= 0) { Prints("You won!!!") } PrintsC Play again? (y/n)") int key ;oops, need another variable. . key = WaitKey() if (key = = 'n'|| key = = 'N') break |
And that's all there is to it: a video
game in about 100 lines of code! |
} |