by Chris Roddy
Let me preface this with some warnings:
The way I did it is I set up one program which coordinates the four directions the ball can move and calls the appropriate subroutine. That looks like this:
Repeat U=0 ' Loop until a sub returns 0 for U, indicating the end of a If U=1 ' level or no more lives prgmBONK1 If U=2 ' Subroutine calls prgmBONK2 If U=3 prgmBONK3 If U=4 prgmBONK4 If Z=0 ' If lives=0 then they lost the game Then 0\->\W prgmBONKZ ' Run the endgame sub End End EndWhere U is the quadrant the ball moves toward assuming it's at 0,0. (Huh?) It just contains the direction of the ball's motion. Each sub sets the new direction upon collision with a wall (which at this point can be determined by X and Y values and not by collision tests, which I will cover shortly.)
Each BONKx subroutine is nearly the same thing, except oriented in a different direction of motion. This takes up more memory than a more dynamic main engine, but it is much faster. By "hardwiring" the ball motion routines and eliminating slooooow if/thens, you speed up the game immensely.
Another thing I'll add is this: Move your ball two pixels at a time. I did that and it doubled the speed. No one really notices anyways.
[Please Pause Your VCR And Complete Step 1]
Now that you've got a pixel bouncing around the screen, debug it and
get ready for...
II. Blocks
Take a break from the hard stuff for now and let's look at array->screen
translations. What that refers to is the converting of array or list
data into squares on the screen. The way I did it was rather stupid;
I set up lists and scrolled through them like GWBASIC "data" statements.
A better technique is to nest two For(...End loops (one for column, the other for row) and have it do stuff based on the value of [A](Y,X... for example, draw a box, a dot, or some stuff inside the box. [B], which is the array Bonk uses contains only four different values: 0 for empty, 1 for an open box, 2 for a double and 3 for a triple block. It subtracts from these each time a block is hit. The number indicates how many more times the block must be hit to disappear.
The quickest way I've found to finish a level is this: Set up a variable which holds the number of blocks left on the screen. Build it up when you load the data and subtract from it as the blocks are broken. When it reaches 0, the level is completed.
Now that your program draws blocks:
III. Collision Tests
This is the most critical part of the entire program. If you screw up here,
the game will be awful. Good collision tests (that is, the code which
tests whether the ball is running into a wall, the paddle, or a block) can
make or break your game. If your ball is sliding between blocks and
bouncing wrong, it'll look terrible.
Collision tests with walls are easy. Just test the X or Y coordinate of the ball and change the direction accordingly.
Collision tests with the paddle are fairly easy. Just test the Y coord, and use a compound inequality (though you have to break it up into two for use with If) to determine if they caught the ball.
Collision tests with blocks are the reason I gave up on this three times before forcing myself to finish. A collision test with a block does three things:
There are two approaches to this, which I call "ball-position array cell approximation" and "pixel-test interperetation". Both of these are fairly easy to understand and not too herculan to implement.
The first technique takes the position of the ball and translates it (by using int( and other things) into a cell position in the block array. Based upon its direction and position, the program does different things to the screen and to the array. This is great if you want to put forty-three if/thens in your main game engine. You don't want to do that on a machine with a 6Mhz Z80 processor and a slooow BASIC interpereter. I believe that Bill Nagel's original Turbo Breakout used this techinique, but I may be wrong. Keep in mind that that was written in ASM. Speed like that with this technique is not possible in TB, IMHO.
Instead, use pixel-test interperetation. Test the pixel that the ball will occupy in its next move and decide what it is: is it part of a block, paddle, or wall? Then erase the block, update the array and bounce on your merry way. This is another reason to use Pxl- instead of Pt-. There is no "Pt-Test(" statement and you don't want to do that much coordinate translation footwork in your main game engine. Frank Force's TI-82 game "Breakout II" used this technique and it worked very well.
Here's the code for BONK1, one of the subs that did all of this in Bonk:
Repeat U\!=\1 ' Loop until we bounce Pxl-On(Y,X ' Draw the ball getKey ' See if we have to move the paddle If Ans prgmBONKP ' Run the paddle motion sub If pxl-Test(Y,X+1 ' Something to the right?... Then prgmBONKR ' See what it is and act accordingly Return End If pxl-Test(Y-2,X ' Something above the ball? ... Then prgmBONKU ' Act on it Return End If pxl-Test(Y-2,X+2 ' Diagonal?... Then prgmBONKD1 ' Do something about it Return End X+2\->\X ' Update the ball position Y-2\->\Y Pxl-Off(Y+2,X-2 ' Erase the ball End Return(Note that the ball is on for the optimum amount of time, and that while the calculations are occurring it stays lit. This avoids flickering.)
Enjoy...
All material on this page Copyright © 1997 by Chris Roddy. All Rights Reserved.