Atari 7800 Basic Lesson 2: Sprites

Note: This tutorial series is designed as video series. The text below is provided as a way to make it easier to follow, but I recommend you watch the video and use the text as supplemental.

Introduction

In Our first lesson on Atari 7800 Basic we made a simple “Hello World” program with a color rotating background.

In this lesson we will begin to turn that idea into a game.

The game we are making is called U.A.P. which is the modern name for U.F.O. and stands for Unidentified Aerial Phenomenon

The game is based on a certain Discovery Channel TV show.

In the game you play the UAP. 

But that’s all we know so far.

So in this lesson we will design a player sprite and get it moving on the screen with the joystick.

If you are like me, you found out about the Atari 7800 sometime in the summer 1984 reading a magazine like Electronic Games.  

And the most exciting thing about the Atari 7800 was its sprite capabilities.

Back then, the capabilities of most video game systems were defined by how many objects could be moved around the screen.  The Atari 2600 with the TIA chip had 5 sprites )player1, plater2, missile1, missile2, and the ball).  The Atari 5200 and 400/800 with CTIA/GTIA at 5 hardware sorites, but also a complicated displaylist and charcterset redefinition system  that made it seem like many more.  

But the 7800, with it’s MARIA chip offered something different.  According to Electronic Games, it would put nearly 100 sprites on the screen, and would make a game like Robotron, then and still now, one of the most impressive arcade gamesa ever made, possible to create on the 7800 with very few compromises.

But then the 7800  wide-release was canceled in 1984, and by the time it came out almost 3 years later, the NES had conquered America.

When I finally did get to play the 7800 version of Robotron, I was not disappointed as it was spectacular!   There were so many independently moving objects on the screen, with no flicker, it felt like the culmination of everything we wished for in 1984. 

But it was too little, too late by 1987 when I first played it.  I could only imagine what games the 7800 could have had by that year if game developers were three years into the development cycle.

So To me, this is the actual lure of the 7800.
The “What Could Have been”?

And much of that stems from the sprite capabilities of the MARIA graphics chip.

One other note.  Atari 7800 Basic is very powerful, but it;s still a “game engine” built in assembly language that abstracts the full power of The Atari 7800.  In this regard, it’s better than bAtari Basic for the 2600, which but it’s still limited compared to programming in full Assembly language.

A good indication of this is how it handles Zones.


Recall, “zones” are horizontal bands, 8 or 16 pixels high.  Only a  certain number of sprites, determined by how long it takes to draw each line on the CRT, can be displayed at a time in a zone.

Atari 7800 Basic abstracts the programmer from having to deal with the zones.

7800basic Guide (randomterrain.com)

This is probably a good thing when you are getting started, but as you advance, you may find that you need more flexibility.  And that flexibility will come with Assembly language.  But that is too much for these tutorials so we will concentrate on what 7800 Basic can do for us.

Note: The Three C’s

In the last lesson I may have failed to make a few things abundantly clear. 
These are rules to live by when programming games in Atari 7800 Basic.

I call them the “Three C’s”  

Code.Case.Configuration.

Well okay, I just made that up on the spot, but you’ll see what I mean

Code

Remember that tabs matter in Atari 7800 Basic.

All regular code MUST be tabbed-in at least 1 space, or it will cause errors.

All _labels for gotos and gosubs must be in the first first column.

There are few exceptions, but we will talk about those if we bet to them.

Case

Case matters.

If the code example says “32k” and the “k” is lower-case, and you use an upper-case “K”, the compiler will throw an error.  Just this one concept can save you a lot of headaches.

Configuration

VS Code needs to be configured to compile your code using the Atari 7800 compiler that came with Atari Dev Studio.  This usually occurs automatically if you have you saved  source files with the .78b extension.   However, if that does not occur, you need to configure VS Code to compile as a 7800 binary.

Check the lower right of VS Code. If it says “7800 Basic” (white text on blue), you are good to go.  If not, click on the text in that location (it might say something like “bAtari Basic” and select Atari 7800 Basic on the selection screen.

By remembering the “Three C’s” (Code, Case, Configuration) you should avoid a lot of headaches when compiling.

Now onto the lesson

Step – 1:  Title Screen / Game Loop

First we need to separate our title screen from our game loop so we can have a place to initialize the game and a place to execute the game.

We will be working from the code design in lesson 1, Hello World.  

The first thing we will do is add a couple more variables : lives and score.

We are not actually sure what we use these for yet, but they are indicative of the types of variables our game will use.

First we will define them, then we will initialize them.

 dim lives = var3
 dim score = var4

 lives = 0
 score = 0

Next we will change the name of _gameLoop to _titleLoop and make sure out goto now targets the correct label

_titleLoop
 goto _titleLoop

Let’s talk a bit about labels because I believe we glossed over the topic in lesson  1.

The labels are “jump” labels and can be used with either goto or gosub.  My convention is to start them with an “_” underscore so I can easily tell them when i see them.  Label must be in the first column of a line.  Most other code must be al least 1 space in, or the compiler will barf and tell you it has no idea what to do.  

Next we will change the name on the title screen from “Hello World” to “u.a.p”.  Notice we only use lowercase letters.  That is because only lower case letters were defined in our font graphic. If you want lower and uppercase letters you can draw your own font graphic.  Infact, in the 320 modes with doublewide fonts, you could get pretty elaborate with the design of a font.  If you create text-heavy game for the 7800, you may want to explore those modes and options.

Next we plot the new text.

plotchars 'u.a.p.'  0 68 5

Then we will test the first and second joystick buttons of the first joystick (joy0fire0, joy0fire1) and if either is pressed, we will jump to a new label named _initGame.

 if joy0fire0  || joy0fire1 then goto _initGame

In _initGame we will reset everything.  This is redundant now, but as the game gets more complex there will be certain variables we want to initialize before the game executes and ones we want to reset every time the game starts.

_initGame
 lives = 3
 score = 0
 BACKGRND=$00

And now we will create a new function named _gameLoop.  It will look pretty much like the old _titleLoop, except we draw some placeholder text that says “game” to remind us that we are no longer on the title screen, and the game is about to start.

_gameLoop
 clearscreen

 plotchars 'game'  0 68 5

 drawscreen

 goto _gameLoop

When we compile and run the code, it looks like this:

The title screen will still rotate colors but it says “U.A.P.” now.
By pressing fire button 0 (Z-key or joystick button 0), the title screen will disappear and we see the “game” placeholder text.

Now, I edited this lesson to make it look like I got all of this right the first time, but that is not the case at all.

In fact, the first time I compiled I got an error, so I’ll show you what that looks like.

The complier will stop and give you information to help you figure out what is wrong.

The most useful information for beginners is this list of unrecognized symbols.

Ignore the ones that you did not define,and look for things you might have messed-up.

For this step I forgot that the name of our loop label was  _gameLoop not _gametitle.  Another common error with labels is not left justifying them. Most other code needs to be at least 1 character or tabbed in.   But labels need to be in the first column.

So if I go ahead and fix the code and re-run, the code executes as expected.

Step – 2: Drawing Sprites.

So I’ve just been clicking things on this menu bar at the bottom of the screen and not talking about them.

This little bar at the bottom right of the screen was added by Atari Dev Studio. 

The functions are : 

  • Welcome – takes you Atari Dev Studio Plug-On Page
  • Sprite Editor – it is what it says it is 
  • Compile
  • Compile and Run

We will spend most of our time on Sprite Editor and Compile and Run

To create a player sprite for the game we will click the Sprite Editor button.

You see a screen that looks like this:

Now we create a new sprite file that is 16×16 with 4 colors for mode 160A, NTSC by pressing the Project+ button on the left.

The windows can be arranged to make it easiest to see everything.

You can grab them and move them around, resize, etc.

I usually resize so I can see an entire sprite, and also the current set of sprites in sprite file I’m making.

Next we set our colors.  For the sprite I’d like to white, grey and red

Recall, as I draw this UAP sprite, that 160A mode have more pixels in the y, and less in the x, so we need to accommodate that when we draw.

Sprite file and .spe extensions, and can hold as many sprite definitions as is reasonable to work with. .spe files are not sprites through. Each  sprite must be exported as .png to be used in a game.

  

When I’m done designing the first UAP sprite, I want to make it animated by inserting a few little details that can move when we add more frames.

I press the copy sprite button, and edit the sprite to make it animate. 

 I do this two more times so my UAP sprite, the player (as you play the UAP in the game) will have four frames.  

Next, I save the player sprite .spe file in a subdirectory of my project name “images”. I call it player.spe.  

Then I export each individual frame as a .png file, naming them player1 through player4.

Now we are ready to load this sprite into our Atari 7800 game and display it.

Step – 3: Displaying Sprites

Now we will display these 4 sprite frames in succession to make it look like our UAp is animating.
The first thing we need to do is to create a color palette to match the colors we used in our sprite.  

We can find the colors we need to set in 7800Basic by looking back in the sprite editor and rolling over each color to find it’s hexadecimal value.

This image has an empty alt attribute; its file name is part2_sprite_editoir.png

In this case the values are $0D, $08, $33 which are two shades of gray plus a deep red.

 rem pallette 1 player
  P1C1 = $0D
  P1C2 = $08
  P1C3 = $33

Next we will include the sprite images we created.

The order of the inclusion is VERY important.

The order of the sprites is used for animating them.

You can easily animate sprites that are loaded in succession.

 incgraphic images/player1.png 160A 0 1 2 3
 incgraphic images/player2.png 160A 0 1 2 3
 incgraphic images/player3.png 160A 0 1 2 3
 incgraphic images/player4.png 160A 0 1 2 3 

The file names of the sprites will be used directly in the code to identify them.   They can’t contain any special characters, and need to start with a  letter.

After the name, you have other optional parameters.

“160A” is the graphics mode of the sprite.  If you don’t specify, 7800 Basic will default to 160A, which are 3-color sprites.   However, in the next lesson we will see how we can load 12-color sprites in the same way by specifying “160B”

The other numbers are color indexes.   These can be very confusing, but we will have an example in just a bit that shows how to use them.

Next we will create a couple new variables to hold the X and Y location of the sprite:

 dim playerX =var5
 dim playerY = var6
 And initialize them to 0
 playerY = 0
 playerX = 0

In the _initGame subroutine we will then initialize the values for the start of a game:

 playerX = 70
 playerY = 90

This is a good time to explain variables a little more in depth.

In the first tutorial we told you that the Atari 7800 Basic has 126 built-in variables

var0-var99 and a-z.
Some functions in Atari 7800 Basic require the a-z variables, so I avoid using them.

You can also assign direct memory locations to another 1535 single byte variables, which is ample space for most simple games.

7800basic Guide (randomterrain.com)

Each variable in Atari7800 Basic represents a single byte, which of course can hold numbers from 0 through 255.

Luckily for us, in 160A mode, the screen size is 160×192, which means a single byte can hold the X position and a single byte can hold the Y position of any sprite.

Now, let’s draw the sprite in our game loop using plotsprite

_gameLoop
 clearscreen
 plotsprite player1 1 playerX playerY
 drawscreen
 goto _gameLoop

The plotsprite command 5 parameters:

  • Name of sprite to display (filename without the extension)
  • Palette number (we defined our sprite colors in palette 1)
  • X location
  • Y location
  • Animation frame (optional, but we will use this soon)

When we compile and test this code, our UAP sits pretty much in the center of the screen.

Okay, this is where things get a bit technical.

Now, let’s look at the compiler output to understand a little bit better what we have done.

With the font and 4 player sprites loaded we have used just about 1K in the ROM (2992 bytes left) in the current block. 

Graphics are stored in memory ROM  blocks on the Atari 7800.

For a game with zoneheight of 16, the graphics blocks are 4k in size.

Graphics in different blocks will not easily animate so as you create more and more graphics to load into your game, you might need to manage the order of how things are loaded.    Also, the more graphics you have, the more chances you will need to use bank switching.

Blocks are created automatically when graphics are loaded, or you can use the “newblock” command to force a new block.


One more interesting thing to see here

The second to last line says “$1830 to $1fff used as zone memory, allowing for 31 display objects per zone.”

With a height of 192 pixels and a zoneheight of 16, that means we have 12 zones. 31 display objects per zone = 372!!.  So conceivably we could get 372 sprites on the screen!!

This why people were so excited about the MARIA chip in 1984!

However, even though a zone can has the memory for 31 objects!, that doesn’t mean they can be displayed in the time it takes to draw each scanline. Also, those display objects are EVERYTHING including and text or background map objects, etc. 

Don’t worry though, there are ways to expand this using extra RAM in the cart and double buffering will help make sure everything needs to draw gets displayed.

Step – 4: Animating The Sprite

To animate the sprite we need a way to remember which player frame we are displaying. I like to use very very descriptive variables, so we will call this one playerAnimFrame.

 dim playerAnimFrame = var7

We will initialize it before our game starts

playerAnimFrame = 0

And also after our _initGame label

 playerAnimFrame = 0

Then in _gameLoop we will add the playerAnimFrame variable as the last, optional parameter to plotSprite.

After that we increment playerAnimFrame, then test to see if it is more than 3. If so we set it to 0.   

_gameLoop
clearscreen
plotsprite player1 1 playerX playerY playerAnimFrame
playerAnimFrame = playerAnimFrame +1
if playerAnimFrame > 3 then playerAnimFrame = 0
drawscreen
goto _gameLoop

Notice a couple things here.

We only ever have to use the name of the first sprite, “player1”.  Because we loaded all 4 sprites in sequence, it will treat the  subsequent sprites as a “frame” of this first sprite if we use the optional frame parameter as we did here.

There is no magic here.  The “frame” parameter is simply moving to the next 160A, 4-color sprite. This could be ANYTHING.  For instance, if you have an explosion that is loaded directly after the player sprite, and you don’t reset the playerAnimFrame back to 0 when it’s above 3, your explosion frames will be displayed.

Now let’s test this.

When you press the “rocket” and compile this version, you will see the UAP animating very quickly in the middle of the screen.   It’s neat, but too fast.

There are many ways to slow this down, but we will employ one that will be necessary for our game: double buffering.

7800basic Guide (randomterrain.com)

Double buffering allows you to define how many frames it will take to draw the screen. It also regulates the frames using a timing delta calculation so animation is smoother.

This is a function of Atari 7800 Basic provided to help manage sprites, zones and memory, and it;s very useful one.  

In our  boilerplate at the top of the program we will use the doublebuffer directive to turn on the functionality

 doublebuffer on

Then in _gameLoop we will replace drawscreen with this line of code

doublebuffer flip 2

“flip 2” tells Atari 7800 Basic to use two frames to draw the screen.

When we compile and run this version, you will see that UAP animates slower at 30fps or 30hz and not the default 60fps or 60hz.    

Let’s look at the compiler output.



Now the compiler tells us that we can only get 14 objects per zone.  This is because doublebuffering is turned on.  The resources needed to smooth out the animation mean there is less memory for sprites.  This is fine, don’t worry.  

We were never getting 300+ sprites on the screen anyway.   

There are other levers we can pull to get more sprites in zone that we will learn about later.

But we are now getting closer to a more realistic number of sprites that can be displayed.    

While we will ultimately need doublebuffering for this game, it’s not a great way to control the speed of animation.  Most likely we will want to control each sprite’s animation individually.

To do this we will create a  new variable name playerAnimWait.

We will use the variable to count frames before we move to new animation frame

 dim playerAnimWait = var8

Will will also initialize it like  the other variables:  before the game start running andafter the  _initGame label

 playerAnimWait = 0

And:

And

_initGame

 playerAnimWait = 0

Now, in the game loop, instead of incremented playerAnimFame every _gameLoop, we will count to “3” by incrementing playerAnimWait.  Every time it goes above 2, we will then increment playerAnimFrame.  

By doing this we will get much more control over the speed of the sprite animation.

_gameLoop

 clearscreen
 plotsprite player1 1 playerX playerY playerAnimFrame
 playerAnimWait = playerAnimWait +1
 if playerAnimWait > 2 then  playerAnimFrame = playerAnimFrame + 1 : playerAnimWait = 0
 if playerAnimFrame > 3 then playerAnimFrame = 0

 doublebuffer flip 2

 goto _gameLoop

When you compile and run this time, you will see that the sprite animated slower, but also that the middle portion doesn’t look quite right. 

Now that we actually can see the sprite, we can also see how it animates. 

Let’s go back into the sprite editor and update the frames to make a different animation,. Instead of animating horizontally, let’s make the middle portion animated vertically. 

Now. Save the player.spe when we are done, and export each frame again.

When we compile and run the code again, something odd happens.  It looks like a couple of the colors are different than what we defined in the spirite editor.

This happens a lot.  

There is an explanation for it, about how the different indexes get transposed depending on which color is used first, or something, but I’ve never quite understood.  What it means in practical terms is that you can’t always trust the colors as they are saved in the .png, and you might have to reorder the indexes.

The good news is, there is an easy way to fix this, but it might take bit of trial and error.
Remember those final parameters on the incgraphic command:

 incgraphic images/player1.png 160A 0 1 3 2
 incgraphic images/player2.png 160A 0 1 3 2
 incgraphic images/player3.png 160A 0 1 3 2
 incgraphic images/player4.png 160A 0 1 3 2

These are the MARIA chip color indexes.  To fix this little color glitch, all we need to do it swap the 2nd and 3rd indexes when we load the sprites .

Now, when we compile and run, the colors look correct, and the animation is smooth.

By the way, Atari 7800 Basic has some recent functionality that allows the programmer to extract color values directly from the loaded .PNG sprites. And putting them into color constants:

7800basic Guide (randomterrain.com)

I have not used this functionality yet myself,  but it looks very interesting. (now, now I HAVE used it, and it will feature in a future lesson).

Step – 5 : Move The Sprite!

Let’s finish up this lesson by allowing the player to move the UAP around the screen using  joystick 0.

Honestly this is the easiest lesson yet.

All we need to do is stick this very much self-explanatory code in _gameLoop:

 if joy0left  then playerX=playerX - 1
if joy0right then playerX=playerX +  1
if joy0up  then playerY=playerY - 1
if joy0down then playerY=playerY +  1

We will move the UAP 1 pixel depending on which direction of joy0 is pressed.  This code is in no way optimized.  We should add a “controlWait” counter as well, or we will read the joystick or fire button 30 times a second which might be too many.

But for now, let’s compile this code and start moving!

Well that is it for lesson 2.  Be sure to read the notes and download the code from GitHub.

Good luck and let;s get some great new games on the Atari 7800, history’s most underutilized game console!

Until next time, Into The Vertical blank!

Feel the urge to support, click here (but no obligation): https://www.buymeacoffee.com/intotheverticalblank?fbclid=IwAR0ryLpAIZPgDgjZqSmMmXLVIOFKWtSDVymoPXsJoj3KsEI0x0KCQOpJMpM

You Can get the code for this and all future lessons on our GitHub:

 intotheverticalblank/makeathing: Code for making things (github.com)

All Links:
Links: 

Source GitHub : intotheverticalblank/makeathing: Code for making things (github.com)

Visual Studio Code: Visual Studio Code – Code Editing. Redefined

Atari 7800 Basic Github: Releases · 7800-devtools/7800basic (github.com)

AtariAge 7800 Basic Forum: 7800basic beta, the release thread – Atari 7800 Programming – AtariAge Forums

Atari 7800 Basic Guide: 7800basic Guide (randomterrain.com)

Concerto Cart: Pre-production Concerto Cartridge | Erstwhile Technologies (square.site)

Leave a Reply