Académique Documents
Professionnel Documents
Culture Documents
Right then!
This is the second part of the game programming tutorials series for Basic4GL. It's pretty much going
to carry on from where part 1 left off, so obviously I advise reading part 1 first. It all fits together!
This tutorial will introduce just one concept: "arrays".
It turns out that arrays, and how to use them effectively gives us enough material for an entire tutorial,
so I wont try to squeeze anything else in (it was hard enough to squeeze it down to its current length,
and it's still pretty long.).
Arrays although simple in concept are actually extremely powerful. They can be used to apply the same
lines of code to different data, which we will put to use to show that the same lines of code that move 1
alien can move 50 of them!
Arrays
An array is a special kind of variable. You remember that a variable is used to store a number or a
string, like in this (fairly meaningless) program:
||
dim count, temperature#dim model$count = 5temperature#
33.44model$
"Plastico 12B"
||
However, instead of just storing 1 number or string, an array can store many numbers or strings.
To illustrate, let's suppose we wanted to store three numbers.
We could simply use 3 different variables:
||
dim n1, n2, n3n1 = 4n2 = 3n3 = n1 + n2
||
But we could also store all three numbers in a single array variable, like this:
||
dim n(3)n(1) = 4n(2) = 3n(3) = n(1) + n(2)
||
This looks pretty similar to the first program. The biggest difference being that there are brackets
around the numbers.
The dim n(3) statement tells the computer that we want an array of 3 elements called n. This is the
array variable name, and follows the same rules as normal variables (for example, we know that the
array stores integers because there is no special symbol after the n. Had we called it n$ as in dim
n$(3), we would have been given an array of three text strings).
So is this better?
Admittedly it's slightly longer and doesn't do anything particularly better. But bear with me, because
there are things we will learn to do with arrays that we can't do with regular variables.
One situation is if we want to store a large number of variables, say 1000. Obviously it would take us a
long time to write out code to "dim" 1000 different variables.
dim n1, n2, n3, n4, n5, n6, n7, n8, n9, n10...!
dim n(1000)
As you can see, we are using them just like normal variables.
numbers(3) = 5
print numbers(3)
print numbers(2)
||
dim numbers(4)numbers(1+1+1) = 5print numbers(3)
||
||
dim numbers(4), ii = 3numbers(i) = 5print numbers(3)
||
numbers(i) = 7
Only we're putting an i = 1 infront of the first one then an i = 2 in front of the next one, then an i = 3,
and so on...
If you remember back to the for..next loop, you may realise that this is exactly the same as saying:
Putting it together
That was quite a bit of theory, and not much about space aliens. It must be about time to put it to use on
something practical.
But before going back to the space alien game though, we're going to start with a simple bouncing ball
program.
This is because we want to demonstrate the inbetween steps for converting a one-object program into a
many-object program, and the space alien game has become rather large. We want something smaller
so we can show each little step without making the tutorial longer than it already is!
1 bouncing ball
Okay, so firstup we need a bouncing ball program with one ball.
Because we're still using text mode, we will simply draw a letter 'o' for the ball. The ball will simply
move diagonally around the screen. Whenever it reaches the edge of the screen it will bounce away.
As before, we need to decide what data the computer needs to store to remember where the ball is, and
keep it moving.
We need to store the ball's current position on the screen. So we will use ballx and bally as the current
column and row.
Now at any one time, the ball will be moving in a direction, so we need to store that too.
We will use two variables called ballxd and ballyd, and will store the horizontal (left and right) and
vertical (up and down) directions of the ball, which we will store as a number. Each time around the
main loop we will update the ball's position like this:
So when ballx is 1, it will be the same as doing a ballx = ballx + 1 and the ball will move to the right.
And when ballx is -1, it will be doing the same as ballx = ballx + -1 (in other words ballx = ballx - 1)
and the ball will move to the left.
Likewise with ballyd. 1 will make the ball move down, and -1 will make it move up.
Here's the first version with 1 ball.
||
dim ballx, ballydim ballxd, ballydballx = rnd () % 38 + 1bally = rnd () % 23 + 1ballxd = 1: ballyd =
1TextMode (TEXT_BUFFERED)SetTextScroll (false)while true ballx = ballx + ballxd bally = bally +
ballyd if ballx <= 0 or ballx >= 39 then ballxd = -ballxd endif if bally <= 0 or bally >= 24 then ballyd =
-ballyd endif cls locate ballx, bally: print "o" DrawText () Sleep (75)wend
||
Most of this should look familiar from the space aliens game. We have declared our variables with dim.
Then we've stored some initial data in them, using the rnd () function and the remainder operator (%)
to generate numbers from 1-38 and 1-23 for the column and row screen position. This makes the ball
start from a random position.
In the main loop, we move the ball as we said we would.
The only tricky bit is the if..then instructions:
detects when the ball has reached the left hand side of the screen (column 0) or the right hand side
(column 39).
If so we reverse the left-right direction with:
ballxd = -ballxd
So if ballxd was 1 (ball moving right), it will be changed to -1 (ball moving left).
And if ballxd was -1 (ball moving left), it will be changed to 1 (ball moving right).
And the ball's up-down direction is handled in the same way.
The rest of the code simply draws the ball on the screen, and delays for 0.075 seconds, to regulate the
speed.
3 bouncing balls
So now we're going to change the program to handle 3 bouncing balls.
As we said before, we're going to do this in stages, so we're not going to jump to the final solution
straight away.
For now we're going to ignore arrays and simply use more variables.
So instead of ballx, we're going to have ballx1, ballx2 and ballx3. And likewise for bally, ballxd and
ballyd all the other variables.
And we're simply going to copy the code that we wrote to move and draw the first ball over to the
second and third.
The code for this one is a little bit repeditive and easy to make mistakes, so you might just want to cut
and paste it rather than type it all in.
||
dim ballx1, bally1dim ballx2, bally2dim ballx3, bally3dim ballxd1, ballyd1dim ballxd2, ballyd2dim
ballxd3, ballyd3ballx1
rnd () % 38 + 1bally1
rnd () % 22 + 1ballxd1
1: ballyd1
1ballx2 = rnd () % 38 + 1bally2 = rnd () % 22 + 1ballxd2 = 1: ballyd2 = 1ballx3 = rnd () % 38 +
1bally3 = rnd () % 22 + 1ballxd3 = 1: ballyd3 = 1TextMode (TEXT_BUFFERED)while true ballx1
ballx1 + ballxd1 bally1
bally1 + ballyd1 if ballx1 <= 0 or ballx1 >= 39 then ballxd1
rnd () % 38 + 1bally(1)
rnd () % 22 + 1ballxd(1)
1: ballyd(1)
1ballx(2)
rnd () % 38 + 1bally(2)
rnd () % 22 + 1ballxd(2)
1: ballyd(2)
1ballx(3)
rnd () % 38 + 1bally(3)
rnd () % 22 + 1ballxd(3)
1: ballyd(3)
1TextMode (TEXT_BUFFERED)while true ballx(1)
i=1
ballx(i) = ballx(i) + ballxd(i)
Where i is a new variable that we are using for the "array index".
Here's the new code:
||
dim ballx(3), bally(3)dim ballxd(3), ballyd(3)dim ii = 1ballx(i)
rnd () % 38 + 1bally(i)
rnd () % 22 + 1ballxd(i)
1: ballyd(i)
1i = 2ballx(i)
rnd () % 38 + 1bally(i)
rnd () % 22 + 1ballxd(i)
1: ballyd(i)
1i = 3ballx(i)
rnd () % 38 + 1bally(i)
rnd () % 22 + 1ballxd(i)
1: ballyd(i)
1TextMode (TEXT_BUFFERED)while true i = 1 ballx(i)
-ballyd(i) endif i
2 ballx(i)
-ballyd(i) endif i
3 ballx(i)
we can write:
const ballCount = 3
Then everytime we want to refer to the number of balls (i.e 3) we will use ballCount instead.
So instead of saying for i =1 to 3, we are instead going to say for i = 1 to ballCount.
Let's see the changed program.
||
const ballCount = 3dim ballx(ballCount), bally(ballCount)dim ballxd(ballCount),
ballyd(ballCount)dim ifor i = 1 to ballCount ballx(i) = rnd () % 38 + 1 bally(i) = rnd () % 22 + 1
ballxd(i) = 1: ballyd(i) = 1nextTextMode (TEXT_BUFFERED)while true for i = 1 to ballCount
ballx(i) = ballx(i) + ballxd(i) bally(i) = bally(i) + ballyd(i) if ballx(i) <= 0 or ballx(i) >= 39 then
ballxd(i) = -ballxd(i) endif if bally(i) <= 0 or bally(i) >= 23 then ballyd(i) = -ballyd(i) endif next cls for
i = 1 to ballCount locate ballx(i), bally(i): print "o" next DrawText () Sleep (75)wend
||
Again, the program works exactly the same way as before. 3 bouncing balls.
So why is this better?
Well consider this.. How difficult would it be to change this program to have 50 balls bouncing around
the screen.
How many lines of code do you think we would have to change?
The answer - believe it or not - is just one line of code!
Try it! Change the top line from:
const ballCount = 3
to read:
const ballCount = 50
More of 'em
We're going to use the same techniques from above to create multiple space aliens.
But first we have to think a little bit about how this will affect the game rules. Because the game rules
for the 1 alien version aren't quite suited for a multiple space alien version.
In the current version, whenever we shoot the alien it reappears on the left side of the screen. But now
we would really prefer them to dissapear and stay gone, so that the player can clear the screen of all
aliens and win the game (or move on to the next level etc).
So the computer also needs to remember which aliens are still on screen, and which aren't, so it knows
which ones to move around and draw.
We'll start by changing the variables declared to arrays. That is we will replace (at the top of the
program):
With :
const alienCount = 10dim score, lives, turretxdim alienx (alienCount), alieny (alienCount),
alienOnScreen (alienCount)dim bulletx, bullety, bulletOnScreen, i
This will stop the program from working for now, but that doesn't matter (we still have some more
changes to make before it is ready).
Notice that we've used a constant for the number of aliens, instead of simply writing 10 everywhere.
This will make it easy to change the number of aliens later (e.g. if we want to make the game easier or
harder.)
We've added the alienOnScreen array to store whether or not each alien is still on the screen.
Next we have to change the code that puts the aliens in their starting position. Now that we have more
than one, we can't have them both start from the same position, so we will use random numbers to set
their starting position.
Replace the lines (near the top):
alienx = 0alieny = 12
With:
This should put the aliens in random start positions (rnd () % 37 makes a random number between 0
and 36, and rnd () % 22 + 1 makes a random number between 1 and 22). We obviously couldn't set
them all to column 0, row 12, as otherwise they would all be drawn over the top of each other, and it
would look like there is only one alien!
We still have a couple of changes to make before the program will compile and run though.
Next we will change the alien movement code.
Find the section of the program that reads:
for i = 1 to alienCount if alienOnScreen (i) then alienx (i) = alienx (i) + 1 if alienx (i) > 37 then alienx
(i) = 0 alieny (i) = rnd () % 22 + 1 endif endif next
Notice that we've used our for..next loop to make sure the instructions get repeated multiple times -
once to move each alien. We've also used an if..then..endif statement to tell the computer to only run
the instructions between then and endif if the alien is on the screen. (There's no reason to move the
alien if it isn't.)
We're almost there. Next we're going to update the code that draws the alien on the screen.
Find this line in the program
for i = 1 to alienCount if alienOnScreen (i) then locate alienx (i), alieny (i): print ">O<" endif next
Again we tell the computer to run the same lines of code once for each alien.
And again we tell the computer only to draw the alien if it's still on the screen.
We've made quite a few changes, and the program still won't run. It's normally a good idea to try and
keep the program working as we make the changes. This means that we can test each of the steps as we
go along, and keeps us from getting disheartened.
So what we're going to do now is completely remove the collision detection code so that we can test the
program! (Don't worry, we will add it back in again very soon.)
So find the section of the program that reads:
if bulletOnScreen and bullety = alieny and bulletx >= alienx and bulletx <= alienx + 2 then color (255,
255, 100) for i = 1 to 10 locate alienx, alieny: print "/" DrawText () Sleep (50) locate alienx, alieny:
print "\\\" DrawText () Sleep (50) next bulletOnScreen = false alienx = 0 alieny = rnd () % 22 + 1
score = score + 100 Sleep (1000) endif
if bulletOnScreen then
Next we tell it to repeat the instructions multiple times, once for each alien.
for i = 1 to alienCount
And then we have the actual check to see if the alien and the bullet are at the same position on the
screen.
if bullety = alieny (i) and bulletx >= alienx (i) and bulletx <= alienx (i) + 2 then
And finally, if it finds an alien at the same position as the bullet, it runs the code to remove the alien
and the bullet from the screen and update the score.
Shooting back
There's still a few things missing from our game, and the most obvious is that the aliens don't shoot
back So let's make them.
As usual we first need to stop and think about how the aliens are going to shoot back, and how that can
be made into specific rules that we can enter into the computer.
The rules will be quite simple.
• The aliens will shoot randomly. Specifically we will give them a one in ten chance of shooting
each time they move.
• There will be up to 10 alien bullets on the screen at one time.
• The bullets will fall down the screen until they reach the bottom, then dissapear.
From this we can see that we will need arrays (because we will have multiple bullets).
We need to store the position of each bullet (we will use x and y array variables) on the screen.
The bullets won't always all be on the screen at once, so we also need to store which ones are on screen
and which aren't.
So we will probably store them something like this:
(I've called them "bombs" because they will fall down the screen, and because I can't be bothered
typing "alienBullet" each time!)
Next we need to make the aliens drop bombs randomly each time they move.
We've said they will have a 1 in 10 chance each time. We can make this work by making picking a
random number from 1 to 10 each time and then checking if it equals 1. If it does we drop the bomb.
In order to drop a bomb, we need to find one that isn't already on the screen. So we need to search
through all the bombs for the first one where bombOnScreen (bombCount) is false. When we find
one, we will place it on the screen where the alien is.
We need something like this (in the move alien loop):
if rnd () % 10 + 1 = 1 then for j = 1 to bombCount if not bombOnScreen (j) then bombOnScreen (j) =
true bombx (j) = alienx (i) + 1 bomby (j) = alieny (i) j = bombCount endif nextendif
We need the new variable j because we are already using i as the alien array index.
You may be wondering about the j = bombCount line at the end, after we have put a bomb on the
screen. This simply tells the computer that we don't want to repeat the instructions in the for..next
anymore (because we've already found our bomb and put it on the screen). Otherwise the computer
would keep on looping through the remaining bombs and putting them all underneath the current alien!
That's not what we want!
The next thing we need is some code to draw the bombs on the screen.
We will put this just after the code that draws the player bullet:
color (175, 175, 175)for i = 1 to bombCount if bombOnScreen (i) then locate bombx (i), bomby (i):
print "O" endifnext
for i = 1 to bombCount if bombOnScreen (i) then bomby (i) = bomby (i) + 1 if bomby (i) > 23 then
bombOnScreen (i) = false endif endifnext
So the bomby (i) = bomby (i) is there to move the bombs down the screen.
The if bomby (i) > 23 then will check if the bomb has fallen off the bottom of the screen, and if so the
bombOnScreen (i) = false will take it off the screen (so it's ready to be dropped again by another
alien).
We can place this code after the code that moves the aliens. Like this:
||
const alienCount = 10const bombCount = 10dim score, lives, turretxdim alienx (alienCount), alieny
(alienCount), alienOnScreen (alienCount)dim bulletx, bullety, bulletOnScreen, i, jdim bombx
(bombCount), bomby (bombCount), bombOnScreen (bombCount)lives = 3turretx = 19for i = 1 to
alienCount alienx(i) = rnd () % 37 alieny(i) = rnd () % 22 + 1 alienOnScreen(i) =
truenextbulletOnScreen = falseTextMode (TEXT_BUFFERED)while true if ScanKeyDown (VK_LEFT)
and turretx > 0 then turretx = turretx - 1 endif if ScanKeyDown (VK_RIGHT) and turretx < 37 then
turretx = turretx + 1 endif for i = 1 to alienCount if alienOnScreen (i) then alienx (i) = alienx (i) + 1 if
alienx (i) > 37 then alienx (i) = 0 alieny (i) = rnd () % 22 + 1 endif if rnd () % 10 + 1 = 1 then for j =
1 to bombCount if not bombOnScreen (j) then bombOnScreen (j) = true bombx (j) = alienx (i) + 1
bomby (j) = alieny (i) j = bombCount endif next endif endif next for i = 1 to bombCount if
bombOnScreen (i) then bomby (i) = bomby (i) + 1 if bomby (i) > 23 then bombOnScreen (i) =
false endif endif next if bulletOnScreen then bullety = bullety - 1 if bullety < 1 then bulletOnScreen =
false endif else if ScanKeyDown (VK_SPACE) then bulletOnScreen = true bullety = 22 bulletx =
turretx + 1 endif endif cls color (255, 255, 255) locate 0, 0: print "Score=" + score locate 30, 0: print
"Lives=" + lives color (255, 50, 50) for i = 1 to alienCount if alienOnScreen (i) then locate alienx (i),
alieny (i): print ">O<" endif next color (150, 150, 150) locate turretx, 23: print "<!>" if
bulletOnScreen then color (255, 255, 50) locate bulletx, bullety: print "!" endif color (175, 175, 175)
for i = 1 to bombCount if bombOnScreen (i) then locate bombx (i), bomby (i): print "O" endif next if
bulletOnScreen then for i = 1 to alienCount if alienOnScreen (i) then if bullety = alieny (i) and bulletx
>= alienx (i) and bulletx <= alienx (i) + 2 then alienOnScreen (i) = false bulletOnScreen = false score
= score + 100 endif endif next endif DrawText () Sleep (75)wend
||
And the last step is to tell the computer how to check whether a bomb has hit the turret, and what to do
if it has.
We want to:
• Display a "turret hit" animation
• Put the turret back in the middle of the screen
• Subtract one from the lives
• If the lives reach zero the game is over, so
• Show the "Game Over" message, and
• End the game.
We also want to remove all the bombs from the screen. This gives the player a chance to react when the
game starts again.
We want to put this after we've drawn the rest of the screen.
So here's the final version.
||
const alienCount = 10const bombCount = 10dim score, lives, turretxdim alienx (alienCount), alieny
(alienCount), alienOnScreen (alienCount)dim bulletx, bullety, bulletOnScreen, i, jdim bombx
(bombCount), bomby (bombCount), bombOnScreen (bombCount)lives = 3turretx = 19for i = 1 to
alienCount alienx(i) = rnd () % 37 alieny(i) = rnd () % 22 + 1 alienOnScreen(i) =
truenextbulletOnScreen = falseTextMode (TEXT_BUFFERED)while true if ScanKeyDown (VK_LEFT)
and turretx > 0 then turretx = turretx - 1 endif if ScanKeyDown (VK_RIGHT) and turretx < 37 then
turretx = turretx + 1 endif for i = 1 to alienCount if alienOnScreen (i) then alienx (i) = alienx (i) + 1 if
alienx (i) > 37 then alienx (i) = 0 alieny (i) = rnd () % 22 + 1 endif if rnd () % 10 + 1 = 1 then for j =
1 to bombCount if not bombOnScreen (j) then bombOnScreen (j) = true bombx (j) = alienx (i) + 1
bomby (j) = alieny (i) j = bombCount endif next endif endif next for i = 1 to bombCount if
bombOnScreen (i) then bomby (i) = bomby (i) + 1 if bomby (i) > 23 then bombOnScreen (i) = false
endif endif next if bulletOnScreen then bullety = bullety - 1 if bullety < 1 then bulletOnScreen = false
endif else if ScanKeyDown (VK_SPACE) then bulletOnScreen = true bullety = 22 bulletx = turretx + 1
endif endif cls color (255, 255, 255) locate 0, 0: print "Score=" + score locate 30, 0: print "Lives=" +
lives color (255, 50, 50) for i = 1 to alienCount if alienOnScreen (i) then locate alienx (i), alieny (i):
print ">O<" endif next color (150, 150, 150) locate turretx, 23: print "<!>" if bulletOnScreen then
color (255, 255, 50) locate bulletx, bullety: print "!" endif color (175, 175, 175) for i = 1 to bombCount
if bombOnScreen (i) then locate bombx (i), bomby (i): print "O" endif next if bulletOnScreen then for i
= 1 to alienCount if alienOnScreen (i) then if bullety = alieny (i) and bulletx >= alienx (i) and bulletx
<= alienx (i) + 2 then alienOnScreen (i) = false bulletOnScreen = false score = score + 100 endif
endif next endif for i = 1 to bombCount if bombOnScreen (i) and bomby (i) = 23 and bombx (i) >=
turretx and bombx (i) <= turretx + 2 then color (255, 255, 0) for j = 1 to 10 locate turretx, 23:
print "\\\" DrawText () Sleep (75) locate turretx, 23: print "/" DrawText () Sleep (75) next turretx
= 19 lives = lives - 1 if lives = 0 then color (255, 255, 255) locate 15, 12: print "Game Over!"
DrawText () end endif for j = 1 to bombCount bombOnScreen (j) = false next endif next DrawText
() Sleep (75)wend