Copyright © 2017 by Víctor Parada
This is a little game for the 2017 NOMAM's BASIC 10-liners Contest. This program fits in the PUR-80 category, and it was written using TurboBASIC XL 1.5 for the 8-bits ATARI XL/XE. Development started on 2017-02-04, and it took 2+2 days. The final version's date is 2017-02-26.
UPDATE: It obtained the 6th place of 26 entries in the category.
With a paddle controller, try to keep the ball within the screen as much as you can.
Connect your paddles in port 1 and press the trigger on the working paddle to start. | |
The ball will start moving slowly to one of the corners. Use this time to get used to your surrounding pads. All of them move at the same time, half of them in the opposite direction. | |
When the ball hits a pad, it will bounce with a new random speed and angle, and the bounce's counter will be increased. | |
Follow the ball or try to predict where it will go and put a pad there. | |
If the ball goes out of the screen, the game is over. Your final score is the number of hits you did. |
I like pong style games. I used to play Video Olympics, Warlords and Breakout in my old 2600. All of them have one thing in common: paddle controllers. Once, I thought about a self pong game, where one could play against himself. Yes, I was borred and found somehow difficult to handle two paddle controllers at the same time. If one paddle controlled both sides of a pong game, instead of left vs right hand, the points should be the number of bounces. It's name could be Selfpong.
With that old idea in my mind, I figured out a program for NOMAM contest. In the process, another idea came into my mind: what if instead of walls, I also add pads in the top and the bottom of the screen? Now, it could be named Quadrapong or something like that.
But I immediatelly noticed a problem: If all pads moves clockwise or counterclockwise at the same time, the corners would be weak points. The solution would be simple: to move horizontal and vertical pads to the corner at the same time. That introduced another degree of difficulty or challenge, it could be like rub the tummy and pat the head at the same time.
Then I thought about some other challenges for the game, like some items that randomly appear in the playfield and change the ball direction or speed, just to let the ball movement be less predictable and increase the difficulty as the time goes. Another improvement could be multiballs. What a mess!
It was time to start a prototype. I decided to program using TurboBASIC XL with P/M graphics and the collision detection registers. I also decided that single line resolution would be used, in order to add details to the ball. But needed 4 pads and a ball for the most simple prototype, so I had to decide which players and which missiles would be used for each element.
The first working prototype was done with P0 as the ball, P1 and P2 as the side pads, and 2 missiles as the top and bottom pads, but even in quad width, I found they were two small, so I used two missiles for each pad. The following is a screenshot with trace data in it:
1st prototype of the game
2nd fine-tunned prototype
As it could be seen, top and bottom pads have two colors, and that is not good, because it would limit the screen colors. But the game was playable and somehow difficult. It was during the tests of the gameplay when the final name of the game was taken.
I noticed some issues with collisions and that would make a bit harder to program the playfiled items. I felt frustrated on that and almost quit this project, but then I noticed that it has few shorth lines. If I add sounds and score, it might fit the PUR-80 category of NOMAM contest.
Well... I did it. But I changed some things. First, to solve the colors issue, I changed which player and missile was assigned for each pad, and enabling the fifth player instead of missiles, I got another color: 4 for normal players and 1 for the missiles. Then reassigned the players: the new order is ball, upper pad, lower and right, and one missile for the left pad. I also reduced the playfield some pixels.
This game was developed using Altirra in PAL video mode, but edited externally using a text editor and a propietary perl script that packs the BASIC code to be ENTERed into TurboBASIC XL interpreter. It was tested on both PAL and NTSC real 800XL using a paddle controller. It took me a couple of hours to pack this program in 800 bytes without obfuscating it more than it actually is. Enjoy it!
Get the DONTGO.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. A pair of paddles in port 1 are required, but only one is used.
NOTE: If you try it using Altirra, in the "Input" menu you must select "Mouse -> Paddle A" for port 1. Once the mouse is captured by Altirra when you click over the emulator's window if it is in autocapture mode, or when you press F12, you can click the left button as the trigger to start the game, and the pads are moved when you move the mouse to the left and to the right. Press the middle button of the mouse or F12 to force Altirra to release the mouse device.
The abbreviated BASIC code is the following:
The full and expanded BASIC listing is:
graphics 8 |
Cleans top 8K of RAM. P/M data will be put there. |
graphics 17 |
Select full screen graphics mode 1. Only the bottom line would be used for the score. Also used for the title screen. |
m=adr("{binary data}") |
Lots of data:
1-4 (4 bytes): block shape of the top and bottom pads. 5-9 (5 bytes): width of each player and missile. 10-17 (8 bytes): color of each P/M and playfield. 18-26 (9 bytes): shape of the ball. 27-35 (9 bytes): text for the title screen. |
move m+9,704,8 |
Sets the color palette. |
poke 559,62 |
SDMCTL=2+32+12+16: This is a standard playfield with DMA access enabled for players and missiles, in 1 line resolution. |
dim d(1) d(0)=1 d(1)=-1 |
Defines an array with direction constants for formulas. 1 means right or down, -1 is for left and up. |
poke $D407,$A0 |
PMBASE=$A000: This reserves the following 256-byte blocks for player missiles (single line resolution):
$A300-$A3FF: Missiles/5th-player shape. $A400-$A4FF: Player 0 shape. $A500-$A5FF: Player 1 shape. $A600-$A6FF: Player 2 shape. $A700-$A7FF: Player 3 shape. |
poke $D01D,3 |
GRACTL=1+2: Turns on players and missiles. |
poke $A8F0,3 move $A8F0,$A8F1,31 |
Top and bottom pads are moved horizontally by a single POKE, but a memory block of data must be moved to shape the left and right pads. This lines defines the source data for that shape: it is a 512-bytes block located at $A800-$A9FF with only 32 bytes set in the middle of it. |
move m,$A520,4 move m,$A6D0,4 |
Draws the top (P1) and bottom (P2) pads inside their respective P/M block. They have a fixed vertical position. |
move m+17,$AAF0,9 |
Just like the side pads, the vertical position of the ball requires the move of a block that includes the shape. This source 512-bytes block is located at $AA00-$ABFF with the ball in the middle. |
dpoke $D003,$30C8 |
Sets the fixed horizontal position of the side pads. |
move m+4,$D008,5 |
Sets the width of each P/M. |
poke 623,17 |
GPRIOR=1+16: Sets the standard player priority on overlaps and enables the 5th player color for the missiles. |
move m+26,$BE4E,9 |
Puts the text in the center of the title screen. This program does not use the DPEEK(88) function to get the memory address of the screen... it just knows where it should be in a standard XL/XE computer with TurboBASIC XL and without a cartridge in the slot. |
while 1 |
Main loop... |
while ptrig(0) wend |
Waits for the paddle's trigger to be pressed. |
? #6;"{cls}" |
Clears the screen. |
s=0 |
Resets the score. |
v=d(rand(2)) w=d(rand(2)) |
Sets a slow initial random direction of the ball. |
x=130 y=112 |
Sets the initial position of the ball in the playfield. |
repeat |
Game loop... |
poke 77,0 |
Disables ATRACT mode if currently enabled. |
x=x+v y=y+w |
Calculates the new position of the ball. |
if t s=s+t t=0 position 9,23 ? #6;s endif |
If the ball touched the pads in last movement, increase the score and print the new value in the screen. |
p=paddle(0) if p<50 p=50 endif if p>190 p=190 endif |
Calculates the position of the pads based on the paddle value, and limit it between a valid range. |
move $A8FE-p,$A300,256 |
Redraws the left pad by moving a 256-bytes data block over the missiles area. The source is calculated in a way that a higher value of the pad points to a far starting point of the pad bitmap, placing it lower in the screen. The blank area of the block will clean the old position of the pad if it was located elsewhere. |
move $A80E+p,$A700,256 |
Redraws the right pad in a similar way using the same source, but a higher paddle value will place the pad upper in the screen. |
sound |
Turns off sounds, if any was enabled during the last loop. |
poke $D001,p |
Place the top pad horizontally based on the current paddle value. |
poke $D002,240-p |
Place the top pad horizontally based on the current paddle value, but in the opposite direction. |
pause 0 |
A small pause to minimize flickering when drawing the ball. |
poke $D000,x |
Sets the horizontal position of the ball. |
move $AB00-y,$A400,256 |
Sets the vertical position of the ball, using the same technique as the vertical pads for simplicity. |
poke $D01E,0 pause 1 |
HITCLR: poking any value to this register cleans the collision registers. Then a pause for next VBLANK is needed to be sure that collisions are properly detected. |
if peek($D008) or peek($D00C)&8 |
Check for players 0's missiles and players collision registers. Only the bit regarding to P3 is needed. |
v=(rand(4)+2)*d(x>128) w=(rand(4)+2)*sgn(w) |
If there was a hit on the left or right pad, a new horizontal direction is set and new random speed is selected for both axis. |
sound 0,30,8,8 |
Enables a horizontal bump sound. |
t=t+1 endif |
Increases the bumps counter. |
if peek($D00C)&6 |
Check for player 0's players collision register. Only P1 and P2 bits are necesary. |
sound 1,40,8,8 |
Enables a vertical bump sound. |
t=t+1 |
Increases the bumps counter. |
w=(rand(4)+2)*d(y>128) v=(rand(4)+2)*sgn(v) endif |
If there was a hit on the top or bottom pad, a new vertical direction is set and new random speed is selected for both axis. |
until x<9 or x>246 or y<10 or y>262 |
The game ends when the ball goes out of bounds. |
sound 0,98,12,15 pause 30 sound |
Plays a short buzzer. |
wend |
Returns to the main loop. |
Return to my 10-liners page.
© 2017 by Víctor Parada - 2017-02-26 (updated: 2020-08-15)