Atari 7800: Lesson 4 – Collect The Orbs

Published by

on

Welcome to Atari 7800 Basic Make-a-Thing lesson

Yes, I’m back.
Look at me.
That intro was done 2 years ago, and I look 10 years older now.
So, I guess I will have to do something about that.
Here is my new Youtube hat! 
This is my new look, for better or worse.
Now I feel like I can continue

You might notice that these new videos look different than the ones from the first 3 lessons.  That is because, back in 2023, a hard drive crash destroyed most of the support material I used to create these lessons.   

When I tried to look at videos they were all corrupted.

So I had to start over from scratch.

So now, I’m getting back on track and starting again from scratch.

Thanks for your patience, I know it’s been a long time.

See lessons 1-3 here:
Atari 7800 Basic Lessons 1-3 – Generation Atari

See the GithubRepo Here:
makeathing/Atari7800/Atari7800Basic/Tutorial at main · intotheverticalblank/makeathing · GitHub

Introduction

First, a bit of an update.
In the last lesson I mentioned that one of my long suffering unfinished games did not have a title screen.  That game is Last stand Halloween which was last updated in 2020.  Well, after saying that, I went ahead and made a title screen for it, and also tweaked the game a tiny bit.  It’s still a failed game, but at least I’m pleased with the title screen now.


You can a link to it in the notes, or if you are reading the on the web site, click this link below:

Last Stand Halloween : Holiday Nightmare by Into The Vertical Blank

Part  1: Designing The Orb

Okay, So let’s start this lesson with another sprite:

The Orb.

The Orb is the object the UAP needs to collect to open-up the next portal to exit the level.

You have to collect enough of them to power the wormhole, and get out of your Quantum Lay-Over.

Open up the sprite editor and create a new sprite file called “orbs.spe”.

Let’s make the Orbs three colors of blue, and look like spheres they stand-out, against the black background.

Create an 8×8 3+1 color sprite and let’s get moving!  

First choose 3 colors of different shades of blue so we can create something that looks a bit 3D.

Now, I am not that good at sprite design, but I’ll try my best.

It takes me sometime to figure out what to do when I’m making sprites, and you will see here that at first I thought I’d make some cool 3D orb in 3 frames of animation. 

However, my first attempt was not that great.

So I start over, change colors a bit, and it starts to get a little better (to me anyway).

When I’m done, I copy the sprite and edit it to make it look like it’s rotating.
At some point I decided to make it 5 frames instead of 3 because I think it will look better.

But you know what, I think 6 frames might be better, and maybe we need to make the top and bottom look like they are rotating too.

When I’m done, I save the file as orb.spe  and then I export each file as ob1.png -> orb6.spe

We are also going to create a “Portal”.
It will be formed by two 32×16 sprites to create a 32×32 sized portal.
We will create two frames so that it will animate kind of like an old NEON sign.

Save all fours parts as:

portal1_top.png

portal1_bottom.png

portal2_top.png 

portal2_bottom.png

Part 2: Put the Orb on the screen

Now load-in the orb sprites.

 incgraphic images/orb1.png 160A 0 1 2 3

 incgraphic images/orb2.png 160A 0 1 2 3

 incgraphic images/orb3.png 160A 0 1 2 3

 incgraphic images/orb4.png 160A 0 1 2 3

 incgraphic images/orb5.png 160A 0 1 2 3

 incgraphic images/orb6.png 160A 0 1 2 3

And then make a similar set of variables like we made for the player to keep track of the orb.: X location, Y location, the  current animation frame, and the count we have before the orb animates.  This should look very familiar

 dim orbX =var9

 dim orbY = var10

 dim orbAnimFrame = var11

 dim orbAnimWait = var12

Now let’s initialize these variables and set the orb to display at 50, 50 on the screen

 orbX = 50

 orbY = 50

 orbAnimFrame = 0

 orbAnimWait = 0

Next we will set a color palette for the orb based on the colors we used in the sprite editor. 

rem orb colors

  P2C1 = $92

  P2C2 = $94

  P2C3 = $99

We will set the palette #2 to the colors of the orb sprite.  


I did this manually instead of pulling the color constants because it appears that the color constants only work for the last sprite loaded.

I’m not sure why this is.  I only know that the color constant did not work, so I did it manually.

plotsprite orb1 2 orbX orbY orbAnimFrame

 orbAnimWait = orbAnimWait +1

 if orbAnimWait > 1 then  orbAnimFrame = orbAnimFrame + 1 : orbAnimWait = 0

 if orbAnimFrame > 5 then orbAnimFrame = 0

So now we are ready to test.
Compile the code, and  it launches.  Press the fire button [z] to get through the title screen.
You should see the orb rotating at x,y 50,50

Lesson4_1.78b

But something is wrong.  It looks like the colors are swapped in palette.
Let’s  move those around a bit.

 incgraphic images/orb1.png 160A 0 3 2 1

 incgraphic images/orb2.png 160A 0 3 2 1

 incgraphic images/orb3.png 160A 0 3 2 1

 incgraphic images/orb4.png 160A 0 3 2 1

 incgraphic images/orb5.png 160A 0 3 2 1

 incgraphic images/orb6.png 160A 0 3 2 1

Now test it again:

Lesson4_2.78b

There we go.  If that had not been right, we would have kept trying until we got it.

Part 3: Just How Many Objects Can You Get?

If you use the link to download the Atari 7800 Basic package from Github, you will find a number of sample programs in the /samples folder.

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

One of them is called OneHundredOne which I believe was written by RevEng Mike Saarna.

You will find it in the examples folder.

Go ahead and load the file, then examine the code.

rem ** 101 sprites double-buffered display. This routine and 7800basic can handle

 rem ** more, but Maria runs out of DMA time when too many of the sprites drift

 rem ** into the same zone. As it stands, this demo intentionally spreads the

 rem ** sprites out vertically, to help Maria out.

  rem ** Make the rom a 128k cart with ram, b

My version has  a .bas extension, so it does not compile correctly.
I needed to change , file extension to .78b before it will compile and run properly.

This is a fun program to examine and execute because it shows over 100 objects moving n an Atari 7800 screen, with little slow-down or corruption.   

It’s fascinating to see, and gives us some ideas on how many objects we will get on the screen or UAP.

Part 4: Randomly Place The Orb

We really don’t want the orb to be at 50,50 on the screen, we want it randomly placed.

Here is the code to do that.

Rand will create a random number between 0 and 255.
Of course the Atari 7800 mode A screen is less than 255 x 255, so we must limit the random values  so it is placed on the visible screen.

orbX = rand  

orbY = rand

if orbX > 151 then orbX = 151

if orbY > 183 then orbY = 183  

We also need to actually draw the orb on the screen, which looks alot like how we drew the player

Notice we use the “2” for the palette in the plotsprite command, to match the palette we defined for the orb.

 plotsprite orb1 2 orbX orbY orbAnimFrame

 orbAnimWait = orbAnimWait +1

 if orbAnimWait > 1 then  orbAnimFrame = orbAnimFrame + 1 : orbAnimWait = 0

 if orbAnimFrame > 5 then orbAnimFrame = 0

(lesson4_3.78b)

Now test this.
Now test it again.

And again.

See that  orb is placed “randomly” but since the random number sequence is the same every time, the game is the same every time, so it’s placed in the same place every time.  This is not an accident.

Think of a game like River Raid or Pitfall on the Atari 2600
The only way a game like this with seemingly so many levels on the endless river could be shoved into an Atari 2600 cartridge was to make use of some kind of repeated number sequence.   David Crane once told me it was a “polynomial sequence” .
He started with random numbers, found a sequence that worked, and then built the game off that sequence.  If the sequence was always random, the games would be unpredictable. 

However, for our game, we’d like an unpredictable random number.
To this we will use the a “seed” value that will starts the random number generator at an unpredictable place. 

 dim randomSeed = var13

randomSeed = randomSeed + 1

if randomSeed > 254  then randomSeed = 1

rand = randomSeed

orbX = rand  

orbY = rand

if orbX > 151 then orbX = 151

if orbY > 183 then orbY = 183  

(lesson4_4.78b)

Now test this version.

And then test it again.
See that by using randomseed, we can achieve our desired result of having the orb placed (somewhat) randomly on the screen each time the program is executed.

Part 5: Pick Up The Orb

So good, we have two independent objects on the screen, but that’s still not a game.  To make this game we need those objects to interact.

First, let’s update the score.

First we made a score variable, but we don’t need it so let’s comment that out.

The basic predefined variables in Atari 7800 basic can only hold 0-255, but scores are usually much more than that.

 rem dim score = var4

Instead  we will use score0, which is a special variable defined by Atari 7800 Basic that can hold a 24-bit value. 

Initialize it like this

 score0 = 0

The score0 variable is BCD, binary coded decimal, which means it can’t be easily used in operations with other Atari 7800 variables.    But we CAN add numbers to it, which we will do when we test a collision

We will print the score on the screen using the plotvalue function
plotvalue command which lets you plot numeric variables as text

One this thing that is  tricky about plotvalue the 4th parameters, which in his example is “6”.  That is the number of characters to print on the screen.  In general, since score0 is 24-bit number, I always just print all 6 numbers.

 plotvalue font 1 score0 6 124 0

Recall that when we set up this game we added this line of code:

 set plotvalueonscreen on

This directive allows numeric values to be displayed on an Atari 7800 Basic game screen.

Now we will create a new subroutine named _randomOrb and use that function to create the new orb every time we need it.

 gosub _randomOrb

It looks just like the code we’ve a;ready made, but now it’s reusable! 

_randomOrb

 orbX = rand  

 orbY = rand

 if orbX > 151 then orbX = 151

 if orbY > 183 then orbY = 183  

 return

Okay, now we are ready to test to see if objects collide.

The simplest and easiest way to do this in Atari 7800 basic is by using boxcollision.
This function tests to see if the bounding box of each object is overlapping, and if so, it returns a positive value.

Of course box collisions are not always the best and most efficient way to perform collision detection,  but they will work fine for our game. 

boxcollision has 8 parameters:

  • The X,Y location of the player
  • The width and height of the player
  • The X,Y location of the orb
  • The width and height of the orb.

We will also make another new subroutine named _testCollisions

 gosub _testCollisions

This call will come right before we plot the score on the screen in the gameLoop routine.

In our code, if we test a collision between the orb and the UAP, we will simply create new random values for orbX and orbY, and keep going.

In this subroutine, we use boxcollision to test the collision between the player and the orb.

If we detect a collision, we will add 10 to score 0 and call _randomOrb
If not we will use a goto (shock!) to skip this code

_testCollisions

 if boxcollision(playerX, playerY, 16, 16, orbX, orbY, 8, 8) then goto _doCollide

 goto _skipCollide

_doCollide

 score0 = score0 + 10

 gosub _randomOrb

_skipCollide

Now let’s test this version and see what we have.

You can collect random orbs all day and wrack up your score!

(Lesson4_5.78b)

Part 6:  Managing A Lot Of Sprites 

So now I know you are saying to yourself, “sure, one collectible seems simple, but what about having 32 all, zipping around the screen. at the same time?  

How do you manage that?

Well, honestly, in a very similar way.

Display and move 32 orbs

(lesson4_6.78b)

First let’s comment out this code that defines the variables for the single orb we randomly placed on the screen.  We will not need them any more.

 rem dim orbX =var9

 rem dim orbY = var10

 rem dim orbAnimFrame = var11

 rem dim orbAnimWait = var12

Instead we will create a set of variables to hold temp values that we will use in our code.

 dim tempX =var9

 dim tempY = var10

 dim tempAnimFrame = var11

 dim tempAnimWait = var12

We will also create a few new variables.
First and X ands Y velocity variables to hold the current speed of the orbs so we can move them around the screen.

 dim tempXVelocity = var13

 dim tempYVelocity = var14

And also a maxOrbs variable that will limit the number if orbs on the screen on level

dim maxOrbs = var16

Now comes the interesting part.
We need to define the space to hold the data for our orbs.
We want to have a lot of orbs to collect.
Let’s say we want 32 orbs, each one with separate X,Y location, X,Y velocity, animation variables, and a variable to track if it has been collected or not.

If we use one byte for each of these values that would be 256 variables!


But we only have 126 predefined single byte variables in Atari 7800 Basic, so how on earth will we track up to 32 orbs like this?

Well, besides the 126 predefined variables, the Atari 7800 also has about 1.5K of usable memory for a game.  We can make use of this memory to store the values for the orbs.

This memory starts at $2200 and ends at $27FF.

(You can also access an additional 16K of memory, if available in the memory map.)

We start by writing dim orbX = $2200
This defines the variable orbX to the memory location $2200

We then count 32 bytes (in HEX not decimal)
Then define the next variable as   dim orbY = $2220

And so on with orbXVelocity, orbYVelocity, orbAminFrame, orbAnimWait, and orbCaptured.

Each time counting 32 in HEX from the last variable location for the next one.

 rem orbs space for 32

  dim orbX = $2200

  dim orbY = $2220

  dim orbXVelocity = $2240

  dim orbYVelocity = $2260

  dim orbAnimFrame = $2280

  dim orbAnimWait =  $22A0

  dim orbCaptured = $22C0

We have now effectively defined the space for all the data we need to hold the orb data.
Now what stops you from defining the variable wrong, counting by HEX wrong, or defining other variables on top of these?

NOTHING.
You need to keep track of all of that yourself.

So be careful.

Now we initialize all the temp variables to 0.

 tempOrbX = 0

 tempOrbY = 0

 tempOrbAnimFrame = 0

 tempOrbAnimWait = 0

 tempOrbXVelocity = 0

 tempOrbYVelocity = 0

Next, in the _initGame function we will set maxObs to 32 so we can draw 32 orbs on the screen.Then we will create all the orbs to display by calling the new makeOrbs subroutine (that does not exist yet)

_initGame

 . . .

  maxOrbs = 32

 . . .

  gosub makeOrbs

So let’s make the makeOrbs routine.
This is the heart of the solution to tracking up to 32 orbs at once.
First we create a for:next loop that counts up the number of orb in maxOrbs (minus one because we start at 0).

Then we use rand to get random numbers between 0 and 255.

We use these values so that some of the orbs start off the visible screen.
We place those random numbers in orbX[i] and orbY[i] .  
The [i] after the variable is array notation for index of the array.
We use it to access all those spaces in memory we skipped when we defined these variables.   
That means each one of those variables will hold the data for all orbs, accessed by this [i] index notation.
That makes orbX and orbY parallel arrays.
Since we can’t easily define structs or objects in memory in 7800 Basic, we can instead use parallel arrays, which will make working with large sets of similar on-screen objects much easier..  

rem ************************************

 rem * fill up orbs to display

 rem ************************************

makeOrbs

 m = maxOrbs – 1

 for i = 0 to m

    orbX[i] = rand  

    orbY[i] = rand

Now we will set some random velocities for the orbs so they will start by moving in different directions on the screen.   The values between -1 and 1 are the number of pixels the orb will move in the X or Y direction on each frame.   This means orbs will move in 8 different directions.
We also set orbAnimFrame, orbAnimWait and orbCaptured to zero.

    r = rand

    if r < 255  then orbXVelocity[i] =  0 : orbYVelocity[i] =  -1

    if r < 228  then orbXVelocity[i] =  1 : orbYVelocity[i] =  -1

    if r < 196  then orbXVelocity[i] =  1 : orbYVelocity[i] =   0

    if r < 164  then orbXVelocity[i] =  1 : orbYVelocity[i] =   1

    if r < 128  then orbXVelocity[i] =  0 : orbYVelocity[i] =   1

    if r < 96   then orbXVelocity[i] = -1 : orbYVelocity[i] =   1

    if r < 64   then orbXVelocity[i] = -1 : orbYVelocity[i] =   0

    if r < 32   then orbXVelocity[i] = -1 : orbYVelocity[i] =  -1

    orbAnimFrame[i] = 0

    orbAnimWait[i] = 0

    orbCaptured[i] = 0

 next    

 return

Now we will update the _gameLoop function.Instead of moving and displaying the single orb on the screen, we will run through a similar for:next loop to the one in makeOrbs, using the temp variables to store the values in the parallels arrays as we iterate through them

We need the temp variables because 7800 Basic doesn’t do well trying to use the values in the arrays directly using index notation.

Also, we use m as the iterator set maxOrbs -1 because the first index of maxOrbs is zero.

_gameLoop

 clearscreen

 rem *******

 rem * Update & Draw Orbs

 rem *******

 m = maxOrbs – 1

 for i = 0 to m

    tempX = orbX[i]

    tempY = orbY[i]

    tempAnimFrame = orbAnimFrame[i]

    tempAnimWait = orbAnimWait[i]

    tempXVelocity = orbXVelocity[i]

    tempYVelocity  =orbYVelocity[i]

    tempX = tempX + tempXVelocity

    tempY = tempY + tempYVelocity

    plotsprite orb1 2 tempX tempY tempAnimFrame

    tempAnimWait = tempAnimWait +1

    if tempAnimWait > 1 then  tempAnimFrame = tempAnimFrame + 1 : tempAnimWait = 0

    if tempAnimFrame > 5 then tempAnimFrame = 0

    orbX[i] = tempX

    orbY[i] = tempY

    orbAnimFrame[i] = tempAnimFrame

    orbAnimWait[i] = tempAnimWait

 next

Let’s also delete the randomOrb subroutine.

_randomOrb

 orbX = rand  

 orbY = rand

 if orbX > 151 then orbX = 151

 if orbY > 183 then orbY = 183  

 return

And then comment out the code that calls it in _testCollisions.

_testCollisions

  . . .

  rem gosub _randomOrb

We should now be ready to test the code!
Here is what it looks like running.

Part 7 : Collect 32 Orbs

(lesson4_7.78b)

Next we will let the player capture the orbs.
To do this, we will first create two new variables:  tempCaptured and playerSpeed.

  dim tempCaptured = var15

  dim playerSpeed =var17

In the _initGame subroutine we will set the player;s speed to 2.
Thai way we have the option to increase or decrease speed later instead of it always being a constant 

_initGame

playerSpeed = 2

We will then use it rightaway in the _gameLoop subroutine, by removing the discrete values we had before, and using the variable to update the location of the player when the joystick is pressed.

We also call a new subroutine named _testCollisions so we can have the UAP collect the orbs.

_gameLoop

. . .

 if joy0left  then playerX=playerX – playerSpeed

 if joy0right then playerX=playerX +  playerSpeed

 if joy0up  then playerY=playerY – playerSpeed

 if joy0down then playerY=playerY +  playerSpeed

 gosub _testCollisions

So now we will build the test collisions subroutine.
We will iterate through the array of orbs, very much like how we displayed them on the screen.

We test orbCaptured[[i] to see if the current orb has already been collected.  If so we skip the rest of the code by jumping to _skipCollide.

Next we are ready for the collision check.
We have to be careful because this code checks boxcollision up to 32 times per frame depending on how many orbs are left to collect.  

This will work fine, but if we keep adding more and more checks of this size into text collisions we may need to optimize the further to make sure all can run inside a single frame.

Back in lesson 2 (two years ago, sorry) we talked about the doublebuffer flip 2  command in Atari 7800 Basic that we are using to draw the screen.   This gives us an effective frame rate of 30 fps, but also allows us extra time to complete all of these checks.   

_testCollisions

 m = maxOrbs – 1

 for i = 0 to m

     tempCaptured = orbCaptured[i]

    if tempCaptured = 1 then goto _skipCollide

    tempX = orbX[i]

    tempY = orbY[i]

    if boxcollision(playerX, playerY, 13, 9,  tempX,  tempY, 8, 8) then goto _doCollide

    goto _skipCollide

_doCollide

    score0 = score0 + 10

    orbCaptured[i] = 1

_skipCollide

 next

 return

If we do find a collision, we update the score0 variable with 10 points, and set orbCaptured for the orb to “1” which means it’s true.

Now let’s test this and capture some orbs!!

Part 8: Why Can’t We Get Them All?


(lesson4_8.78b)


So you may notice that not all the orbs display on the screen at the beginning, and some may actually be assigned movement that makes them nearly never appear on the screen.

To help with this, let’s make sure the orbs always start on the visible screen.

We do this by making sure that tempX is always between 0 and 152 and tempY is always between 0 and 184.  We will get random numbers for each, then loop back to a label (_getX and _getY) until we find a number within that range.

makeOrbs

 rem ************************************

 rem * fill up orbs to display

 rem ************************************

 m = maxOrbs – 1

 for i = 0 to m

_getX

    tempX = rand

    if tempX > 152  then goto _getX

_getY    

    tempY = rand

    if tempY > 184 then goto _getY  

    orbX[i] = tempX

    orbY[i] = tempY

Okay, let’s test this one.

Try it a couple times.
You will see that more orbs appear on the visible screen now before they fly off into the ether.

(lesson4_8.78b)

Part 9: Display Portal

(lesson4_9.78b)

So now we will end the level and display the interdimensional portal so the UAP and travel beyond the current ranch to the next “ranch”  when a level is complete.

Here is  the portal we designed way back at the beginning.
We will load the sprites in like this.

 incgraphic images/portal1_top.png 160A 0 1 2 3

 incgraphic images/portal2_top.png 160A 0 1 2 3

 incgraphic images/portal1_bottom.png 160A 0 1 2 3

 incgraphic images/portal2_bottom.png 160A 0 1 2 3

Then we create a new variable named level that will hold the current game level

Now we will define a similar set of variables for the portal that we defined for our single orb (now deleted):  The X, Y, animation frame and animation wait.

We will also define a new variable named “orbsLeft” that will help us keep track of when the level has been completed.

 dim level = var19

 dim portalX =var20

 dim portalY = var21

 dim portalAnimFrame = var22

 dim portalAnimWait = var23

 dim orbsLeft = var24

So now we define the level as 0 and set the colors for the portal into palette 3.

_initGame

. . . 

  level = 0

. . .

  rem portal colors

  P3C1 = $55

  P3C2 = $63

  P3C3 = $60

Next  we will remove the call to gosub makeOrbs from _initGame and move it to a new sub routine named _initLevel.  

This is because we will want to remake the orbs before every level, so there is no need to do it initGame

We increase the level in initLevel because it is set to 0 when we start.
Now we can call this subroutine every time we want to start a level

Then  set orbsLeft to the 32 and an X,Y position for where the portal will be displayed.

_initLevel  

 level = level + 1

 maxOrbs = 32

 orbsLeft = 32

 portalX = 64

 portalY = 80

 gosub makeOrbs

Now we will add the code to display the portal when all the orbs we have collected.
We will test the orbsLeft variable to see if we should display the portal.  If the number is 0, we call a new sub youtube named _displayPortal.
We will also test to see if the player has collided with the portal.  If so, call that new function we created _initLevel to start a new level.

We do not want to change levels if the player touches any one part of the portal.
Insead we add 10 pixels to the x and y location, and then only test a 6 x 6 region inside.  We want this so that the player needs to actually ENTER the portal to go the next level.

_gameLoop

 tempX = portalX + 10

 tempY = portalY + 10

 if orbsLeft = 0 then gosub _displayPortal

 if orbsLeft = 0 && boxcollision(playerX, playerY, 13, 9,  tempX,  tempY, 6, 6)          then goto _initLevel

gosub _testCollisions 

Also in _gameLoop we will add some new code to where we display the score. 
We will add some text for ‘orbs left’.

We will then use the converttobcd function, that converts the HEX byte variable into a decimal number.(0-99) which is good for displaying stuff like percentages.  In this case it will be used to display the number of orbs left.

We put the converted value into the k variable, then display it on the screen.

 plotchars ‘orbs left’ 2 20 0

 k = converttobcd(orbsLeft)

 plotvalue font 1 k 2 60 0

 plotvalue font 1 score0 6 124 0

Next we will add some code to the _testCollisions subroutine.
We will add one line of code here to update the number if orbs left after the player collects one of them:  orbsLeft = orbsLeft – 1

_testCollisions

. . . 

_doCollide

    score0 = score0 + 10

    orbCaptured[i] = 1

    orbsLeft = orbsLeft – 1

Finally, we will create a brand new subroutine called _displayPortal.
This is very similar to other places where we have displayed sprites. 
The difference here is that the portal is 2 separate sprites.

_displayPortal

 tempY = portalY + 16

 plotsprite portal1_top 3 portalX portalY portalAnimFrame

 plotsprite portal1_bottom 3 portalX tempY portalAnimFrame

 portalAnimWait = portalAnimWait +1

 if portalAnimWait > 2 then  portalAnimFrame = portalAnimFrame + 1 : portalAnimWait = 0

 if portalAnimFrame > 1 then portalAnimFrame = 0

 return

Wow, that was a lot.
Let’s test this version and see what happens.
We should see the portal appear and the player should be able to enter it to move to the next level

Part 10: Cleaning Up Again!

(lesson4_10.78b)

Okay, finally, some clean-up at the end of this lesson.

I noticed that some of the label names are confusing.

We need to  rename the subroutines to be different from goto labels.

Let make sure all the goto labels have an  underscore at the beginning _

And all the subroutines no not

_setTitleColors change to  setTitleColors

_titleLoop change to  titleLoop

Make sure the call to titleLoop is updated at the end of that subroutine:

 goto titleLoop

_initGame change to initGame

In the titleLoop we need to update this line:
initGam

 if joy0fire0  || joy0fire1 then goto initGame

_initLevel change to initLevel

Then update this line of code in _gameLoop (which will soon be gameLoop)

if orbsLeft = 0 && boxcollision(playerX, playerY, 13, 9,  tempX,  tempY, 6, 6) then goto initLevel

Also in initLevel change the call to _makeOrbs to makeOrbs

gosub makeOrbs

_gameLoop change to gameLoop_ma

On the last line of gameLoop change this line of code to call the correct subroutine

  goto gameLoop

Change _testCollisions to testCollisions

Then change this line in gameLoop

gosub testCollisions

Change _displayPortal to displayPortal

Then change this line of code in gameLoop that calls displayPortal

if orbsLeft = 0 then gosub displayPortal

This is good chance to practice your skills debugging 7800 Basic,  As will probably not get all of this right the first time Truthfully, it might just be easier for you to pull the lesson4_10.78b file from the GitHub repo and start there

Now let’s add a couple more little things just to finish-up.

First let’s add random values to the orbAnimFrame (from 0 to 5) so that the orbs will display with a different start frame, and will not look all uniform on the screen.

The last lines in the for:next loop in the  makeOrbs subroutine should look like this now:

     r = rand

    if r < 255  then orbAnimFrame[i] = 0

    if r < 213   then orbAnimFrame[i] = 1

    if r < 170   then orbAnimFrame[i] = 2

    if r < 127   then orbAnimFrame[i] = 3

    if r < 84   then orbAnimFrame[i] = 4

    if r < 42   then orbAnimFrame[i] = 5

    orbAnimWait[i] = 0

    orbCaptured[i] = 0

Finally,. Let’s limit the player’s UAP to so it stays on the visible screen:

Add the following for lines of code (ignore the first one, it’s just there for illustration) right under the place you test the joystick in the gameLoop.

 if joy0down then playerY=playerY +  playerSpeed

 if playerX > 144 && playerX < 160 then playerX = 144 ; went off right

 if playerX <= 255 && playerX > 144 then playerX = 0   ;went off left

 if playerY > 183 && playerY < 199 then playerY = 183  ; went off bottom

 if playerY <= 255 && playerY > 239 then playerY = 0   ; went off top

Now test it!

Wow, that was a lot this time, but I think after a 2 year break, you deserved a bit more meat for this lesson.

Next time we turn this UAP sighting into a full-on, battle in the sky!!

And there you go, we MADE A THING!

See lessons 1-3 here:
Atari 7800 Basic Lessons 1-3 – Generation Atari

See the GithubRepo Here:
makeathing/Atari7800/Atari7800Basic/Tutorial at main · intotheverticalblank/makeathing · GitHub

Atari 7800 Basic Guide:

https://www.randomterrain.com/7800basic.html

Leave a comment