Copyright © 2024 by Víctor Parada
This is a little game for the 2024 NOMAM's BASIC 10-liners Contest. This program fits in the "stock" PUR-80 category, and it was written in Atari BASIC for the 8-bits ATARI XL/XE. Development started on 2023-02-24, and it took 2+2+1 days. The final version's date is 2024-02-28.
Jump over the cacti during your run avoiding Coyote's rockets that follow you.
You are the Road Runner, running in through a highway in the desert. | |
Use the joystick to move to the left and to the right. Use the button to jump. | |
When you face a cactus, jump over it. | |
Do not jump if there is a rocket above you. | |
Each time a cactus is left behind, you score a point. As time goes, rockets will be faster. | |
The game is over when a rocket or a cactus hit you. Press the button to try again. |
While I was searching for a simple game concept for the PUR-80 category, Eric Carr submitted a beautiful gem for the same category: Magic Carpet Ride. He used the same programming techiques I used in previous games and I thought if I could also combine those techniques to create another game concept.
Some days ago, someone asked in AA forum why there is no Atari 8-bits port of Road Runner, an arcade game published by Atari in 1986, and ported to many other computers and consoles. I never knew about that game and wanted to see how it was. I immediately realized that it could be simplified for a new game using similar programming techniques.
Screenshot from the Atari arcade.
Screenshot from the Commodore 64 port.
Far from usual, I started by creating the bitmap for the Road Runner simplifying the game sprite I took from the screenshot. I started with Paint and then transfered it to Matosimi's Atari FontMaker, but then I did many iterations to get a sprite that I liked.
Pixelart for the sprite (with animation).
Then, I had to select other elements for the game: the "enemies". At first I thought about rocks or cars to avoid, or some dishes with seed to collect while avoiding those other obstacles, either with a vertical movement or an isometric view, but looking some images of the cartoon gave me the final elements: an ACME rocket and a cactus. One will be going from the front and the other from the back of the player, and the gameplay would be to avoid both elements at the same time, in two levels: the cactus should be jumped over and the rocket would restrict where to jump. Timming and coordination should be required.
My sprite was designed to be used in ANTIC 5 graphics mode (BASIC GR.13 mode). It consisted in six 4x8 pixels tiles, 8x24 pixels in total. Then I had to create a prototype that could move the sprite in the screen. As Atari BASIC does not have memory management other than a single POKE statement and its corresponding PEEK function, I decided to use string arrays to manage averything: Player/Missile (P/M) graphics, charset (bitmaps) and screen data. After a while, I had a simple proto with the animated Road Runner, and the cactus and the rocket P/M graphics moving to their corresponding direction. Later, I programmed the code to allow the sprite to be moved forward and backward, and then I added a jump feature.
First proto with the elements.
Playable proto, with score and collision detection.
It was time to pack the code and make it fit in 10 lines. The game logic was using 6 lines, and the playfield setup was also using 6 lines, but in total, the packed source code had less than 800 bytes. The problem was to reorganize the code to better distribute it in the lines. A sequence of POKEs was converted to a single POKE within a loop, reading the address and the value from DATA. That saved a bunch of bytes and reduced the code to 11 lines. More was needed, so I changed the READ-DATA approach to a string with a sequence of addresses and data bytes. The FOR-NEXT loop was larger, but the data was shorter. In total, I saved more bytes, but I still had 11 lines (6 for the set up and 5 for the code). I gave up and moved one statement from the setup to the game loop and problem solved: that statement continuously put a constant value in the same place.
I was so excited with the animation that I completely forgot sound effects. The lines for the logic code had enough space to add two FXs: a beep for the checkpoints (score) and a crash sound when hit. I also added a flash of the playfield to enhance the fact that game is over. In two days the game was ready...
The following two days, I started to write the docs (this page) and to add comments to the source code. In this stage I usually find bugs or a better way to improve the performance or avoid glitches. In this case, I used the extra bytes in the setup routine to change the text mode of the score, almost removed a small delay between the movement of the players and the colision detection. I cancelled the posibility to move to the left and to the right while jumping to make it harder. I also fine-tuned the increase of difficulty and changed the jump sequence to be more fluent: it previously took two frames each step of the jump, increasing the posibility to be catched by a rocket, and now the stay on the top is only one frame shorter, but the game looks an feels better. Finally, I tweaked the color palette...
As this game belongs to the "endless runner" type, I called it "Endless Road Runner", and the following image that I found in the net has all the game elements...
Road Runner and Wile E. Coyote (art by @imptasticles)
Just after I submitted the game to the contest and published the video, I added another FX: jumping sound. This improved the game, but the cost was to remove the flashing background at the game over. I also shrinked a bit the playfield in order to center the action. When I uploaded the V2 video, the firstone had 31 views, 3 likes and 1 comment in 7 hours. I hope that the new one will have better statistics ;-)
DISCLAIMER: Neither Looney Tunes nor Merrie Melodies staff have disapproved the use of their character in this game.
Get the ROADRUN.ATR file and set it as drive 1 in a real Atari (or emulator). Turn on the computer and the game should start after loading. Don't press OPTION key as internal BASIC is required. A joystick in port 1 is also required.
NOTE: This is a PAL game. To run in NTSC computers, press [RESET] key and type:
The abbreviated BASIC code is the following:
The full and expanded BASIC listing is:
|
Endless Road Runner (c) 2024 Víctor Parada |
0 |
LINE 0: INITIALIZATION |
dim a$(76) a=adr(a$) |
a$: Initialization data |
dim f$(24500-a),b$(3000) |
f$: Unused, just a filler to align next var to page 96 ($60). b$: String-managed memory - $6000-$63FF Charset - $6000 PMBASE - $6200 P0 - $6280 P1 - $6400-$67FF Screen |
b$="{binary data}" b$(3000)=b$ b$(2)=b$ |
Clears charset, P/M area and screen |
graphics 13 |
Set screen to graphics mode 13 (ANTIC 5) with text window |
t=1 |
Animation tile toggle |
a$="{binary data}" |
Initialization data table 8 bytes: Jump sequence (screen offset) 4 byes: Tiles for leg animation 19*3-1 bytes: Address+Data to POKE at initialization: - HPOSP0=0: Takes P0 out of the screen - HPOSP1=0: Takes P1 out of the screen - (DLIST)+4=$6400: Change screen data area to our string - (DLIST)+6=$10: Remove 14 scan lines in the top to center the playfield - (DLIST)+20=6: Change bottom line to ANTIC 6 (GR.1) - COLOR4=$16: Background color to brown - COLOR2=$0C: Street color to light gray - PMBASE=$60: P/M data at $6000 - SDMCTL=2+32+8+4: Double line resolution P/M in standard playfield - GRACTL=2: Enable players - SIZEP1=3: Set rocket to quadruple width - CHBAS=$60: Charset at $6000 (same as PMBASE) - CRSINH=1: Disable the cursor - COLOR0=$EC: Color for bird's beak and legs (orange) - COLOR1=$64: Color for plume and wings (purple) - COLOR3=$9C: Color for body and tail (light blue) - PCOLR0=$B6: Color of the cactus (green) - PCOLR1=$34: Color of the rocket (red/pink) - HITCLR=?: Clear P/M collisions (saved one byte because last byte could be any value) |
for i=12 to 71 step 3 poke peek(a+i)*256+peek(a+i+1),peek(a+i+2) next i |
Process the list of POKEs to set up the playfield |
for i=24704 to 24783 poke i,peek(32768+i) next i |
Copy the digit's bitmaps from ROM to the new charset area |
b$(586)="{binary data}" |
Draw a cactus in P0 |
b$(691)="{binary data}" |
Draw a rocket in P1 |
b$(1302)="{binary data}" |
Draw the top tile of the Road Runner (head and tail) |
|
Variable initialization These variables are set to zero at the start by BASIC c=0: Cactus horizontal position r=0: Rocket horizontal position s=0: Rocket speed p=0: Points x=0: Horizontal position of the player y=0: Vertical position of the player |
v=15 |
Counter for hit FX |
b$(9)="{binary data}" |
Road Runner bitmap |
|
Clears collisions |
5 |
LINE 5: GAME LOOP |
y=y+(strig(0)=0 and y=0)*7-(y>0) |
Activate a jump using the joystick button and update the height of the Road Runner in the following frames |
if r<=s then r=255 |
If the rocket crossed the screen, move it to the right again |
s=int(rnd(0)*(p+9)/5+3) |
Select a random speed, based on the score |
6 |
LINE 6: MOVING THE PLAYER |
j=stick(0) x=x+((j=11)*(x<30)-(j=7)*(x>0))*(y=0) |
Move the player to the left or to the right between bounds, except when it is jumping |
h=peek(53253)+peek(53252)>0 |
Check if the Road Runner hit the rocket or the cactus |
7 |
LINE 7: GAME OVER FX |
sound 0,20,8,v*h |
Disables the sound or plays the hit FX |
sound 1,90,12,y |
Jumping FX |
if h then v=v-(v>0) |
Hit the cactus or rocket? Decrease the FX counter on each frame |
y=0 |
Disables jump sound (if any) |
on strig(0) or v goto 7 |
Iterate until the joystick button is pressed |
run |
Restart |
8 |
LINE 8: REFRESH FRAME |
r=r-s |
Compute the new position of the rocket |
poke 40300,x+peek(a+y) |
Move the tiles to the new position by moving the screen data pointer to the opposite direction |
poke 53249,r |
Move the rocket (P1) horizontally |
poke 53248,c |
Move the cactus (P0) horizontally |
poke 77,0 |
Disable ATRACT mode |
t=-t |
Toggle the leg's animation flag |
b$(1342)="{binary data}" |
Draw the middle tiles for the body of the Road Runner |
9 |
LINE 9: UPDATE SCORE |
b$(1382,1383)=a$(10+t) |
Draw the bottom tiles (animated legs) of the Road Runner |
c=c+6 |
Compute the next horizontal position of the cactus (move to the right) |
on c<220 goto 5 |
Will the cactus still be in screen? Repeat... |
sound 0,9,10,8 |
The cactus crossed the screen to the right. Beep sound for the counter |
c=0 |
Move the cactus to the left |
p=p+1 print "{binary data}",p; |
Increase the score |
goto 5 |
and repeat... |
Return to my 10-liners page.
© 2024 by Víctor Parada - 2024-02-26 (updated: 2024-02-88)