15-May-2004
-Tom Mulgrew
This is a tutorial on how to write games in Basic4GL, which is a free
programming language for Windows computers.
It's aimed at the complete beginner, and takes you from the very
basics of writing simple programs, right through to writing
scrolling 2D sprite based games.
So if you've never programmed a line of code before, I recommend
you start at the beginning. Otherwise you may want to skip a few
sections and jump in at the level that suits you.
This is part 1 of the tutorial, which introduces the basics of programming by using them to write a simple text based space invaders like game. Later parts will build onto what is taught here, introducing 2D sprite based animation and finally a full parallax scrolling 2D shooter.
Once upon a time if you bought a computer, it came with a free
programming language called BASIC, which stands for
"Beginner's All Purpose Symbolic Instruction Code" and
was invented to make programming easier to learn for beginners.
Traditionally it wasn't the most powerful language for writing
complex applications, but it did make it easy to write
interesting programs - often with graphics and/or sound effects -
without having to write pages of program code just to get
started.
Basic4GL aims to continue in this spirit, as a free, beginner
friendly language, based on today's technology like OpenGL 3D
graphics. It's specifically designed to make the fun stuff easily
accessible, like games and animations.
And while you're doing this, you're also learning basic
programming concepts and skills that you can use if you decide to
move on to more powerful languages that professional programmers
use.
So, in that spirit, this tutorial will teach you to program using animations, games, and basically anything that I think looks interesting or cool. We will start with text based animation (because it's easiest to start with), move into sprite based 2D animation and work our way up to a full 2D parallax scrolling platform shooter.
First you need a computer. It will need to be:
Next you need the Basic4GL compiler and development
environment.
Fortunately this is available for free from the Basic4GL website:
www.basic4gl.net.
You will need to download and install it.
Okay! Let's assume you've installed Basic4GL and are ready to go. (If you haven't, there's not much that this tutorial can do for you :)
We're going to write our first program. It will be very simple.
First, run Basic4GL as follows:
Click the windows "Start" menu, then
"Programs", then "Basic4GL", then
"Basic4GL".
You should see the Basic4GL programming window.

This window looks fairly innocent. Infact it looks a bit like
the Windows notepad.
It has an area where you can type into, and and a few buttons on
the top.
This however is the Basic4GL editor and is all you need to create and test your own programs. You type them into the text area at the bottom, and run them by clicking the "Go" button on the toolbar.
Here's the first program.
print "Hello world!" |
Type this in, then click the "Go" button on the
toolbar: ![]()
Now one of two things will happen!
If it works, the screen will go black and you will see this:
![]()
In the top left hand corner.
Yes, it's the infamous Hello World program. Press a key to finish
the program and switch back to the regular screen.
If it doesn't work, you will likely see something like this:

This means there is a syntax error in the program.
If this happens to you, do not panic! Syntax
errors occur all the time. They are the programming equivalent of
a typo. The computer is simply saying it does not understand what
you are trying to do, so you just need to fix it up and try
again.
The computer has positioned the cursor at the position of the
problem, and has displayed a description of the problem on the
status bar (the gray bar at the bottom). In the example, it reads
"Unknown variable: prit. Must be declared with DIM."
Sometimes these 'error messages' can be helpful in figuring out
the cause of the problem.
In this example, it isn't all that useful, so we need to have a
close look ourselves and figure out what is wrong.
Here we have written: prit instead of print
All we need to do is correct the problem, then click the Go button again, and we should get the results we need.
Lets have a look at how "Hello World" worked. It's
quite a simple program.
It has just one instruction, consisting of the command print
and a parameter "Hello world!".
The print command as you might have guessed
prints text on the screen.
You may have noticed that Basic4GL changed its colour to red as
you typed it. This is Basic4GL's way of telling you that it has
recognised the word "print" as one of its commands.
The "Hello world!" part is what's known as a quoted string. This is how we supply text to the program, so we can tell the print command what we want to print to the screen. The double quotes tell Basic4GL that anything between the quotes are to be treated as text data, so it doesn't try to read it as program code. Basic4GL displays quoted strings in green.
If we remove the quotes from the program and try to run it, it won't work! Because now it treats Hello World! as program instructions. There is no command called "Hello", so Basic4GL will stop and complain.
Once you have a working program that you want to keep, you can
save it to disk.
It is also a good idea to save your changes as you go, so that
your work isn't lost if something unexpected happens.
Basic4GL saves programs the same way as a text editor would.
You can click "Program|Save", press Control+S on your
keyboard, or click the save button ![]()
Here's our second program.
Before typing it in, click the new program button on the toolbar
, to tell Basic4GL we
are working on a new and different program.
print "4 + 5 = " print 4 + 5 |
Again, click on the "Go" button to run the program.
![]()
So now we can use Basic4GL as a calculator!
Infact we've just written our first expression!
You've just written your first expression: 4
+ 5
And the computer has calculated the result and displayed it (with
print).
Again let's break it down.
This program has two instructions. Each on a different line.
print "4 + 5 = "
This is just like the Hello World program. We have used the print
command, and supplied it with the text "4 + 5 =
" as a quoted string. We know that this means write
the text "4 + 5 =" to the screen.
print 4 + 5
This looks much like the first line, except the 4 + 5 is
not a quoted string anymore. We are using the print
command again, but this time using 4 + 5 as the
parameter.
So what does the computer do? It evaluates 4
+ 5 first. It calculates that 4 + 5 equals 9, and then
sends 9 through to print as the parameter.
So the second line prints out a 9 on the screen.
Try modifying the program to calculate other equations. Here are some examples:
| 4 + 5 + 6 | |
| 7 * 8 | * means multiplication |
| 14.2 - .5 | |
| 3 / 2 | / means division |
| 1 + 2 * 3 | |
| (1 + 2) * 3 | |
| sqrt (2) | |
| (1 + sqrt (2)) * 2 | |
| "Cat" + "fish" | |
| "Five" + 5 | |
| "1" + "3" | |
| "4 x 5 = " + 4 * 5 |
Some notes to be aware of:
So now we can calculate mathematical equations and print the
results on the screen.
Useful... But we are still some distance away from writing a
parallax side scroller! Don't worry, we will get there! But first
we need to introduce a few more concepts.
We will start with variables.
A variable is somewhere that you can store some data.
In Basic4GL, this data can be one of the following:
Almost all programs use variables. Even games use them to keep track of all sorts of things. They might store how many aliens there currently are, or how many bullets the player has, or what the score is, or what the players names are on the high score chart, or how long since each one fired a bullet, or any number of things.
So let's have an example.
Clear out the old program (save it first if you want to), and
type in the following.
dim a, b a = 5 b = 3 printr "a stores " + a printr "b stores " + b |
Then run the program (with the Go button, as usual).
It should tell us that a is storing 5, and b is storing 3.
a and b are variables.
We told the computer that we wanted to create two variables with
line at the top:
dim a, b
dim is the command that creates
variables. After it we list the names that we want to give to
those variables, with commas in between (if there are more than
one). In this case, we have two variables called a
and b.
Next we tell the computer to assign values to them with:
a = 5
b = 3
This tells the computer to store the value 5
in the variable named a, and the value 3
in the variable named b.
Finally we print the results to screen:
printr "a stores " + a
printr "b stores " + b
This time we're using the Basic4GL printr command. This is exactly like the print command except that it returns the cursor to the start of the next line after it has finished.
Variables can be used anywhere that you would normally put a number - in expressions or as parameters for commands. For example, consider the following program.
dim a, b, c a = 5 b = 3 + 4 c = a + b printr "a = " + a printr "b = " + b printr "c = " + c printr "b + c = " + (b + c) |
(Type it in and run it if you want.)
This program uses an expression 3 + 4 to calculate the value to store in b:
b = 3 + 4
It uses a + b to calculate the value to store in c:
c = a + b
It uses b + c to calculate a value to use in a parameter to printr:
printr "b + c = " + (b + c)
So far we have used a, b and
c as variable names, but we don't have
to stick with single letters if we don't want. In our program,
the variables didn't really have any purpose, but in most
programs they do, so it is a good idea to try to give them names
that match what it is they are for. This makes the program easier
to understand when you come back to it.
If we are storing the number of lives the player has and his/her
score, we could write this:
dim a, b
a = 3
b = 1020
this works fine, but if we instead wrote:
dim lives, score
lives = 3
score = 1020
it makes it a lot easier to understand what the program is trying to do.
There are a few rules you have to follow when choosing the names for your variables, otherwise the compiler won't compile and run your program:
Some examples of acceptable variable names:
cat, a1, my_shoe_size, MaximumHealth, counter
Some examples of unacceptable variable names:
cat fish, 2many, health&armour
All the variables we have seen so far are integer variables.
We can't use them to store text strings.
dim a
a = "my house"
Would not work.
We can't use them to store real numbers with fractions.
dim a
a = 3.443
would compile and run, however it would round 3.443 to 3 before storing it in a.
So how do we tell the computer we want to store a text string
instead of an integer?
To store a text string, we have tell the computer to allocate a text
string variable.
We do this by appending a dollar sign ($) to the variable name
when we declare it.
Here's another example to try.
dim school$, schoolMotto$ school$ = "Scott Base elementary" schoolMotto$ = "If it moves, don't eat it" printr "Welcome to " + school$ printr "Our motto is" printr schoolMotto$ |
We've created two text string variables:
dim school$, schoolMotto$
Because they end in a dollar sign, the computer knows that we
want to store text string data inside them.
We've stored some text inside them:
school$ = "Scott Base elementary"
schoolMotto$ = "If it moves, don't eat it"
And we've used them in expressions and as parameters to printr
printr "Welcome to " + school$
printr "Our motto is"
printr schoolMotto$
So that's how we store text in variables.
If we want to tell the computer to store a real number in a variable, we have to append a hash sign (#) to the variable name..
For example:
dim l#, w#, diameter# l# = 10 w# = 14 diameter# = sqrt (l# * l# + w# * w#) printr "A " + w# + " by " + l# + " inch screen" printr "Is " + diameter# + " inches in diameter" |
We've covered a fair bit of theory so far, and you may now be scratching your head and wondering how you're going to hold it all in. Again, don't worry! The best way to pick these things up is from examples, and we'll have plenty of those.
For now, let's move on to something a little more visual,
where we can see what's going on.
We're going to draw a scene from a space invaders like game.
Just be a single snapshot for now as we will need to learn a few
more things before we can turn it into something playable.
Here's the program:
color (255, 255, 255) locate 0, 0: print "Score=1040" locate 30, 0: print "Lives=3" color (255, 50, 50) locate 11, 12: print ">O<" color (150, 150, 150) locate 17, 23: print "<!>" color (255, 255, 50) locate 15, 17: print "!" |
When you run this, you should see something that looks a bit
like a scene from a space invaders type of game.
It has the score and lives displayed at the top, some sort of red
space invader thing in the middle, the player's gun turret down
the bottom in gray, and a yellow bullet presumably halfway
through flying up the screen.
Okay, it's all just coloured text characters for now, but it will
serve until we learn about sprites and other forms of animation.
We have used three different commands:
You can see that we've used the colon (:) to
separate the locate command from the print
command.
We must use a colon if we want to place more than one command on
one line, so that Basic4GL knows where the first one stops, and
the second one begins.
Believe it or not, we are going to turn the previous program
into a full working game. So don't forget to save it before
moving on.
First though, we are going to learn how animate.
The basic principles of computer animation are the same as those
of cartoon animation. It can be broken down into steps:
The brain interprets the continually changing still images as movement, and we have animation.
Let's illustrate with an example:
Sleep (2000) cls:locate 10, 12: print "->": Sleep (200) cls:locate 11, 12: print "->": Sleep (200) cls:locate 12, 12: print "->": Sleep (200) cls:locate 13, 12: print "->": Sleep (200) cls:locate 14, 12: print "->": Sleep (200) |
This is a very short animation. It simply moves
"->" along the screen a few times and stops.
The new commands are:
As you can see, we display a picture (the "->") on the screen, leave it for a short amout of time, then replace it with another picture (the "->" slightly to the right of where it was). We do this five times, each time changing the position of the "->" by changing the column number in the locate command. This gives us our very simple animation.
Note: I put the "Sleep (2000)" line at the top to add a 2 second delay to the program before it started. This gives the monitor time to switch resolutions and get setup before the animation starts.
The biggest problem with that animation is that we had to
write a line of code for each "frame" of the animation.
In this case, it wasn't so bad, as we only had 5 frames, and each
frame is very simple. But if you consider that even a simple 2D
computer game can display several thousand frames, with dozens of
objects moving around in each, then it becomes clear that we need
a better way of doing things than writing one line of code for
each frame!
One better approach is to use an "animation loop".
We will demonstrate this by extending the animation to move the
"->" all the way from the left hand side of the
screen to the right hand side.
Here's the program:
Sleep (2000)
dim x
for x = 0 to 38
cls
locate x, 12
print "->"
Sleep (75)
next
|
As you can see, this program is a lot shorter than 39 lines,
but it still displays 39 frames of animation!
Let's examine what it's doing:
We've introduced a variable x, which we are using to store the column of the "->"s position. Notice that we are now positioning the cursor with "locate x, 12". That is we are calling the locate command, and passing x as the first parameter (the column number) and 12 as the second (the row number).
Next, we've created a for..next
"loop".
A "loop" is a set of commands that get run more than
once. In our case, this is all the commands between the for
line and the next line.
The for..next loop is a
particular type of loop. It has a loop variable, which counts
from one number to another number:
for x = 0 to 38
In this case, the loop variable is x. It will count from 0 to 38 (inclusive). And for each time, it will run the contents of the loop.
So the first time it is effectively running:
x = 0
cls
locate x, 12
print "->"
Sleep (75)
And the second time:
x = 1
cls
locate x, 12
print "->"
Sleep (75)
And so on, up until the last time, where it runs:
x = 38
cls
locate x, 12
print "->"
Sleep (75)
And then it's finished.
So each time it runs the locate command, the
cursor will end up one to the right of where it was last time,
and the arrow will be drawn in a slightly different place.
As you can see, the for..next
loop is very useful, and makes what would otherwise have been a
long repeditive program very small and compact.
Here's some more for..next examples:
dim i
for i = 1 to 10
printr i
next
|
dim i
for i = 0 to 9
printr 10 - i
Sleep (1000)
next
print "Blastoff!"
|
dim i
printr "12 times table"
for i = 1 to 12
printr i + " x 12 = " + (i * 12)
next
|
So let's take what we've learned and extend the space invaders program. We will be adding to the program bit by bit, so each example will show the new pieces in red.
First, we will start by storing the score and lives in some variables:
dim score, lives lives = 3 color (255, 255, 255) locate 0, 0: print "Score=" + score locate 30, 0: print "Lives=" + lives color (255, 50, 50) locate 11, 12: print ">O<" color (150, 150, 150) locate 17, 23: print "<!>" color (255, 255, 50) locate 15, 17: print "!" |
Notice that we set "lives" to it's initial value at the start of the program. The initial value for "score" is 0, so we don't have to change it.
Next we will take all the drawing code, and put it into an animation loop. The program will keep on drawing new animation frames until the user quits it by pressing escape. So remember to press escape when you want to get out of the program!
dim score, lives
lives = 3
while true
cls
color (255, 255, 255)
locate 0, 0: print "Score=" + score
locate 30, 0: print "Lives=" + lives
color (255, 50, 50)
locate 11, 12: print ">O<"
color (150, 150, 150)
locate 17, 23: print "<!>"
color (255, 255, 50)
locate 15, 17: print "!"
Sleep (75)
wend
|
This time we've used a while..wend
loop, which is another sort of loop. Like the for..next
loop, the instructions inside the loop are run multiple times. In
this case the computer will keep on running the instructions
forever, until the user quits the program by pressing escape.
(Not all while..wend loops run
forever, there are many different ways to use them. The while..wend
loop will be explained in more detail later.)
You may have noticed a couple of things:
We will fix the flickering later. For now we need to concentrate on making things move, and the obvious place to start is the player's turret, which will slide along the bottom of the screen.
To make the player's turret move, the computer needs to store
information about the turret in variables. We need to
decide exactly what information it needs to remember so that it
can draw the turret on the screen and move it around when the
player pressed the right keys.
We will make the turret moves as follows:
But first, we need to take another detour to introduce some more new concepts.
Before we can continue with the space invaders game we need to take a detour to learn a few new techniques. Don't forget to save the space invaders program away to disk first.
A constant is much like a variable.
It has a name (like true, TEXT_BUFFERED,
VK_LEFT). It also has a value, which can be
either a number or a string.
Unlike variables, the value of a constant never changes.
Basic4GL has a number of pre-defined "constants". These are constants that Basic4GL already knows about, without you having to tell it first.
Here are some pre-defined constants:
printr "m_pi = " + m_pi printr "TEXT_BUFFERED = " + TEXT_BUFFERED printr "VK_LEFT = " + VK_LEFT |
Sometimes constants are used as an easy way to remember a commonly used number, such as Pi (stored in the constant m_pi).
Sometimes constants are used to associate a more meaningful
name with a number. For example VK_LEFT stores
the scan code of the left arrow key, which happens to be 37.
The computer knows that 37 means the left arrow key, but I'm less
likely to remember that. But if I use the VK_LEFT
constant in a program, I can easily see the program is trying to
do.
We will be using the following constants to find out which keys are being pressed, so we can move the gun turret accordingly:
A function is like a command. It has a name which Basic4GL
recognises, and sometimes has one or more parameters.
The main difference is that a function evaluates to a number or a
string. We call this the "return value". We can use
this value anywhere we would normally use a value, e.g. in an
expression, as a parameter to another command or function. We can
also assign it to a variable.
Some examples of functions:
printr "Half the square root of 2 is " + sqrt (2) / 2 printr "A random number: " + rnd () dim a$, helloLength a$ = "Hello" helloLength = len (a$) print a$ + " has " + helloLength + " letters" |
sqrt, rnd, and len
are all functions.
As you can see, they all evaluate to a number or string that can
be used like any other value.
Basic4GL has a large number of functions that calculate a number
of different things.
Right! Now we've had a very quick crash course on functions
and constants, we can introduce the ScanKeyDown
function.
We are going to use this function to find out whether
keys are being pressed or not. The function takes a single parameter
which is the "scan code" of the key that we are
interested in. Because I don't know all the keyboard scan key
codes off the top of my head, we're going to use special
predefined constants: VK_LEFT, VK_RIGHT
and VK_SPACE.
Here's how it all fits together:
while true
cls
print ScanKeyDown (VK_SPACE)
wend
|
(Tap the spacebar while the program is running to see it in effect.)
ScanKeyDown (VK_SPACE) evaluates to -1 when
the spacebar is being pressed, and 0 when it isn't.
(-1 and 0 are actually special "boolean" values true
and false. But we will worry about boolean
values later.)
Here's another example:
while true
cls
if ScanKeyDown (VK_UP) then
locate 19, 4: print "Up"
endif
if ScanKeyDown (VK_DOWN) then
locate 18, 19: print "Down"
endif
if ScanKeyDown (VK_LEFT) then
locate 8, 12: print "Left"
endif
if ScanKeyDown (VK_RIGHT) then
locate 28, 12: print "Right"
endif
wend
|
(In this one, you need to press the arrow keys while it's running to see what it does.)
This example uses the if..then..endif statement, which will be explained very soon.
Okay, load up the space invaders program, and modify it to look like the following (new bits are in red.)
dim score, lives, turretx
lives = 3
turretx = 19
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
cls
color (255, 255, 255)
locate 0, 0: print "Score=" + score
locate 30, 0: print "Lives=" + lives
color (255, 50, 50)
locate 11, 12: print ">O<"
color (150, 150, 150)
locate turretx, 23: print "<!>"
color (255, 255, 50)
locate 15, 17: print "!"
Sleep (75)
wend
|
(Don't forget to update the locate command where it draws the turret!)
Okay, so now we can move the turret left and right by pressing the left and right arrow keys. This is our first interactive program! We're well on our way!
But first we have to understand this new if..then..endif
statement.
This is called a conditional statement, because the
computer sometimes runs the instructions between then
and endif and sometimes doesn't. This all
depends on the part between if and then,
i.e. the "condition".
Let's examine the first one:
if ScanKeyDown (VK_LEFT) and turretx > 0 then
The "condition" here is: "ScanKeyDown
(VK_LEFT) and turretx > 0"
This is like an expression (e.g. 1+2/3), except it evaluates to
either true or false.
Conditional statements often read a lot like english. In
english you might say "If it is raining then take your
umbrella to work".
In this one we are telling the computer "if the player is
pressing the left arrow key and the turret hasn't
already moved as far as it will go, then move it slightly to the
left".
Of course the computer doesn't speak english, so we need to put
it in computer terms. So "the player is pressing the left
arrow key" becomes "ScanKeyDown (VK_LEFT)",
and "the turret hasn't already moved as far as it will
go" becomes "turretx > 0".
When the computer runs this instruction and sees that the condition is true (i.e. the player is pressing the key and the turret can move further), then it will run the instructions between then and endif:
turretx = turretx - 1
Which will move our turret one column to the left (by subtracting one from it's column number).
Of course if the computer runs the if ... then instruction and the player is not pressing the left arrow key (or the turret has already reached the edge of the screen) then the computer will see that the condition is false, and it will not run the instructions between then and endif. Instead it will skip to just after the endif and keep running the program from there.
The second if..then..endif line is used to move the turret right. It works much the same way as moving left so I'll leave you to examine it and see how it works.
It's time to deal with the flickering, as it is quite painful to watch!
The reason for the flickering is that the screen is updated every time we:
So each time a frame is drawn, everything dissapears, and then is drawn back in, one object at a time. So the ugly flicker is due to everything constantly dissapearing and re-appearing.
What we want is a way to prevent the user seeing our drawing
until we have everything setup and ready to display. So the user
never has to see a half drawn frame.
We can do this with the TextMode and DrawText
commands.
dim score, lives, turretx
lives = 3
turretx = 19
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
cls
color (255, 255, 255)
locate 0, 0: print "Score=" + score
locate 30, 0: print "Lives=" + lives
color (255, 50, 50)
locate 11, 12: print ">O<"
color (150, 150, 150)
locate turretx, 23: print "<!>"
color (255, 255, 50)
locate 15, 17: print "!"
DrawText ()
Sleep (75)
wend
|
Flicker problem solved!
TextMode (TEXT_BUFFERED) switches the text
drawing mode to buffered mode. This means that any changes to
text on the screen will not be shown until we say so. And we tell
the computer we're ready to display the changes with the DrawText
() command.
Sorted!
Next we'll add some code to move the space alien.
It will move from left to right. When it reaches the right hand
side of the screen, we will start it again from the left.
dim score, lives, turretx, alienx
lives = 3
turretx = 19
alienx = 0
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
alienx = alienx + 1
if alienx > 37 then
alienx = 0
endif
cls
color (255, 255, 255)
locate 0, 0: print "Score=" + score
locate 30, 0: print "Lives=" + lives
color (255, 50, 50)
locate alienx, 12: print ">O<"
color (150, 150, 150)
locate turretx, 23: print "<!>"
color (255, 255, 50)
locate 15, 17: print "!"
DrawText ()
Sleep (75)
wend
|
(Again, don't forget to update the locate line where we draw the alien.)
It should be getting easier to see how this works.
We've created a new variable to store the alien's position,
called alienx. Like with the turret, this stores
the column that the alien is currently positioned at.
We set it to zero at the start. We didn't really have to (as zero
is the default anyway), but it doesn't hurt to be specific.
We move the alien one column to the right by adding one to it's
column position.
alienx = alienx + 1.
Then we check whether the alien has reached the right hand side of the screen:
if alienx > 37 then
And if it has, we move it back to the left hand side:
alienx = 0
And that's all there is to it.
The object of the game is to shoot the alien, so we need to
have a moving bullet.
This is a little bit more complicated than the other moving
objects because it isn't fixed at a single height. Also,
sometimes the bullet isn't on the screen at all.
Again, we need to decide what the computer needs to store in
order to handle the bullet.
We will store the bullet in three variables:
So when the user presses space, we want to "fire"
the bullet, by placing it on the screen just above the turret.
While the bullet is on the screen, it will fly up until it
reaches the top, then it will be taken off the screen ready to be
fired again.
When it comes time to draw the bullet, we only draw it
if it's on the screen.
The modified program looks like this.
dim score, lives, turretx, alienx
dim bulletx, bullety, bulletOnScreen
lives = 3
turretx = 19
alienx = 0
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
alienx = alienx + 1
if alienx > 37 then
alienx = 0
endif
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)
locate alienx, 12: print ">O<"
color (150, 150, 150)
locate turretx, 23: print "<!>"
if bulletOnScreen then
color (255, 255, 50)
locate bulletx, bullety: print "!"
endif
DrawText ()
Sleep (75)
wend
|
(You may notice that while we can now shoot at the alien, we can't actually hit it! The bullet passes straight through. This is because we haven't told the computer to do anything when the bullet hits the alien.)
We're getting very close to a complete game now! A very simple one, but a complete one all the same.
The new code should be starting to make sense now, but you may
be wondering what true and false
mean.
You may remember we learnt earlier that conditional
expressions evaluate to true or false.
And that if..then..endif
uses the condition between if and then
to determine whether to run the instructions between then
and endif.
Well we can actually store a condition result in a variable. So
we set bulletOnScreen to true
to say that the bullet is on the screen, and false
to say that it isn't. We can then use it as the condition part of
our if..then..endif
statement.
We've used some if..then..endif
statements inside other if..then..endif
statements.
This is okay. The second if..then..endif
simply become and instruction inside the first one.
We've also used an if..then..else..endif
statement. So you may be wondering how this new else
bit works.
It's actually just a simple extension of the standard if..then..endif
statement. If the condition (between if and then)
evaluates to true, the computer runs the
instructions between then and else,
otherwise it runs the instructions between else
and endif instead.
To look at what it actually does:
If the bullet is on the screen "if bulletOnScreen then", we move it up the screen by subtracting one from the row position "bullety = bullety - 1". We also check whether the bullet has reached the top of the screen "if bullety < 1 then", and if so take it off the screen. "bulletOnScreen = false".
Inside the else..endif section we say what to do if the bullet is not on the screen. In this case the player can shoot it by pressing the spacebar, so we check whether the user is pressing space "if ScanKeyDown (VK_SPACE) then" and if so, place the bullet on the screen and position it above the gun turret:
bulletOnScreen = true
bullety = 22
bulletx = turretx + 1
To complete the game we need to make the bullet hit the alien.
So we have to tell the computer how to check when the bullet has
hit the alien, and what to do when it happens.
We're going to keep it simple, and do the following:
So let's do it:
dim score, lives, turretx, alienx
dim bulletx, bullety, bulletOnScreen, i
lives = 3
turretx = 19
alienx = 0
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
alienx = alienx + 1
if alienx > 37 then
alienx = 0
endif
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)
locate alienx, 12: print ">O<"
color (150, 150, 150)
locate turretx, 23: print "<!>"
if bulletOnScreen then
color (255, 255, 50)
locate bulletx, bullety: print "!"
endif
if bulletOnScreen and bullety = 12 and bulletx >= alienx and bulletx <= alienx + 2 then
color (255, 255, 100)
for i = 1 to 10
locate alienx, 12: print "///"
DrawText ()
Sleep (50)
locate alienx, 12: print "\\\"
DrawText ()
Sleep (50)
next
bulletOnScreen = false
alienx = 0
score = score + 100
Sleep (1000)
endif
DrawText ()
Sleep (75)
wend
|
To hit the alien, the bullet has to be on the screen, at the
same row as the alien, and on a column between alienx
and alienx + 2 (because the alien is 3 columns
wide).
We animate the exploding alien by repeatedly drawing diagonal
lines over the top, using a for..next
loop to repeat the process 10 times, and a Sleep (50)
delay for timing.
We placed all this code after the regular drawing code, so that everything is already on the screen when we perform our animation.
After our animation, we remove the bullet from the screen, reset the alien to the left side, add 100 hundred points and pause for 1 second.
And that's it. That's our text based space alien game.
Currently it has a lot of restrictions, such as there's only one alien, and it doesn't shoot back (so there's not much point in having 3 lives...). But it's a playable game all the same.
Along the way we've learnt a number of programming concepts and techniques, including:
Notice how we built up the program in stages.
At each stage we had a working program that we could run and
examine the results of. This allowed us to check each stage, and
make sure that the code was doing what we expected before moving
on. It also kept things interesting (I hope!), as we were able to
see the difference that each of our changes made.
As a final touch we will add a little variety and make the
alien fly past at different heights.
We can use the rnd() function, which returns a random
number between 0 and about 32,000. A bit like throwing a
32,000 sided dice I guess.
With a bit of maths we can turn this into a number between 1 and
22 like so:
alieny = rnd () % 22 + 1
Here's the final version:
dim score, lives, turretx, alienx, alieny
dim bulletx, bullety, bulletOnScreen, i
lives = 3
turretx = 19
alienx = 0
alieny = 12
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
alienx = alienx + 1
if alienx > 37 then
alienx = 0
alieny = rnd () % 22 + 1
endif
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)
locate alienx, alieny: print ">O<"
color (150, 150, 150)
locate turretx, 23: print "<!>"
if bulletOnScreen then
color (255, 255, 50)
locate bulletx, bullety: print "!"
endif
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
DrawText ()
Sleep (75)
wend
|
Don't worry too much if this all seems like a lot to take in in one setting. It's not important to absorb it all the first time through. The best way to learn is by example and experimentation, so don't be afraid to play around with the examples or try and invent some of your own. You won't break anything!
You may want to try skimming through the Programmer's guide (choose "Programmer's guide" from the "Help" menu in Basic4GL), which lists a number of functions and commands used in Basic4GL for things like joystick and mouse input, resizing the text area or changing the font.
You may also want to play with the demo programs that are distributed with Basic4GL (click "Open..." from the "Program" menu in Basic4GL). Just keep in mind that some of the demo programs use programming features that we haven't learnt yet, and many of them use OpenGL which is a huge topic in it's own right.)
We will finish off this first part of the tutorial with some more example programs/games to try out and experiment with. See if you can figure out how they work, or modify/extend them into your own customised versions.
dim score, balls
dim ballx#, bally#, ballxd#, ballyd#
dim paddlex
dim col, line, a$
paddlex = 18
ballx# = 20
bally# = 10
ballxd# = 0
ballyd# = 1
score = 0
balls = 3
color (255, 255, 255)
locate 0, 0: print "Score: 0"
locate 30, 0: print "Balls: 3"
locate 0, 2
color (255, 100, 100)
for line = 1 to 7
for col = 1 to 20
print "[]"
next
next
TextMode (TEXT_BUFFERED)
while true
color (255, 255, 255)
locate 0, 0: print "Score: " + score
locate 30, 0: print "Balls: " + balls
locate paddlex, 23: print" "
if ScanKeyDown (VK_LEFT) and paddlex > 0 then
paddlex = paddlex - 1
endif
if ScanKeyDown (VK_RIGHT) and paddlex < 35 then
paddlex = paddlex + 1
endif
Color (200, 200, 200)
locate paddlex, 23: print"-----"
Color (255, 255, 255)
locate ballx#, bally#: print " "
a$ = CharAt$ (ballx# + ballxd#, bally# + ballyd#)
if a$ = "-" then
ballyd# = -ballyd#
ballxd# = (int (ballx#) - paddlex - 2) / 2.0
a$ = " "
endif
ballx# = ballx# + ballxd#
bally# = bally# + ballyd#
if ballx# <= 0 or ballx# > 39 then ballxd# = -ballxd# endif
if bally# <= 0 then ballyd# = -ballyd# endif
if bally# > 23 then
DrawText ()
Sleep (1000)
balls = balls - 1
if balls > 0 then
locate paddlex, 23: print" "
paddlex = 18
ballx# = 20
bally# = 10
ballxd# = 0
ballyd# = 1
else
Color (255, 255, 255)
locate 15, 12: print "Game Over!"
DrawText ()
end
endif
endif
locate ballx#, bally#: print "o"
if a$ = "[" or a$ = "]" then
ballyd# = -ballyd#
score = score + 1
endif
DrawText ()
Sleep (50)
wend
|
dim roadx, carx, score
dim delay#
dim i
roadx = 13
carx = 20
delay# = 100
Color (200, 200, 200)
for i = 1 to 23
locate roadx, i: print "** **"
next
TextMode (TEXT_BUFFERED)
while true
roadx = roadx + rnd () % 3 - 1
if roadx < 0 then roadx = 0 endif
if roadx > 40 - 14 then roadx = 40 - 14 endif
Color (200, 200, 200)
locate 0, 24: printr
locate roadx, 23: print "** **"
score = score + 1
Color (255, 255, 0)
locate 0, 0: print "Score = " + score
if ScanKeyDown (VK_LEFT) then
carx = carx - 1
endif
if ScanKeyDown (VK_RIGHT) then
carx = carx + 1
endif
if CharAt$ (carx, 12) <> " " then
Color (255, 100, 10)
locate carx - 1, 11: print "X X"
locate carx - 1, 12: print " X "
locate carx - 1, 13: print "X X"
Color (255, 255, 255)
locate 15, 12: print "Game Over!"
DrawText ()
end
endif
Color (255, 255, 255)
locate carx, 12: print "O"
DrawText ()
Sleep (delay#)
delay# = delay# - 0.25
wend
|
dim guesses, number, guess
number = rnd () % 100 + 1
Color (255, 255, 255)
printr "I've chosen a number between 1 and 100"
printr "See if you can guess it in 10 guesses"
printr "To make a guess, type in the number and"
printr "press Enter"
printr
for guesses = 1 to 10
print "Guess " + guesses + ": "
guess = val (Input$ ())
if guess = number then
printr
printr "Correct!"
end
endif
if number > guess then
printr "The number is greater than " + guess
else
printr "The number is less than " + guess
endif
next
printr
printr "Out of guesses!"
printr "The number was " + number
|
dim x, y, xd, yd, key, score
x = 20: y = 12
xd = 0: yd = -1
Color (0, 255, 0)
while true
key = InScanKey ()
if key = VK_LEFT and xd <> 1 then
xd = -1: yd = 0
endif
if key = VK_RIGHT and xd <> -1 then
xd = 1: yd = 0
endif
if key = VK_UP and yd <> 1 then
xd = 0: yd = -1
endif
if key = VK_DOWN and yd <> -1 then
xd = 0: yd = 1
endif
x = x + xd
y = y + yd
score = score + 1
if CharAt$ (x, y) <> " " then
Color (255, 255, 255)
locate 15, 11: print "Game Over!"
locate 15, 13: print "You scored " + score
end
endif
locate x, y: print "X"
Sleep (75)
wend
|