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!
The challenge is thus:
Take the simple space alien game from the previous tutorial
and extend it to handle multiple space aliens.
For completeness, we might as well make them shoot back too.
---> 
So...
...How would we approach this?
Based on what we've learned so far, we might consider doing this:
This would give us a complete working set for a second space alien.
This would work fine. Infact there's nothing
wrong with this approach, so long as you have a small number of
space aliens. But if we wanted say 50 aliens, we would have to do
a lot of cutting and pasting and the program would get very long
very quickly.
Also if we later wanted to change the alien code (which we will
later when we make them shoot back) we would have to make the
same change 50 times!
So we're going to take another approach, which (surprise, surprise) involves introducing our new concept, called "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 = 5 temperature# = 33.44 model$ = "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, n3 n1 = 4 n2 = 3 n3 = n1 + n2
But we could also store all three numbers in a single array variable, like this:
dim n(3) n(1) = 4 n(2) = 3 n(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 ...!
But with an array we just do this:
dim n(1000)
And there are other advantages which we will see soon.
Each number (or text string) that is stored in an array is
called an "array element". Each element
behaves like a regular variable. That is, we can read or write to
it, use it in expressions, as function parameters or whatever.
We tell the computer which element we want to access by
putting the number in brackets after the array variable name. So
in the previous examples, n(2) accesses the
seond element of the array.
Here's some more examples of using array elements.
dim name$(3), numbers(4) name$(1) = "Tom" name$(2) = "Dick" name$(3) = "Harry" numbers(1) = 3 numbers(2) = numbers(1) numbers(3) = numbers(1) + numbers(2) * 2 numbers(4) = sqrt (numbers (3))
As you can see, we are using them just like normal variables.

The number inside the brackets is called the "array index".
This is the number used to 'lookup' the variable in the array.
You can think of this like a mailbox number. It tells the postman
where the letter is supposed to go.
So for an instruction like:
numbers(3) = 5
We're delivering the number 5 to mailbox
number 3.
We could then look inside mailbox number 3 like
this:
print numbers(3)
And we would find the number 5 which we just
delivered there.
Of course if we used a different array index like 2:
print numbers(2)
We wouldn't find our number 5! We've looked
in the wrong mailbox.
(We would infact find a number 0 there, because that is the
default for integer variables if we haven't changed them to
anything else yet.)
We put a 3 in the brackets to specify array
index 3.
But what if we had used something like 1+1+1 instead?
dim numbers(4) numbers(1+1+1) = 5 print numbers(3)
Would this compile?
Would it have the same effect?
The answer is: yes, it does exactly the same thing. Type it in an run it, and you'll see that it does indeed print a 5 on the screen.
The reason this works is that the array index doesn't have to be just a single number. It will also accept any expression that sums up to a single number.
So we could have used 2 + 1 or 7 - 4 or sqrt (9) all to access
mailbox number 3.
The computer is quite happy to calculate the result of this sum
and go to the appropriate "mailbox".
(Unlike the postal service who turn their nose up at any address
that requires long division... Don't ask...)
Here's another way to access the 3rd element (mailbox) of the numbers array:
dim numbers(4), i i = 3 numbers(i) = 5 print numbers(3)
This is actually a very powerful technique!
What we've done is declared a variable i, and
then stored the number 3 in it.
Then we've used i as the array index!
Remember that we can use any expression we want to
calculate the array index number, and that includes
other variables like i.
Again the computer calculates the expression, and sees that it
comes out as 3. So off to index 3 it
goes and stores in the number 5.
Right! Now we can bring it all together and show exactly why
arrays are very powerful for dealing with large amounts of data
(like space alien positions :).
The technique involves using a for..next loop,
and combining it with the using-a-variable-for-the-array-index we
just saw above.
Now that sentence probably sounded like Mongolian Swahili to you,
so we'll illustrate with another example:
Let's say we have an array of 10 numbers, and we want to set all the elements to the number 7. (Think of it like delivering a copy of 7 to all the mailboxes in the street).
One way would be to do this:
dim numbers(10) numbers(1) = 7 numbers(2) = 7 numbers(3) = 7 numbers(4) = 7 numbers(5) = 7 numbers(6) = 7 numbers(7) = 7 numbers(8) = 7 numbers(9) = 7 numbers(10) = 7 |
That works fine.
Another way would be to do this:
dim numbers(10), i i = 1 numbers(i) = 7 i = 2 numbers(i) = 7 i = 3 numbers(i) = 7 i = 4 numbers(i) = 7 i = 5 numbers(i) = 7 i = 6 numbers(i) = 7 i = 7 numbers(i) = 7 i = 8 numbers(i) = 7 i = 9 numbers(i) = 7 i = 10 numbers(i) = 7 |
This works fine too. But it's almost twice as long.
But! Here's the trick!
Notice that we are simply running the same instruction ten times:
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:
for i = 1 to 10
numbers (i) = 7
next
(Or here's the full program:)
dim numbers(10), i
for i = 1 to 10
numbers(i) = 7
next
|
Now this does everything we needed it to do, and it's quite a bit shorter than the first program.
And it has other advantages.
Say you wanted to store an 8 in each array element (mailbox), it
would be very easy to change the program to do this.
Or, if you decided you wanted to have 100 array elements (or
1000), it's still very easy to update the program to do this.
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!
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:
ballx = ballx + ballxd bally = bally + ballyd
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, bally
dim ballxd, ballyd
ballx = rnd () % 38 + 1
bally = rnd () % 23 + 1
ballxd = 1: ballyd = 1
TextMode (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:
if ballx <= 0 or ballx >= 39 then
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.
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, bally1
dim ballx2, bally2
dim ballx3, bally3
dim ballxd1, ballyd1
dim ballxd2, ballyd2
dim ballxd3, ballyd3
ballx1 = rnd () % 38 + 1
bally1 = rnd () % 22 + 1
ballxd1 = 1: ballyd1 = 1
ballx2 = rnd () % 38 + 1
bally2 = rnd () % 22 + 1
ballxd2 = 1: ballyd2 = 1
ballx3 = rnd () % 38 + 1
bally3 = rnd () % 22 + 1
ballxd3 = 1: ballyd3 = 1
TextMode (TEXT_BUFFERED)
while true
ballx1 = ballx1 + ballxd1
bally1 = bally1 + ballyd1
if ballx1 <= 0 or ballx1 >= 39 then
ballxd1 = -ballxd1
endif
if bally1 <= 0 or bally1 >= 23 then
ballyd1 = -ballyd1
endif
ballx2 = ballx2 + ballxd2
bally2 = bally2 + ballyd2
if ballx2 <= 0 or ballx2 >= 39 then
ballxd2 = -ballxd2
endif
if bally2 <= 0 or bally2 >= 23 then
ballyd2 = -ballyd2
endif
ballx3 = ballx3 + ballxd3
bally3 = bally3 + ballyd3
if ballx3 <= 0 or ballx3 >= 39 then
ballxd3 = -ballxd3
endif
if bally3 <= 0 or bally3 >= 23 then
ballyd3 = -ballyd3
endif
cls
locate ballx1, bally1: print "o"
locate ballx2, bally2: print "o"
locate ballx3, bally3: print "o"
DrawText ()
Sleep (75)
wend
|
As before I've used bold red
to highlight the new bits.
So the program is almost 3 times as long now, but as you can see
when you run it, it does work fine. There are 3 balls bouncing
around the screen like they were told.
Okay, from now on, each version is going to do the same thing,
just in slightly different ways each time!
So please try not to be discouraged when you don't see any
improvement. You will see in the end that it was worth it,
especially when we see how easy it is to change the final version
to bounce 50 balls around the screen.
So let's soldier on and replace these variables with arrays.
Still gradual steps remember!
dim ballx(3), bally(3)
dim ballxd(3), ballyd(3)
ballx(1) = rnd () % 38 + 1
bally(1) = rnd () % 22 + 1
ballxd(1) = 1: ballyd(1) = 1
ballx(2) = rnd () % 38 + 1
bally(2) = rnd () % 22 + 1
ballxd(2) = 1: ballyd(2) = 1
ballx(3) = rnd () % 38 + 1
bally(3) = rnd () % 22 + 1
ballxd(3) = 1: ballyd(3) = 1
TextMode (TEXT_BUFFERED)
while true
ballx(1) = ballx(1) + ballxd(1)
bally(1) = bally(1) + ballyd(1)
if ballx(1) <= 0 or ballx(1) >= 39 then
ballxd(1) = -ballxd(1)
endif
if bally(1) <= 0 or bally(1) >= 23 then
ballyd(1) = -ballyd(1)
endif
ballx(2) = ballx(2) + ballxd(2)
bally(2) = bally(2) + ballyd(2)
if ballx(2) <= 0 or ballx(2) >= 39 then
ballxd(2) = -ballxd(2)
endif
if bally(2) <= 0 or bally(2) >= 23 then
ballyd(2) = -ballyd(2)
endif
ballx(3) = ballx(3) + ballxd(3)
bally(3) = bally(3) + ballyd(3)
if ballx(3) <= 0 or ballx(3) >= 39 then
ballxd(3) = -ballxd(3)
endif
if bally(3) <= 0 or bally(3) >= 23 then
ballyd(3) = -ballyd(3)
endif
cls
locate ballx(1), bally(1): print "o"
locate ballx(2), bally(2): print "o"
locate ballx(3), bally(3): print "o"
DrawText ()
Sleep (75)
wend
|
So the program hasn't improved a great amount, but we are
using arrays. And we still get 3 bouncing balls when we run it.
This still isn't the best way to use arrays though.
In the next step we are going to replace code like:
ballx(1) = ballx(1) + ballxd(1)
With code like this:
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 i
i = 1
ballx(i) = rnd () % 38 + 1
bally(i) = rnd () % 22 + 1
ballxd(i) = 1: ballyd(i) = 1
i = 2
ballx(i) = rnd () % 38 + 1
bally(i) = rnd () % 22 + 1
ballxd(i) = 1: ballyd(i) = 1
i = 3
ballx(i) = rnd () % 38 + 1
bally(i) = rnd () % 22 + 1
ballxd(i) = 1: ballyd(i) = 1
TextMode (TEXT_BUFFERED)
while true
i = 1
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
i = 2
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
i = 3
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
cls
i = 1
locate ballx(i), bally(i): print "o"
i = 2
locate ballx(i), bally(i): print "o"
i = 3
locate ballx(i), bally(i): print "o"
DrawText ()
Sleep (75)
wend
|
Now again the program still produces 3 bouncing balls. And it
hasn't become any simpler or shorter. Infact all these i
= ... statements have made it longer still.
But there is one very important feature here that you may have
noticed!
The positioning code is exactly the same for each
ball.
The movement code is exactly the same for each ball.
The drawing code is exactly the same for each ball.
All that differs is the i = 1, i = 2, or i = 3 that is infront.
So we can use our for..next trick (from
before) so that the same instructions can be used on all
the balls!
So instead of:
i = 1 locate ballx(i), bally(i): print "o" i = 2 locate ballx(i), bally(i): print "o" i = 3 locate ballx(i), bally(i): print "o"
we can write:
for i = 1 to 3
locate ballx(i), bally(i): print "o"
next
So let's do it! Here's the new program:
dim ballx(3), bally(3)
dim ballxd(3), ballyd(3)
dim i
for i = 1 to 3
ballx(i) = rnd () % 38 + 1
bally(i) = rnd () % 22 + 1
ballxd(i) = 1: ballyd(i) = 1
next
TextMode (TEXT_BUFFERED)
while true
for i = 1 to 3
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 3
locate ballx(i), bally(i): print "o"
next
DrawText ()
Sleep (75)
wend
|
Now there's an improvement! It's only a little bit longer than the code to bounce one ball around the screen!
But let's take this a little bit further.
We keep on writing for i = 1 to 3. This is
obviously because there are 3 balls on the screen. But instead of
saying 3 everytime, let's use a constant
instead!
Why would we do this? We'll see in a minute :-)
We will call the constant ballCount and give it the value 3 at the start of the program like this:
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 = 3
dim ballx(ballCount), bally(ballCount)
dim ballxd(ballCount), ballyd(ballCount)
dim i
for i = 1 to ballCount
ballx(i) = rnd () % 38 + 1
bally(i) = rnd () % 22 + 1
ballxd(i) = 1: ballyd(i) = 1
next
TextMode (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
And re-run the program.
That's right! Changing just one line of the program can make it into a 50 ball program. And you can just as easily change it to 1, 10, 100 or 1000 balls, or any other number for that matter (although when the number gets really big the computer will start to slow down. If it gets too big the computer will say it doesn't have enough memory to store all these balls and won't be able to run the program.)
So that is - in a nutshell - the power of using arrays that I've been harping on about all this time...
Now I promised that we were going to have multiple space aliens, and now we have the tools to do it.
So load up the space alien game from the first tutorial (or cut and paste it from the tutorial if necessary).
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):
dim score, lives, turretx, alienx, alieny
With :
const alienCount = 10 dim score, lives, turretx dim 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 = 0 alieny = 12
With:
for i = 1 to alienCount
alienx(i) = rnd () % 37
alieny(i) = rnd () % 22 + 1
alienOnScreen(i) = true
next
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:
alienx = alienx + 1
if alienx > 37 then
alienx = 0
alieny = rnd () % 22 + 1
endif
And replace it with:
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
locate alienx, alieny: print ">O<"
And replace it with this:
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
And delete it!
Now run the program, and you should see a whole screenful of space aliens flying up above the turret.
If it doesn't work, then you will need to check over the
program for mistakes.
To make it easier, here's the complete program at this point,
with the changes in red
as usual.
const alienCount = 10
dim score, lives, turretx
dim alienx (alienCount), alieny (alienCount), alienOnScreen (alienCount)
dim bulletx, bullety, bulletOnScreen, i
lives = 3
turretx = 19
for i = 1 to alienCount
alienx(i) = rnd () % 37
alieny(i) = rnd () % 22 + 1
alienOnScreen(i) = true
next
bulletOnScreen = false
TextMode (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
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
DrawText ()
Sleep (75)
wend
|
So we can see that the game indeed runs, and that there are many aliens.
This looks a bit more exciting! But if you're like me, you'll be wanting get that collision code back in so we can start blasting aliens! (It's a male thing...)
So we'll simplify what happens when the alien gets hit a little bit and just do the following:
Because there are 10 aliens, we need to tell the computer to check whether the bullet has hit each one individually. So we will need another for..next loop, to check the bullet's position against all of the aliens.
Here's the updated code:
const alienCount = 10
dim score, lives, turretx
dim alienx (alienCount), alieny (alienCount), alienOnScreen (alienCount)
dim bulletx, bullety, bulletOnScreen, i
lives = 3
turretx = 19
for i = 1 to alienCount
alienx(i) = rnd () % 37
alieny(i) = rnd () % 22 + 1
alienOnScreen(i) = true
next
bulletOnScreen = false
TextMode (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
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
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
|
Now this is probably more if..thens and for..nexts than we've used in combination before, but we should be ready to cope with it now :) It's the same as what we've seen before, just in a few more layers.
First we tell the computer that if the bullet is not on the screen then don't worry about checking any of the aliens:
if bulletOnScreen then
Next we tell it to repeat the instructions multiple times, once for each alien.
for i = 1 to alienCount
Then we say to only to check the alien if it's on the screen.
if alienOnScreen (i) then
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.
alienOnScreen (i) = false
bulletOnScreen = false
score = score + 100
And that's about all there is too it.
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.
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:
const bombCount = 10 dim bombx (bombCount), bomby (bombCount), bombOnScreen (bombCount)
(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
next
endif
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"
endif
next
Here's what the program currently looks like:
const alienCount = 10
const bombCount = 10
dim score, lives, turretx
dim alienx (alienCount), alieny (alienCount), alienOnScreen (alienCount)
dim bulletx, bullety, bulletOnScreen, i, j
dim bombx (bombCount), bomby (bombCount), bombOnScreen (bombCount)
lives = 3
turretx = 19
for i = 1 to alienCount
alienx(i) = rnd () % 37
alieny(i) = rnd () % 22 + 1
alienOnScreen(i) = true
next
bulletOnScreen = false
TextMode (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
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
|
(Don't forget to add the j to the dim instruction at the top!)
You can see that the program actually runs, and that the
aliens do make bombs.
We just need to make them fall down the screen, like this:
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
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 = 10
const bombCount = 10
dim score, lives, turretx
dim alienx (alienCount), alieny (alienCount), alienOnScreen (alienCount)
dim bulletx, bullety, bulletOnScreen, i, j
dim bombx (bombCount), bomby (bombCount), bombOnScreen (bombCount)
lives = 3
turretx = 19
for i = 1 to alienCount
alienx(i) = rnd () % 37
alieny(i) = rnd () % 22 + 1
alienOnScreen(i) = true
next
bulletOnScreen = false
TextMode (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:
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 = 10
const bombCount = 10
dim score, lives, turretx
dim alienx (alienCount), alieny (alienCount), alienOnScreen (alienCount)
dim bulletx, bullety, bulletOnScreen, i, j
dim bombx (bombCount), bomby (bombCount), bombOnScreen (bombCount)
lives = 3
turretx = 19
for i = 1 to alienCount
alienx(i) = rnd () % 37
alieny(i) = rnd () % 22 + 1
alienOnScreen(i) = true
next
bulletOnScreen = false
TextMode (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
|
So now we have something that looks a bit more like a complete
playable game.
There are still a lot of things we could do to improve it, such
as automatically ending the game once all the aliens are shot (or
moving onto the next level..?). Or letting the player shoot more
than one bullet at a time. I'll leave these up to you.
You may also have noticed that the game is quite difficult at the start. This is no big deal, it just means we need to fine-tune some of the parameters. I'll leave this up to you also, but here are some ideas:
For example, changing the line that reads:
if rnd () % 10 + 1 = 1 then
To
if rnd () % 30 + 1 = 1 then
Will give the aliens a 1 in 30 chance of shooting each time
instead of 1 in 10.
(Or try some other numbers.)
Replace this line:
alieny(i) = rnd () % 22 + 1
With
alieny(i) = rnd () % 20 + 1
To stop the aliens coming in quite so low.
(There are two places in the program with this line, you'll need
to replace both.)
Change the 10 in line:
const alienCount = 10
To the number of aliens you want to have on the screen.
Change the 10 in line:
const bombCount = 10
To the number of bombs you want on the screen.
By changing the line:
Sleep (75)
To a different number. (Higher numbers slow the game down. Lower numbers speed it up.)
By changing the line:
lives = 3
And that about wraps it up for this tutorial! The next one will introduce a few more programming techniques for writing cleaner and easier to read code.