Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
15-May-2004
-Tom Mulgrew
Intro
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.
Getting started
First you need a computer. It will need to be:
• A PC. About 350 Mhz or faster is recommended.
• It must be running one of the following versions of Windows:
• Windows 98, or
• Windows ME, or
• Windows 2000, or
• Windows XP
• A graphics card with OpenGL support (any recent computer should be fine).
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.
My first program!
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.
Basic4GL as a calculator
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:
• Some arithmetic operations are performed before others. E.g. multiplication (*) is always
performed before addition and subtraction (+)
• You can force the order of evaluation by using brackets
• sqrt is a function (calculates the square root).
You can use functions anywhere that you can use a regular number.
• You can use plus (+) to join two quoted strings together.
Variables
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:
• A real number.
This corresponds to a regular number, like 5, -12, 4.332 or 3.14159265
These numbers can be positive or negative, or have fractions.
(Another name for these sorts of numbers is "floating point" numbers. But we will just call them "real"
numbers in this tutorial.)
• An integer number.
These are just like real numbers, but can only store whole numbers, not fractions.
Like -4, 1000, 32.
(But not 0.3333 or -12.9)
• A text "string".
This stores some text, such as "Hello World!" or "The price of fish is $4.77 today" or "Press any key to
continue"
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, ba = 5b = 3printr "a stores " + aprintr "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)
Variable types
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:
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:
Adding animation
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:
1. You display a picture.
2. Leave it on the screen for a short amount of time
3. Then replace it with another picture which has changed slightly from the first.
4. Go back to step 2
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:
• "cls" which clears all the text from the screen.
• "Sleep" which makes Basic4GL pause before it continues executing the instructions. The
number is the length of the pause in milliseconds. So 1000 corresponds to a one second pause.
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.
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)
x=1
cls
locate x, 12
print "->"
Sleep (75)
x = 38
cls
locate x, 12
print "->"
Sleep (75)
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
Constants
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:
• VK_LEFT
• VK_RIGHT
• VK_SPACE
Functions
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.
Keyboard input
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.
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:
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.
lives = 3
turretx = 19
alienx = 0
TextMode (TEXT_BUFFERED)
while true
alienx = alienx + 1
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:
alienx = 0
And that's all there is to it.
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
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.
alieny = rnd () % 22 + 1
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
Where to now?
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.
Bricks
dim score, ballsdim ballx#, bally#, ballxd#, ballyd#dim paddlexdim col, line, a$paddlex = 18ballx#
20bally#
10ballxd#
0ballyd#
1score = 0balls = 3color (255, 255, 255)locate 0, 0: print "Score: 0"locate 30, 0: print "Balls: 3"locate
0, 2color (255, 100, 100)for line = 1 to 7 for col = 1 to 20 print "[]" nextnextTextMode
(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#
0 then ballyd#
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
Road
dim roadx, carx, scoredim delay#dim iroadx = 13carx = 20delay#
Guess a number
dim guesses, number, guessnumber = rnd () % 100 + 1Color (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"printrfor 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
endifnextprintrprintr "Out of guesses!"printr "The number was " + number
Worm
dim x, y, xd, yd, key, scorex = 20: y = 12xd = 0: yd = -1Color (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