Programming Games With Microsoft Small Basic
Programming Games With Microsoft Small Basic
Kidware Software
PO Box 701
Maple Valley, WA 98038
http://www.computerscienceforkids.com
http://www.kidwaresoftware.com
Copyright © 2013 by Philip Conrod & Lou Tylee. All rights reserved
All Rights Reserved. No part of the contents of this book may be reproduced or transmitted in any
form or by any means without the written permission of the publisher.
Previous edition published as “Programming Kid Games with Microsoft Small Basic”
This copy of the “Programming Games with Microsoft Small Basic” book and the associated
software is licensed to a single user. Copies of the course are not to be distributed or provided to any
other user. Multiple copy licenses are available for educational institutions. Please contact Kidware
Software for school site license information.
This guide was developed for the course, “Programming Games with Microsoft Small Basic,”
produced by Kidware Software, Maple Valley, Washington. It is not intended to be a complete
reference to the Small Basic language. Please consult the Microsoft website for detailed reference
information.
This guide refers to several software and hardware products by their trade names. These references
are for informational purposes only and all trademarks are the property of their respective companies
and owners. Microsoft, Visual Studio, Small Basic, Visual Basic, Visual J#, and Visual C#,
IntelliSense, Word, Excel, MSDN, and Windows are all trademark products of the Microsoft
Corporation. Java is a trademark product of the Oracle Corporation. JCreator is a trademark product
of XINOX Software
The example companies, organizations, products, domain names, e-mail addresses, logos, people,
places, and events depicted are fictitious. No association with any real company, organization,
product, domain name, e-mail address, logo, person, place, or event is intended or should be inferred.
This book expresses the author’s views and opinions. The information in this book is distributed on
an "as is" basis, without and expresses, statutory, or implied warranties.
Neither the author(s) nor Kidware Software shall have any liability to any person or entity with
respect to any loss nor damage caused or alleged to be caused directly or indirectly by the
information contained in this book.
About The Authors Philip Conrod has authored, co-authored and
edited numerous computer programming books for kids, teens and adults.
Philip holds a BS in Computer Information Systems and a Master's
certificate in the Essentials of Business Development from Regis
University. Philip started programming computers in 1977 at 13 years of
age. Philip has also held various Information Technology leadership roles in
companies like Sundstrand Aerospace, Safeco Insurance Companies,
FamilyLife, Kenworth Truck Company, PACCAR and Darigold. Philip
serves as the President & Publisher of Kidware Software, LLC. He is the
proud father of three “techie” daughters. Philip and his family live in Maple
Valley, Washington.
I also want to thank my multi-talented co-author, Lou Tylee, for doing all
the real hard work necessary to develop, test, debug, and keep current all
the ‘kid-friendly’ applications, games and base tutorial text found in this
book. Lou has tirelessly poured his heart and soul into so many previous
versions of this tutorial and there are so many beginners who have benefited
from his work over the years. Lou is by far one of the best application
developers and tutorial writers I have ever worked with. Thank you Lou for
collaborating with me on this book project.
Contents
Chapter Review
TextWindow Object
GraphicsWindow Object
Controls Object
Program Object
Text Object
Mouse Object
ImageList Object
Shapes Object
File Object
Timer Object
Sound Object
Chapter Review
Variables
Arrays
Intellisense Feature
Concatenation Operator
String Methods
Math Methods
Random Numbers
Graphics Methods
Shapes Objects
Chapter Review
Syntax Errors
Run-Time Errors
Logic Errors
Chapter Review
5. Safecracker Program
Review and Preview
Remaining Work
Collision Detection
● 766 MHz Pentium or compatible processor (1.5 Ghz Pentium Recommended) ● 256 MB
RAM (512MB or more recommended) ● Video Monitor (1024 x768) with High Color 16
bit) ● CD-ROM or DVD-ROM Drive ● Microsoft Mouse or compatible pointing device
Course Prerequisites To grasp the concepts presented in
PROGRAMMING GAMES WITH MICROSOFT SMALL BASIC,
you should possess a working knowledge of the Windows operating system.
You should know how to locate, copy, move and delete files. You should be
familiar with the simple tasks of using menus, toolbars, resizing windows,
and moving windows around.
You should have had some exposure to Small Basic programming (or some
other programming language). We offer a beginning programming tutorial
BEGINNING MICROSOFT SMALL BASIC that would help you gain
this needed exposure.
You will also need the ability to view and print documents saved in the
Adobe Acrobat format.
Please complete the online registration web form at the webpage above with
your name, shipping address, email address, date of purchase, online or
physical store name, and your order confirmation number from that store.
After we receive all this information from you we will email you a
download link for the Program Solution and Multimedia Files associated
with this book.
WARNING: If you purchased this book “used” or “second hand” you are
NOT licensed or entitled to download the Program Solution Files. However,
you can purchase the Download Only version of this book as an E-Book at
a discounted price which allows you access to the program solutions and
multimedia files required for completing this tutorial.
One thing these machines had in common was that they were all
programmed in some version of Microsoft’s BASIC. Each computer had its
own fans and own magazines. Users would wait each month for the next
issue of a magazine with BASIC programs you could type into your
computer and try at home.
This was a fun and exciting time for the beginning programmer, but the fun
times ended with the introduction of the IBM-PC in the early 1980’s.
Bigger and faster computers brought forth bigger languages and bigger
development environments. These new languages were expensive to
acquire and difficult for the beginning programmer to grasp.
Which brings us to Small Basic, which I would call a relative of the early,
original BASIC language. The development of Small Basic is an attempt to
rekindle the exciting days when just about anyone could sit down at a
computer and write a simple program using the BASIC language.
Those of you who wrote programs on those old “toy” computers will
recognize the simplicity of the Small Basic language and the ease of its use.
And, you will also notice Small Basic is a great environment for writing
and testing code, something missing in the early 1980’s. For those of you
new to programming, I hope you can feel the excitement we old timers once
had. For the old timers, I hope you rekindle your programming skills with
this new product.
(Some of the headings given here may differ slightly on your computer, but
you should have no trouble finding the correct ones.) The Small Basic
program should start. If you are using Windows 8, search for the Small
Basic tile on the menu page.
After installation and trying to start, you may see an error message that
announces Small Basic cannot be started. If this occurs, try downloading
and installing the latest version of the Microsoft .NET framework at:
http://msdn.microsoft.com/en-us/netframework/aa569263.aspx
This contains some files that Small Basic needs to operate and such files
may not be on your computer.
Upon starting, my screen shows:
Below the title bar is a Toolbar. Here, little buttons with pictures allow us
to control Small Basic.
In the middle of the screen is the Editor. This is where we will write our
Small Basic programs. To the right is a Help area. Small Basic has great
help features when writing programs. This area will display hints and tips
while we write code.
Running a Small Basic Program Let’s write our first Small Basic
program. When you start, a new editor window appears. You can also get a
new editor window by clicking the New toolbar button. Type these two
lines in the editor window: TextWindow.Title = "Hello Program"
Small Basic has “intellisense” and uses this to make typing suggestions.
You can just keep typing or accept its suggestion by scrolling through the
pop-up list and pressing the Enter key.
Also, notice this appeared in the help area:
Once you typed TextWindow, the help feature displayed all it knows about
the TextWindow to help you in your programming.
Let’s run the program. Simply click the Run button on the toolbar to see:
This is the text window displaying the program output. I have resized the
window a bit. To stop the program, click the X in the upper right corner of
the window.
That’s all there is to writing a Small Basic program. Type the code in the
editor window. Click the Run button to run the code. We will learn a lot of
Small Basic code as we build the games in this course. Chapter 3 reviews
most elements of the Small Basic language.
Other useful toolbar buttons are: Open – Open a previously saved Small
Basic program Save – Save a Small Basic program Save As – Save a Small
Basic program with a different name We suggest saving each Small Basic
program in its own folder.
There are also the Cut, Copy, Paste, Undo, and Redo buttons for common
editing tasks. Learn to use these – they will save you lots of time typing
code.
Chapter Review
This completes our overview of the Small Basic environment and a brief
demonstration of how to write a Small Basic program. If you’ve used Small
Basic before, this material should be familiar. If you’ve programmed with
other languages, you should have a fairly clear understanding of what’s
going on.
Here TextWindow is the object, Title is the property (the information that
appears in the window title bar) and “Hello Program” is the value of the
property. So, in general, to set the Property of an Object, you use this “dot-
notation”: Object.Property = Value A method does something to an object.
Again, in Chapter 1, we had this line: TextWindow.WriteLine("This is the
first line of the program.") Here, WriteLine is the method (it writes
information in the text window) and the item in the parentheses is called the
method argument. The argument (or sometimes arguments) provides
information needed by the method to do its job. To apply a Method to an
Object, use: Object.Method(Arguments) Sometimes, the method may
compute and return a value. In this case, that Value is found using: Value =
Object.Method(Arguments) Lastly, an event is something that happens to
an object. Example events are pressing a mouse button or pressing a key on
the keyboard. To respond to an event, the event must be assigned a
subroutine (a self-contained segment of program code) that is called if the
event occurs. To assign the subroutine EventSub to the Event for Object,
use: Object.Event = EventSub In the rest of this chapter, we look at objects
we will use in the course to build our games. For each object, we review
some of the properties, methods and events (if any).
TextWindow Object
The TextWindow is an object where we can receive text input and write
text output. In the game programs written in this course, we will use the text
window to set game options. We saw the text window in the little example
in Chapter 1.
TextWindow Properties:
Hide()
Hides the text window.
Pause()
Waits for user input before returning.
Read()
Reads a line of text from the text window. This method will not return
until the user presses Enter. Returns entered text.
ReadNumber()
Reads a number from the text window. This method will not return until
the user presses Enter. Returns entered number.
Show()
Shows the text window.
Write(data)
Writes text or number (data) to the text window. Unlike WriteLine, this
will not append a new line character, which means, anything written to
the text window after this call will be on the same line.
TextWindow Example: This code shows the text window, asks for an
input and writes that input back to the text window: TextWindow.Show()
TextWindow.Write("Enter a number ") A = TextWindow.ReadNumber()
TextWindow.WriteLine(A)
GraphicsWindow Object The GraphicsWindow object is the
cornerstone of our game building. In the graphics window, we can draw
lines, shapes, and text in many colors. We can receive mouse and keyboard
input from a user. The coordinate system used by the graphics window is:
The window is Width pixels wide and Height pixels high. We use two
values (coordinates) to identify a single pixel in the window. The x
(horizontal) coordinate increases from left to right, starting at 0. The y
(vertical) coordinate increases from top to bottom, also starting at 0. Points
in the region are referred to by the two coordinates enclosed in parentheses,
or (x, y).
Each game program will be developed within the graphics window. This
window has many properties, methods and events. As you build the games,
you will become familiar with the use of most of these.
GraphicsWindow Properties:
BackgroundColor Gets or sets the background color of the
graphics window.
BrushColor Gets or sets the brush color to be used to fill
shapes drawn on the graphics window.
FontBold Gets or sets whether or not the font to be used
when drawing text on the graphics window, is
bold.
FontSize Gets or sets the font size to be used when
drawing text on the graphics window.
Height Gets or sets the height of the graphics window.
LastKey Gets the last key that was pressed or released.
MouseX Gets the x-position of the mouse relative to the
graphics window.
MouseY Gets the y-position of the mouse relative to the
graphics window.
PenColor Gets or sets the color of the pen used to draw
shapes on the graphics window.
PenWidth Gets or sets the width of the pen used to draw
shapes on the graphics window.
Title Gets or sets the title for the graphics window.
Width Gets or sets the width of the graphics window.
DrawLine(x1, y1, x2, y2) Draws a line from one point (x1, y1) to
another (x2, y2).
DrawRectangle(x, y, w, h) Draws a rectangle (width w, height h) on the
screen at (x, y) using the selected pen.
DrawTriangle(x1, y1, x2, y2, x3, y3) Draws a triangle connecting the
three input points on the screen using the selected pen.
FillTriangle(x1, y1, x2, y2, x3, y3) Fills a triangle connecting the three
input points on the screen using the selected brush.
Hide()
Hides the graphics window.
Show()
Shows the graphics window to enable interactions with it.
The Controls object allows you to use three controls in your Small Basic
programs – a Button, a TextBox and a MultiLineTextBox. In these notes,
we will only use the button control. The Button control is used to begin,
interrupt, or end a particular process.
Controls Properties:
Controls Events:
Button Control Example: This code creates a button (caption This Button,
size 100 pixels by 40 pixels) in the graphics window:
GraphicsWindow.Show() GraphicsWindow.Width = 400
GraphicsWindow.Height = 150
GraphicsWindow.BrushColor = "Black"
ThisButton = Controls.AddButton("This Button", 10, 10)
Controls.SetSize(ThisButton, 100, 40)
Program Object
The Program object (or more properly class) helps with program
execution.
Program Properties:
End()
Ends the program.
Text Object
The Text object provides helpful operations when working with strings of
text.
GetLength(text) Gets the length of the given text. Returns the length
(number of characters).
The Mouse object (or more properly class) helps decide if mouse is being
used.
Mouse Properties:
The ImageList object (or more properly class) helps to load and store
images in variables.
The Shapes object allows you to add, move and rotate shapes to the
graphics window. Shapes are drawn and filled with the current pen and
brush settings.
AddLine(x1, y1, x2, y2) Adds a line between the specified points (x1,
y1) and (x2, y2). Returns the line.
AddText(text)
Adds text as a shape that can be moved, animated or rotated. Returns the
text shape.
AddTriangle(x1, y1, x2, y2, x3, y3) Adds a triangle shape represented by
the specified points. Returns the triangle.
GetTop(shape)
Gets the top coordinate of the specified shape. Returns the top
coordinate.
Move(shape, x, y) Moves the shape with the specified name to a new
position (x, y).
Remove(shape)
Removes a shape from the graphics window.
Rotate(shape, angle) Rotates the shape with the specified name to the
specified angle (in degrees).
Shapes Example: This code draws a red rectangle with a blue border and
rotates it 30 degrees: GraphicsWindow.Show() GraphicsWindow.Width =
400
GraphicsWindow.Height = 150
GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 5
GraphicsWindow.BrushColor = "Red"
MyShape = Shapes.AddRectangle(70, 100) Shapes.Move(MyShape, 100,
20) Shapes.Rotate(MyShape, 30)
File Object
The File object provides methods to access, read and write information
from and to a file on disk. You provide the complete filepath to the file.
ReadLine(file, line number) Opens the specified file and reads the
contents at the specified line number. Returns the text at the specified
line.
The Timer object provides an easy way for doing something repeatedly
with a constant interval between.
Timer Properties:
Resume()
Resumes the timer from a paused state. Tick events will now be raised.
Timer Events:
The Sound object provides operations that allow the playback of sounds.
Some sample sounds are provided along with the library.
Play(file)
Plays an audio file. If the file was already paused, this operation will
resume from the position where the playback was paused.
PlayChime()
Plays the chime sound.
PlayChimes()
Plays the chimes sound.
PlayClick()
Plays the click sound.
PlayClickAndWait() Plays the click sound and waits for it to finish.
Stop(file)
Stops playback of an audio file. If the file was not already playing, this
operation will not do anything.
Chapter Review
We have completed our overview of the Small Basic objects. Use this
chapter as a reference when building the game programs. Next we look at
the language used to write program code.
3. Overview of Small Basic Programming
Review and Preview
In this chapter, we are concerned with writing code for our programs.
We will provide an overview of many of the elements of the language
used in Small Basic. This chapter is essentially a self-contained guide
to the Small Basic language. This will give us the foundation needed
to begin building some kid games.
A Brief History of BASIC
In the mid-1970's, two college students decided that the new Altair
microcomputer needed a BASIC language interpreter. They sold their
product on cassette tape for a cost of $350. You may have heard of these
entrepreneurs: Bill Gates and Paul Allen!
Every BASIC written since then has been based on that early version.
Examples include: GW-Basic, QBasic, QuickBasic, Visual Basic. All the
toy computers of the early 80’s (anyone remember TI99/4A, Commodore
64, Timex, Atari 400?) used BASIC for programming.
Use meaningful variable names that help you (or other programmers)
understand the purpose of the information stored by the variable.
A string variable is just that – one that stores a string (list) of various
characters. A string can be a name, a string of numbers, a sentence, a
paragraph, any characters at all. And, many times, a string will contain no
characters at all (an empty string). We will use lots of strings in Small
Basic, so it’s something you should become familiar with. Strings are
always enclosed in quotes (“). Examples of strings:
Boolean variables can have one of two different string values: “true” or
“false”. The quotes are need to indicate these are string values. Boolean
variables are helpful in making decisions.
With all the different variable types, we need to be careful not to improperly
mix types. We can only do mathematical operations on numbers (integer
and decimal types). String types must only work with other string types.
Boolean types are used for decisions.
Small Basic has facilities for handling arrays, which provide a way to store
a large number of variables under the same name. Each variable, called an
element, in an array must have the same data type, and they are
distinguished from each other by an array index which is enclosed in
brackets [].
The index on an array variable begins at 0 and ends at the highest value
used. Hence, the Item array in the above example actually has ten
elements, ranging from Item[0] to Item[9]. This is different than other
languages. You use array variables just like any other variable - just
remember to include its name and its index. Many times, the 0 index is
ignored and we just start with item 1. But sometimes the 0th element cannot
be ignored. You will see examples of both 0-based and 1-based arrays in the
course examples.
This refers to the element in the 2nd row and 7th column of the array
AnotherArray.
Intellisense Feature
Working within the code editor window is easy. You will see that typing
code is just like using any word processor. The usual navigation and editing
features are all there.
One feature that you will become comfortable with and amazed with is
called Intellisense. As you type code, the Intellisense feature will, at times,
provide assistance in completing lines of code. For example, once you type
an object name and a dot (.), a drop-down list of possible properties and
methods will appear. When we use methods and events, suggested values
for arguments will be provided in the Small Basic help panel.
Comment statements begin with a single quote ('). For example: ' This is a
comment
x = 2 * y ' another way to write a comment You, as a programmer, should
decide how much to comment your code. Consider such factors as reuse,
your audience, and the legacy of your code. In our notes and examples,
we try to insert comment statements when necessary to explain some
detail.
Small Basic Arithmetic Operators
Addition is done using the plus (+) sign and subtraction is done using the
minus (-) sign. Simple examples are:
Multiplication is done using the asterisk (*) and division is done using the
slash (/). Simple examples are:
There are six comparison operators in Small Basic used to compare the
value of two expressions (the expressions must be of the same data type).
These are the basis for making decisions:
Operator Comparison
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
= Equal to
<> Not equal to
Operator Operation
And Logical And
Or Logical Or
The And operator checks to see if two different Boolean data types are both
“true”. If both are “true”, the operator returns a “true”. Otherwise, it returns
a “false” value. Examples: A = “true”, B = “true”, then A And B = “true”
A = “true”, B = “false”, then A And B = “false”
A = “false”, B = “true”, then A And B = “false”
A = “false”, B = “false”, then A And B = “false”
The Or operator checks to see if either of two Boolean data types is “true”.
If either is “true”, the operator returns a “true”. Otherwise, it returns a
“false” value. Examples: A = “true”, B = “true”, then A Or B = “true”
A = “true”, B = “false”, then A Or B = “true”
A = “false”, B = “true”, then A Or B = “true”
A = “false”, B = “false”, then A Or B = “false”
To concatentate two string data types (tie them together), use the + symbol,
the string concatenation operators: CurrentTime = "The current time is" +
Clock.Time SampleText = "Hook this " + "to this"
Small Basic Methods
Some methods do not return a value, but only perform a task. To use these
methods, just type: ObjectName.MethodName(Arguments)
String Methods
Small Basic offers a powerful set of methods to work with string type
variables, which are very important in Small Basic. These methods are
associated with the Text object.
Perhaps, you just want a far left portion of a string. Use the GetSubText
method with a starting position of 1. This example extracts the 3 left-most
characters from a string: MyString = "Small Basic is fun!"
LeftString = Text.GetSubText(MyString, 1, 3) The LeftString variable is
equal to “Sma”
To get the far right portion of a string, use the GetSubTextToEnd method.
Specify the character to start with and the right portion of the string is
returned. To get 6 characters at the end of our example, you would use:
MyString = "Small Basic is fun!"
RightString = Text.GetSubTextToEnd(MyString, 13) The RightString
variable is equal to “s fun!”
Many times, you want to convert letters to upper case or vice versa. Small
Basic provides two methods for this purpose: ConvertToUpperCase and
ConvertToLowerCase. The ConvertToUpperCase method will convert all
letters in a string variable to upper case, while the ConvertToLowerCase
method will convert all letters to lower case. Any non-alphabetic characters
are ignored in the conversion. And, if a letter is already in the desired case,
it is left unmodified. For our example (modified a bit): MyString = "Read
About Small Basic in 2010!”
A = Text.ConvertToUpperCase(MyString) B =
Text.ConvertToLowerCase(MyString) The first conversion using
ConvertToUpperCase will result in: A = “READ ABOUT SMALL
BASIC IN 2010!”
Each of the Small Basic math functions comes from the Math class. All this
means is that each method name must be preceded by Math. (say Math-dot)
to work properly. The methods and the returned values are:
We single out one math method for its importance. In writing games and
learning software, we use a random number generator to introduce
unpredictability. The Math.GetRandomNumber method is used in Small
Basic for random numbers.
Whenever you need a random whole number (integer) value, use this
method: Math.GetRandomNumber(Limit) This statement generates a
random value that is between 1 and Limit. For example, the method:
Math.GetRandomNumber(5) will generate random numbers from 1 to 5.
The possible values will be 1, 2, 3, 4 and 5.
All of our games will be “hosted” by the Small Basic graphics window. To
put anything in the graphics window, it must be “drawn” there using one of
the many Small Basic graphics methods. Even text has to be drawn! Let’s
take a look at these methods.
The window is Width pixels wide and Height pixels high. We use two
values (coordinates) to identify a single pixel in the window. The x
(horizontal) coordinate increases from left to right, starting at 0. The y
(vertical) coordinate increases from top to bottom, also starting at 0. Points
in the region are referred to by the two coordinates enclosed in parentheses,
or (x, y).
To draw lines and shapes, we use a pen. You can choose color and width.
Lines of code that accomplish this task are: GraphicsWindow.PenColor =
Color GraphicsWindow.PenWidth = Width where Color is the color your
pen will draw in and Width is the integer width (a value of 1 by default) of
the line (in pixels) drawn. This pen will draw a solid line. To specify a
color, you use a color name like “Red”, “White” or “Blue”. Appendix I lists
the multitude of colors available with Small Basic.
The Small Basic DrawLine method is used to connect two points with a
straight-line segment. If we wish to connect the point (x1, y1) with (x2, y2),
the statement is: GraphicsWindow.DrawLine(x1, y1, x2, y2) The line will
draw in the current pen Color and Width. Example that draws a blue line
of width 1: GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 1
GraphicsWindowGraphicsWindow.DrawLine(20, 50, 380, 280) The
Small Basic DrawRectangle method is used to draw a rectangle. To
draw a rectangle, we specify the upper left hand corner’s coordinate (x,
y) and the width and height of the rectangle. To draw such a rectangle in
the graphics window: GraphicsWindow.DrawRectangle(x, y, width,
height) The rectangle will draw with the current pen. To draw a blue
rectangle (pen width 2) with the upper left corner at (20, 50), width 150
and height 100, use this code: GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawRectangle(20, 50, 150, 100) The Small Basic
DrawEllipse method is used to draw an ellipse. To draw an ellipse, we
specify the upper left hand corner’s coordinate (x, y) and the width and
height of the ellipse. To draw such an ellipse in the graphics window:
GraphicsWindow.DrawEllipse(x, y, width, height) The ellipse will draw
with the current pen. To draw a green ellipse (pen width 3) with the upper
left corner at (20, 50), width 150 and height 100, use this code:
GraphicsWindow.PenColor = "Green"
GraphicsWindow.PenWidth = 3
GraphicsWindow.DrawEllipse(20, 50, 150, 100) A brush is like a “wide”
pen. It is used to fill areas with a color. It has a single property (Color).
To set the brush color, use: GraphicsWindow.BrushColor = Color A brush
is ‘solid’ – filling areas completely with the specified color To fill
rectangles and ellipses with the current brush color, use the FillRectangle
and FillEllipse methods. They have the same arguments as
DrawRectangle and DrawEllipse, respectively.
To add text information to the graphics window, we use the Small Basic
DrawText method – yes, text is “drawn” to the window. The DrawText
method is: GraphicsWindow.DrawText(x, y, text) In this statement, text
represents the string to print in the window and the point (x, y) is where the
string will be located. The string will draw in the graphics window using the
current brush color using the default font. Note this method uses the brush
color, not the pen color – text is truly drawn like other graphics objects.
To create a shape with an image, we need two steps. First, we must load the
image, then create the shape. Assume you have jpg image file (a digital
photo) named MyImage.jpg. (You can use other image files types too). The
file with this image must be in the same folder as your Small Basic
program. The image is loaded using the LoadImage method of the
ImageList object: MyImage = ImageList.LoadImage(Program.Directory +
"\MyImage.jpg") Then the image shape (MyImageShape) is created using:
MyImageShape = Shapes.AddImage(MyImage) The shape will be placed in
the upper left corner of the graphics window.
We will see many examples of using Shapes objects in the game programs
we build. We will provide the image files for any Shapes requiring images.
Small Basic Decisions - If Statements
In this case, if Balance - Check is less than zero, two lines of information
are processed: Trouble is set to “true” and the window turns red. Notice the
indentation of the code between the If and EndIf lines. The Small Basic
Intellisense feature will automatically do this indentation. It makes
understanding (and debugging) your code much easier.
Here, the same two lines are executed if you are overdrawn (Balance -
Check < 0), but if you are not overdrawn (Else), the Trouble flag is turned
off and your window is black.
In this block, if Condition1 is “true”, the code between the If and first ElseIf
line is executed. If Condition1 is “false”, Condition2 is checked. If
Condition2 is “true”, the indicated code is executed. If Condition2 is not
true, Condition3 is checked. Each subsequent condition in the structure is
checked until a “true” condition is found, a Else statement is reached or the
EndIf is reached.
Now, one more condition is added. If your Balance equals the Check
amount (ElseIf Balance - Check = 0), you’re still not in trouble and the
screen is yellow.
In Small Basic, one way of looping is with the While loop: While
(Condition) ' Small Basic code block to repeat while Condition is true
EndWhile
In this structure, all code between While and EndWhile is repeated while
the given logical Condition is “true”.
Note a While loop structure will not execute even once if Condition is
“false” the first time through. If we do enter the loop (Condition is “true”),
it is assumed at some point Condition will become false to allow exiting.
Once this happens, code execution continues at the statement following the
EndWhile statement. This brings up a very important point about loops – if
you get in one, make sure you get out at some point. In the While loop, if
Condition is always “true”, you will loop forever – something called an
infinite loop.
Here is an example:
Counter = 1
While (Counter <= 1000) Counter = Counter + 1
EndWhile
This loop repeats as long as (While) the variable Counter is less than or
equal to 1000.
Another example:
Rolls = 0
Counter = 0
While (Counter < 10) ' Roll a simulated die
Roll = Roll + 1
If (Math.GetRandomNumber(6) = 6) Then Counter = Counter + 1
EndIf
EndWhile
This loop repeats while the Counter variable remains less than 10. The
counter variable is incremented (increased by one) each time a simulated
die rolls a 6. The Roll variable tells you how many rolls of the die were
needed to roll 10 sixes. Theoretically, it should take 60 rolls since there is a
1 in 6 chance of rolling a six.
We can build a loop that will always be executed at least once. To do this
we need to introduce the Small Basic Goto statement. A Goto allows you to
transfer code execution to anywhere in your code. A Goto requires a label.
A label is like a bookmark – it can be named anything you want. A label
name is always followed by a colon. An example is: MyLabel: Anytime we
want to transfer program execution to this label statement, we use a Goto:
Goto MyLabel You do not write the colon in the Goto statement.
Using these new concepts in a loop, we have what we’ll call a Goto loop:
MyLabel: ' Small Basic code block to process
If (Condition) Then Goto MyLabel EndIf
The code block repeats as long as Condition is “true”. Unlike the While
loop, this loop is always executed at least once. Somewhere in the loop,
Condition should be changed to “false” to allow exiting.
Let’s look at examples of the Goto loop. What if we want to keep adding
three to a Sum until the value exceeds 50. This loop will do it: Sum = 0
SumLoop: Sum = Sum + 3
If (Sum <= 50) Then Goto SumLoop EndIf
Sum = 0
Roll = 0
SumLoop: ' Roll a simulated die
Die = Math.GetRandomNumber(6) Sum = Sum + Die Roll = Roll + 1
If (Sum <= 30) Then Goto SumLoop EndIf
This loop rolls a simulated die (Die) while the Sum of the rolls does not
exceed 30. It also keeps track of the number of rolls (Roll) needed to
achieve this sum.
You need to decide which of the loop structures (While, Goto) fits your
program. Recall the major difference is that a Goto loop is always executed
at least once; a While loop may never be executed.
And, make sure you can always get out of a loop. In both looping
structures, this means that, at some point, the checking logical condition
must become “false” to allow exiting the loop. When you exit a While loop,
processing continues at the next Small Basic statement after the EndWhile.
In a Goto loop, processing continues at the Small Basic statement after the
If structure checking whether the loop should repeat.
If, at some point in the code block of a loop, you decide you need to
immediately leave the loop or move to another point in the code, a Goto
statement can also do this. You just need a label statement at the appropriate
place. When the Goto statement is encountered, processing is immediately
transferred to the labeled statement.
Small Basic Counting
With While loop structures, we usually didn’t know, ahead of time, how
many times we execute a loop or iterate. If you know how many times you
need to iterate on some code, you want to use Small Basic counting.
Counting is useful for adding items to a list or perhaps summing a known
number of values to find an average.
Small Basic counting is accomplished using the For loop: For Variable =
Start To End Step Increment ' Small Basic code to execute goes here]
EndFor
Example:
Another Example:
Sum = 0
For I = 1 to 100
Sum = Sum + MyValues[I]
EndFor
Average = Sum / 100
This code finds the average value of 100 numbers stored in the array
MyValues. It first sums each of the values in a For loop. That sum is then
divided by the number of terms (100) to yield the average.
You may exit a For loop early using an Goto statement. This will transfer
program control to the corresponding labeled statement, usually the line
after the EndFor.
Small Basic Subroutines
In the looping discussion, we saw how code in one particular block could
be repeated until some desired condition was met. Many times in Small
Basic programs, we might have a need to repeat a certain block of code at
several different points in the program. Why would you want to do this?
Say we had a game that requires us to roll 5 dice and add up their individual
values to yield a sum. What if we needed to do this at 10 different places in
our program? We could write the code, then copy and paste it to the 10
different places. I think you can see problems already. What if you need to
change the code? You would need to change it in 10 different places. What
if you needed to put the code in another place in your program? You would
need to do another ‘copy and paste’ operation. There’s a better way. And
that way is to use a Small Basic subroutine.
A subroutine allows you to write the code to perform certain tasks just once.
Then, whenever you need to access the code in your program, you can “call
it.,” providing any information it might need to do its tasks. Subroutines are
the building blocks of a Small Basic program. Using subroutines in your
Small Basic programs can help divide a complex application into more
manageable units of code. Just think of a subroutine as a code block you
can access from anywhere in a Small Basic program. When you call the
subroutine, program control goes to that subroutine, performs the assigned
tasks and returns to the calling program. It’s that easy.
Let’s see how to create and call a subroutine. Subroutines go at the end of
your ‘main’ program code. A subroutine named MySubroutine would have
the form (starts with a Sub keyword and ends with EndSub): Sub
MySubroutine ' Code to be executed in the subroutine EndSub
You execute, or call, this subroutine using: MySubroutine() The parentheses
are needed to tell the computer you are executing a subroutine. When the
subroutine is called, the corresponding code is executed until the EndSub
line is reached. At this point, program execution returns to the ‘main’ code
after the line calling the subroutine.
A subroutine can access and use any variable you use in your program.
Likewise, your program can use any variables defined in your subroutines.
In computer talk, we say the variables in a Small Basic program have
global scope.
This subroutine is named RollDice and the variable SumDice has the
resulting sum.
Using this subroutine, any time you need the sum of five dice in your
program, you would use: RollDice() A = SumDice After this code is
executed, the variable A will have sum of five dice.
We now have the foundation needed to write code for our programs. We
will begin our first program in Chapter 5, once we have a brief discussion
of debugging Small Basic programs (Chapter 4).
4. Debugging a Small Basic Program
Review and Preview As you begin building projects using
Programming Games With Microsoft Small Basic, you will
undoubtedly encounter errors in your code. In this chapter, we look
at handling errors in projects. After this, we begin building projects
(at last).
Debugging a Small Basic Program No matter how well you plan your
program and no matter how careful you are in implementing your ideas in
Small Basic code, you will make mistakes. Errors, or what computer
programmers call bugs, do creep into your program. You may have already
encountered a few in the programs we’ve built so far. Perhaps you spelled a
keyword wrong, forgot a punctuation mark or misspelled a variable name.
These are all examples of program bugs. You, as a programmer, need to
have a strategy for finding and eliminating those bugs. The process of
eliminating bugs in a program is called debugging. Unfortunately, there are
not a lot of hard, fast rules for finding bugs in a program. Each programmer
has his or her own way of attacking bugs. You will develop your ways. We
can come up with some general strategies, though, and that’s what we’ll
give you here.
Syntax errors occur when you make an error typing a line of Small Basic
code. Something is misspelled or something is left out that needs to be
there. Your program won’t run if there are any syntax errors. Run-time
errors occur when you try to run your program. It will stop abruptly
because something has happened beyond its control. Logic errors are the
toughest to find. Your program will run okay, but the results it gives are not
what you expected. Let’s examine each error type and address possible
debugging methods.
Syntax Errors Syntax errors are the easiest to identify and eliminate. The
Small Basic development environment is a big help in finding syntax errors.
Syntax errors will occur as you’re writing Small Basic code.
Start Small Basic. We’ll type in a few snippets of code to see how different
bugs are identified. Let’s look at some typical errors. In the editor, type
these two lines of code: MyNumber = 7
TextWindow.WriteLine(MyNmber) We’ve misspelled the assigned
variable name (MyNumber) in the WriteLine statement.
Try running this and below the editor you will see the message:
The 2,22 implies there is an error in Line 2, Column 22. It tells you it
does not recognize the variable MyNmber and asks if you misspelled it.
We did. Small Basic is pretty smart!
Correct your error. But, change the first line as shown (leave out the
assignment operator): MyNumber 7
TextWindow.WriteLine(MyNumber) Try running and you’ll get this error
message:
You are being told this (line 1 again) is not a recognized statement and the
problem is somewhere around Column 11. You should immediately see the
problem and be able to fix it. Fix the error.
Let’s try one other example. Change the second line by adding an additional
parenthesis at the end of the WriteLine method: MyNumber = 7
TextWindow.WriteLine(MyNumber)) Try running and you receive this
message:
The problem is clear – you have one too many right parentheses.
So when you try to run with syntax errors, the Small Basic environment
will kindly point out your errors to you so you can fix them. Note that
syntax errors usually result because of incorrect typing, either misspellings,
additions or omissions - another great reason to improve your typing skills,
if they need it.
Run-Time Errors Once you have written your code and eliminated all
identified syntax errors, obtaining a successful compilation, you try to run
your program. If the program runs, great! But, many times, your program
may stop and tell you it found an error - this is a run-time error. You need to
figure out why it stopped and fix the problem. At this writing, the Small
Basic environment does not give you much useful information when a run-
time error occurs. Many times, the program will just stop.
Another common run-time error occurs when using one of Small Basic’s
built-in functions. Errors result if you use the wrong type or value as one of
the arguments. Try these two lines of code: MyNumber = ‐7
TextWindow.WriteLine(Math.SquareRoot(MyNumber)) We attempt to
take the square root of a negative number (not allowed). When we run the
program, we get some indication that something is wrong, but it is not
very explicit:
We’ve seen just a couple of possible run-time errors. There are others and
you’ll see them as you start building programs. And, unfortunately, the
current Small Basic program is not very helpful in pointing out where errors
are. Hopefully, this situation will change with future versions. One last
thing about run-time errors. Small Basic will not find all errors at once. It
will stop at the first run-time error it encounters. After you fix that error,
there may be more. You have to fix run-time errors one at a time.
Logic Errors Logic errors are the most difficult to find and eliminate.
These are errors that don’t keep your program from running, but cause
incorrect or unexpected results. The only thing you can do at this point, if
you suspect logic errors exist, is to dive into your program and make sure
everything is coded exactly as you want it. Finding logic errors is a time-
consuming art, not a science. There are no general rules for finding logic
errors. Each programmer has his or her own particular way of searching for
logic errors.
With the example we have been using, a logic error would be setting a
variable to an incorrect value. Or, perhaps you add two numbers together
when you should have subtracted. Logic errors are mistakes you have
inadvertently introduced into your Small Basic code. And, unfortunately,
these errors are not pointed out to you. Hence, eliminating logic errors is
not always easy.
The first program we build is a Safecracker that asks you to guess a secret
combination of numbers using clues from the computer.
Safecracker Program Preview
The only option you can change is the number of digits in the combination.
I selected 3, then pressed Enter. The graphics window reappears with the
game still in the ‘stopped’ state:
Notice the title bar area now reflects 3 digits in the combination and that
number of digits is shown in the bank safe.
Click Start Game to start playing. Two of the buttons disappear and a
Results area appears on the right of the window. We call this the ‘playing’
state:
In this state, you make a guess at the three digit combination using the
number keys on the keyboard. After each guess, the results of your guess
are displayed in the Results area. You keep guessing until correct or until
you click Stop Game.
Enter a guess; I entered 123:
Continue playing the game to understand its operation. Click Exit when
you’re done to stop the game. Look over the code in the editor if you like.
You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program. This is the approach we will take on
all programs in these notes.
Since this is our first program, let’s look briefly at the idea of game window
design. This is a first step in building a Small Basic game program (or any
program) where you decide what you want to display to the user in the
graphics window. In this window design phase, you need to know what
inputs you need from the user and how you want to show them outputs.
Make initial sketches of where you want certain game elements to appear.
Always have an area to provide messages to the user – messages like how
to start/stop the game and messages on how they are progressing in the
game. Use button controls to perform specific tasks (start, stop, change
options) in your program. In your design, since you are using the graphics
window, make sure you incorporate graphics elements of colors and shapes.
Make the window pleasant to look at and easy to understand. Finalize your
sketch on graph paper to help with positioning parts of the final layout.
Make notes for dimensions and locations of different components.
Translate your sketch to actual Small Basic code to draw the window
elements. With Small Basic, you can make quick changes and see the
results of these changes immediately. The window design process is
iterative – meaning you will always be tweaking certain items until you are
satisfied with your window design. For the games in these notes, we present
our ideas for windows. Feel free to modify them in anyway you choose.
Safecracker Window Design
Here is the sketch for the window layout of the Safecracker game:
We draw a safe on the left side of the window using lines and rectangles.
The combination digits will be displayed in bordered rectangles. A little
‘money bag’ graphic is added. The right side of the window is a blank area
where we will provide information to the user at the appropriate times.
Three button controls will be used: one to start and stop the game, one to
change options and one to exit the program.
We now begin writing code for the Safecracker game program. We will
write the code in several steps. As a first step, we will write the code that
draws the game window and establishes the ‘stopped’ state. We write code
to set game options in a text window. Then, we look at how to go to
‘playing’ state following clicking of the Start Game button. During the
code development process, recognize you may modify a particular
procedure several times before arriving at the finished product.
Before starting, make sure you have established a folder on your computer
for building Small Basic programs. Always save your programs in this
folder. Do not save them in the folder used in these notes
(KidGamesSB\KidGamesSB Programs). Leave this folder intact so you
can always reference the finished programs, if needed.
We see in the sketch that the safe used in the Safecracker game is made up
of rectangles, lines, a heading (BANK) and a little money bag graphic. In
the KidGamesSB\KidGamesSB Programs\Safecracker folder is a file
money.jpg. This is the graphic we will display. It is loaded by the program.
Copy this file to your program’s folder.
'Safecracker
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 650
GraphicsWindow.Height = 400
'Draw bank safe
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(0, 0, 310, 400)
GraphicsWindow.BrushColor = "LightGray"
GraphicsWindow.FillRectangle(25, 25, 260, 350)
GraphicsWindow.BrushColor = "Gray"
GraphicsWindow.FillRectangle(50, 50, 210, 300)
GraphicsWindow.PenWidth = 2
GraphicsWindow.PenColor = "Black"
GraphicsWindow.DrawRectangle(25, 25, 260, 350)
GraphicsWindow.DrawRectangle(50, 50, 210, 300)
GraphicsWindow.DrawLine(25, 25, 50, 50)
GraphicsWindow.DrawLine(285, 25, 260, 50)
GraphicsWindow.DrawLine(285, 375, 260, 350)
GraphicsWindow.DrawLine(25, 375, 50, 350)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 48
GraphicsWindow.DrawText(95, 50, "BANK") MoneyImage =
ImageList.LoadImage(Program.Directory + "\money.jpg")
GraphicsWindow.DrawImage(MoneyImage, 80, 200) EndSub
This code is just a translation of our window sketch into actual code. The
first line of code calls a subroutine InitializeProgram where we will put all
code needed to set up the program for use. All remaining code here goes in
that subroutine. Notice the graphics file (money.jpg) is loaded from the
Program.Directory folder – this is your program’s folder. That’s why we
asked you to copy the file to this particular folder. Notice the line loading
the file is displayed on two lines in these notes due to margin restrictions.
Make sure this is typed on one line in the code editor. Look for similar
occurrences throughout the notes for this course.
Save and Run (click Run in the toolbar) the program. The safe will appear:
If the money bag does not show up, double-check you copied the file into
the same folder holding your program code.
Window Design – Display Combination Digits The combination
entered by the user will be displayed in bordered rectangles on the safe. To
draw these rectangles, we need to know how many digits will be entered.
The variable NumberDigits will be used for this purpose – we give it a
default (beginning value) of 2. This can be changed by the user later when
setting program options.
Add this code at the end of the current code in InitializeProgram: 'Default
Options
NumberDigits = 2
GraphicsWindow.Title = "Safecracker ‐ " + NumberDigits + " Digits in
Combination"
ClearDigits() A value is set for NumberDigits and used in the graphics
window Title to reflect that value.
Save and Run the program. You should now see two blank boxes ready for
digits in the safe. Also, notice the information shown in the title bar area:
Window Design – Results Area
The final item we need in the window is the results area. It is simply a blank
area with a header (Results:) and three button controls used to start/stop the
game, change options and exit the program.
We have three choices at this point – either click Start Game to start, click
Change Options to change options, or click Exit to exit the program. We
will write code for each of these options in reverse order.
First, we need to be able to detect button clicks so next add this line at the
end of InitializeProgram: Controls.ButtonClicked = ButtonClickedSub
With this, each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.
This simply says whenever the ExitButton button is clicked, the program
ends. Note, we only want to detect clicking Exit when the game is stopped,
hence it is place within an If structure. Run the program. Click Exit to
make sure the game stops.
If the user clicks Change Options, we want to provide the ability to change
program options (NumberDigits in this game). In all games in these notes,
we will use the Small Basic text window to establish game options. Add the
shaded code to the ButtonClickedSub subroutine: Sub ButtonClickedSub
B = Controls.LastClickedButton If (GameStatus = "Stopped") Then If (B =
ExitButton) Then Program.End()
ElseIf (B = OptionsButton) Then SetOptions()
EndIf
EndIf
EndSub
The options are set in the SetOptions subroutine – add this routine: Sub
SetOptions GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title
= "Safecracker"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("SAFECRACKER OPTIONS")
TextWindow.WriteLine("") GetInput: TextWindow.CursorLeft = 3
TextWindow.WriteLine("The safe combination can have 2, 3, or 4
digits.") TextWindow.CursorLeft = 3
TextWindow.Write("How many digits do you want?") NumberDigits
= TextWindow.ReadNumber() If (NumberDigits < 2 Or
NumberDigits > 4) Then Goto GetInput EndIf
GraphicsWindow.Title = "Safecracker ‐ " + NumberDigits + " Digits
in Combination"
ClearDigits() TextWindow.Hide() GraphicsWindow.Show() EndSub
This routine hides the graphics window, displays a text window and asks
the user how many digits. Once entered, the program returns to the game in
‘stopped’ state, displaying the entered number of digits.
Save and Run the program. Click the Change Options button to change
options:
Make a choice and press Enter. The Safecracker game window will again
appear.
Right now, we will just implement the first step (setting up the results area).
The other steps, those establishing the secret combination and accepting and
checking user input, will be addressed separately.
Save and Run the program. Change options if you want. Click Start Game
and the game should switch to ‘playing’ state (assumes 2 digits in
combination):
Make sure the number of boxes displayed in the bank area match the
number of digits selected. Notice the single button –Stop Game. Also,
notice clicking this button does nothing. Let’s fix that. Stop the program by
clicking the X in the upper right corner of the window.
Code Design – Playing to Stopped State When the user clicks the
Stop Game button in ‘playing’ state, we want to switch the Safecracker
game back to ‘stopped’ state. The steps are:
We now look for button clicks while playing the game. Clicking Stop
Game calls the StopGame subroutine: Sub StopGame 'restore buttons
GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton) EndSub
Later, we will add code to this routine to report game results.
Save and Run the program. You should be able to now move from
‘stopped’ to ‘playing’ state and back. Make sure you can display 2, 3 or 4
digits in the combination (changing options). Try the Exit button. We can
now look at the three missing steps in the program: generating a secret
combination and accepting and checking user input.
Code Design – Generating Secret Combination A critical step in
the Safecracker program is to generate the secret combination the game
player is trying to guess. Using the options selected, we know the
combination can be from 2 to 4 digits. We have also specified none of the
digits can repeat.
Since repeated digits are not allowed, for each digit in the combination, we
generate a random number from 1 to 9, but only add it to the combination if
it has not been used before. The code snippet that accomplishes this for our
game is: 'Get combination
SecretCombo = ""
For I = 1 To NumberDigits 'select unique digit
UniqueDigit = "false"
While (UniqueDigit = "false") J = Math.GetRandomNumber(9)
UniqueDigit = "true"
If I <> 1 Then For K = 1 To I ‐ 1
If (Text.GetSubText(SecretCombo, K, 1) = J) Then
UniqueDigit = "false"
EndIf
EndFor
EndIf
EndWhile
SecretCombo = Text.Append(SecretCombo, J) EndFor
We’ll step you through this code to see what’s going on. A string variable
(SecretCombo) is used to store the combination. It is initially blank. One
digit at a time (a total of NumberDigits) is added to SecretCombo using
string concatenation.
Add the given snippet to the StartGame subroutine as shown in the shaded
code below: Sub StartGame GameStatus = "Playing"
'clear results area and change buttons GraphicsWindow.BrushColor
= "White"
GraphicsWindow.FillRectangle(320, 30, 330, 370)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Stop Game")
Controls.HideControl(OptionsButton)
Controls.HideControl(ExitButton) ClearDigits()
'Get combination
SecretCombo = ""
For I = 1 To NumberDigits 'select unique digit
UniqueDigit = "false"
While (UniqueDigit = "false") J = Math.GetRandomNumber(9)
UniqueDigit = "true"
If I <> 1 Then For K = 1 To I ‐ 1
If (Text.GetSubText(SecretCombo, K, 1) = J) Then
UniqueDigit = "false"
EndIf
EndFor
EndIf
EndWhile
SecretCombo = Text.Append(SecretCombo, J) EndFor
EndSub
We can now generate a secret combination, but have no way of seeing what
it is. Let’s change that. Many times while developing a program, you want
to check results before the program is complete. This means adding
temporary code just for debugging purposes. Place this line after the
EndFor line in the code generating the combination:
GraphicsWindow.ShowMessage("Combo: " + SecretCombo, "") This will
write the generated combination in a message box allowing you to see if the
combination meets the requirements (proper number of digits and proper
repeating/non-repeating of digits.
Save and Run the program. Click Start Game to start the game. View the
message box to see the generated combination. Make sure it meets the
selected options requirement. Click Stop Game to stop game. Repeat this
process for various combinations (and different numbers of digits) to make
sure the combination is being generated correctly. When done, delete the
debug line from the code.
We’re now ready to accept the player’s guess at the secret combination.
Code Design – Accepting Player Input Once the secret combination
has been generated, the next step is to allow the user to enter his or her
guess at the combination. This is done using the number keys on the
keyboard (or numeric keypad). The steps followed are:
These variables are used to store the combination entered by the user
(EnteredCombo), the number of digits entered (DigitsEntered), the
number of tries to guess the combination (Tries), and the location to print
the results of a guess (ComboX, ComboY).
And, we need to be able to detect key presses so add this line at the end of
the InitializeProgram subroutine: GraphicsWindow.KeyDown =
KeyDownSub With this, each time a KeyDown event occurs, the
subroutine named KeyDownSub is called.
Now, add this code (there is a lot of it) to the KeyDownSub subroutine:
Sub KeyDownSub K = GraphicsWindow.LastKey If (GameStatus =
"Playing") Then N = 0
If (K = "D1" Or K = "NumPad1") Then N = 1
ElseIf (K = "D2" Or K = "NumPad2") Then N = 2
ElseIf (K = "D3" Or K = "NumPad3") Then N = 3
ElseIf (K = "D4" Or K = "NumPad4") Then N = 4
ElseIf (K = "D5" Or K = "NumPad5") Then N = 5
ElseIf (K = "D6" Or K = "NumPad6") Then N = 6
ElseIf (K = "D7" Or K = "NumPad7") Then N = 7
ElseIf (K = "D8" Or K = "NumPad8") Then N = 8
ElseIf (K = "D9" Or K = "NumPad9") Then N = 9
EndIf
If (N = 0) Then Goto LeaveSub EndIf
'if first number in combo, clear out digits boxes If DigitsEntered
= 0 Then ClearDigits() EndIf
'for second digit on, make sure not in code already If
(NumberDigits >= 1) Then For I = 1 To NumberDigits If (N =
Text.GetSubText(EnteredCombo, I, 1)) Then Goto LeaveSub
EndIf
EndFor
EndIf
EnteredCombo = Text.Append(EnteredCombo, N) DigitsEntered
= DigitsEntered + 1
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 48
GraphicsWindow.DrawText(67 + (DigitsEntered ‐ 1) * 50, 120,
N) 'if all digits entered, check combo If (DigitsEntered =
NumberDigits) Then GraphicsWindow.ShowMessage("Combo: "
+ EnteredCombo, "") EndIf
EndIf
LeaveSub: EndSub
Notice we allow the user to press a number on the keyboard or on the
numeric keypad. The pressed digit is the variable N. We have temporarily
display the entered combination in a message box for debug purposes.
Save and Run the program. Make sure the entered combination looks
correct (has the proper number of digits, in the correct order and following
repeatability rules). Let’s complete the game by comparing the player’s
input to the actual combination and displaying the results.
Code Design – Checking Player Input We now have the capability to
generate a secret combination and obtain the player’s guess at that
combination. We need the code that compares the two string variables and
displays the results. If it’s a match, great! If not, we tell the player how
many digits are correct and how many are in the correct position. This is
some of the trickier code.
Once the user has complete their input, we follow these steps:
We have a specific format for the displaying the results to the user. For each
guess, we display three pieces of information: EnteredCode NumberRight
: PositionCorrect EnteredCode is what the user entered. NumberRight is
the number of correct digits in the guess, PositionCorrect is the number of
digits in the correct position. There is room for three sets of results on each
line in the results area.
You should be able to follow the above code. It first counts the number of
correct digits in the user’s input. The code to see if digits are in correct
position just compares each digit (using the GetSubText method) in
EnteredCombo and SecretCombo. All the results are displayed in the
results area. Check how we use ComboX and ComboY to establish the
location for each set of results.
If the entered combination is correct, we just go to the StopGame
subroutine. We need to modify the subroutine a bit to distinguish whether
we called it because the correct combination was guessed or because S was
pressed to stop the game. Add these shaded lines to that routine: Sub
StopGame 'restore buttons
GameStatus = "Stopped"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
Controls.SetButtonCaption(StartStopButton, "Start Game")
Controls.ShowControl(OptionsButton)
Controls.ShowControl(ExitButton)
'write message
ComboX = 330
ComboY = ComboY + 20
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontSize = 16
If (EnteredCombo = SecretCombo) Then
GraphicsWindow.DrawText(ComboX, ComboY, "That's it!! It took
you " + Tries + " tries.") Else
GraphicsWindow.DrawText(ComboX, ComboY, "Game Stopped.
Combination: " + SecretCombo) EndIf
EndSub
Here, if the combination is correct, you are told so. Else, if the game was
stopped by clicking Stop Game, we display the combination to the user.
Save and Run the program. The game is now fully functional. Try playing
it a few times to make sure things are working okay. It still needs just one
more thing.
Code Design – Adding Sounds
The text feedback of the Safecracker game is a bit boring. Let’s snazz it up
a bit by adding sounds. In the KidGamesSB\KidGamesSB
Programs\Safecracker folder are two wav files that can be used for sound.
The file uhoh.wav is an ‘uhoh’ sound we’ll use for incorrect guesses. The
tada.wav file is a celebratory sound we’ll use for correct guesses. These
files will be loaded when the program starts. Copy the two sound files to
your program’s folder.
Like the earlier graphics file, the sound files are loaded from the
Program.Directory folder. Also notice you should always Stop a sound
before you Play it – just in case it’s already playing.
Save and Run the program. You should now have a complete, running
version of the Safecracker game. Have fun playing it! See if you can come
up with some kind of winning strategy. Here’s a game I played using 3 non-
repeating digits. First, I tried 123 (obviously not a good guess) and heard
‘uh-oh’:
The Safecracker game program is now complete. Save and Run the
program and make sure it works as promised. Check that all options work
correctly.
While completing this program, new concepts and skills you should have
gained include:
➢ Add an option so the digits in the combination can repeat. You will
need to modify the code that generates and checks the combination.
You will need to allow the user to enter repeated digits. Do you see
how such an option makes the game easier to play?
➢ To make the game simpler for smaller children, you might like to
have combinations that use fewer than the 9 digits. For example, a
three digit code that only uses the numbers from 1 to 4 would be
much easier to guess. You would need logic to decide which keys to
allow.
➢ After each guess, you might like to provide a hint on how to proceed.
➢ After a correct combination, maybe have more dramatic results.
Perhaps, have the bank graphic disappear and a pile of treasure
appear.
6. Tic Tac Toe Program
Review and Preview
The next program we build is the classic Tic Tac Toe game, where
you try to line up 3 X’s or 3 O’s in a 3 by 3 grid. We’ll develop a two
player version and one where you can play against the computer.
Tic Tac Toe Program Preview
In this chapter, we will build a Tic Tac Toe game. This is purportedly the
first game ever programmed on a computer and one of the first ever
programmed by Bill Gates when he was a teenager. The object of the game
is line up 3 X markers or 3 O markers in a 3 by 3 grid. The markers can run
horizontally, vertically or diagonally. Turns alternate between players. The
version we build here allows two players to compete against each other or
to have a single player compete against a pretty smart computer.
You are given a few questions to choose game options (one or two players
and, if one player, who goes first and how smart you want the computer to
be). Make your choices (pressing Enter after each). For this example, I
selected a one player game, where I go first (giving me X’s) and a smart
computer:
The graphics window reappears with the game still in the ‘stopped’ state.
Notice the title bar area reflects a single player game.
Click the Start Game button to start playing. The button choices change.
The message at the top of the grid says X’s Turn. X always goes first in this
game (whether it’s you, the human player, or the computer). This is the
In this state, you make a mark in the grid by clicking on the desired square.
The computer will then place its mark, making it your turn again. After each
mark, the board is examined for a win or a draw. You keep alternating turns
until there is a win, the grid is full or until you click Stop Game. The game
works the same way for two players, with the two players alternating turns
marking the grid.
Enter a mark; I chose the center square and the computer immediately
placed its mark (an O) in the upper left corner:
I try the lower left corner and the computer blocks me from winning:
I block the computer’s possible win by putting an X in the middle box of
the top row. Then, the computer blocks me with a move to the middle of the
bottom row:
I continued playing (moving to the right of the middle row and, following
the computer’s block, a move to the right of the bottom row) until finally
we ended in a draw:
Looks like the computer is pretty smart! We’ll see how this intelligence is
programmed later. Notice the game returns to its ‘stopped’ state to allow
another game, changing options or to stop the program.
Continue playing the game to understand its operation. Try using the
Random Computer option (the computer just makes random moves
making it easier to beat). Click the Exit button when you’re done to exit the
game. Look over the code in the editor if you like.
You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.
Here is a sketch for the window layout of the Tic Tac Toe game:
A message area is at the top. The game grid (drawn with skinny rectangles)
is below. Identifying numbers are given to the nine boxes in the grid. Three
button controls will be used: one to start and stop the game, one to change
options and one to exit the program.
We now begin writing code for the Tic Tac Toe game. We will write the
code in several steps. As a first step, we will write the code that draws the
window, then starts the game and establishes its ‘stopped’ state. We write
code to set game options in a text window. Then, we look at how to go to
‘playing’ state following clicking of the Start Game button. During the
code development process, recognize you may modify a particular
procedure several times before arriving at the finished product.
Start a new program in Small Basic. Once started, we suggest you
immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Message Area
The first element of the Tic Tac Toe window is the bordered message area
at the top of the window. It is used to inform the user of whose turn it is and
who wins (if there is a win).
The subroutine DisplayMessage writes the message. Add this to your code:
Sub DisplayMessage Shapes.Move(MessageArea, MessageX, 15)
Shapes.SetText(MessageArea, Message) EndSub
Save and Run the program. You should see the initial ‘Game Stopped’
message:
Window Design – Draw Grid
The next element of the game window is the Tic Tac Toe grid. It is drawn
with ‘skinny’ rectangles. Add these lines of code at the end of the
InitializeProgram subroutine: 'draw grid
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(10, 170, 320, 10)
GraphicsWindow.FillRectangle(10, 280, 320, 10)
GraphicsWindow.FillRectangle(110, 70, 10, 320)
GraphicsWindow.FillRectangle(220, 70, 10, 320) Save and Run the
The final item we need are three button controls used to start/stop the game,
change options and exit the program.
This code initializes the options variables. Next, the (x, y) location of the
nine boxes in the grid is established. Lastly, the GameStatus is set to
“Stopped”.
Once again, Save and Run. You’ll see the game in the ‘stopped’ state (using
default properties):
We have three choices at this point – either click Start Game to start, click
Change Options to change options, or click Exit to exit the program. We
will write code for each of these options in reverse order.
First, we need to be able to detect button clicks so add this line at the end of
InitializeProgram: Controls.ButtonClicked = ButtonClickedSub With this,
each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.
The code for exiting is simple. It is placed in the ButtonClickedSub
subroutine: Sub ButtonClickedSub B = Controls.LastClickedButton If
(GameStatus = "Stopped") Then If (B = ExitButton) Then Program.End()
EndIf
EndIf
EndSub
This simply says whenever Exit is clicked, the program ends. Run the
program. Click Exit to make sure the game stops.
If the user clicks Change Options, we want to provide the ability to change
program options. We will use the Small Basic text window to establish
game options. Add the shaded code to the ButtonClickedSub subroutine:
Sub ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =
"Stopped") Then If (B = ExitButton) Then Program.End()
ElseIf (B = OptionsButton) Then SetOptions()
EndIf
EndIf
EndSub
The options are set in the SetOptions subroutine – add this routine: Sub
SetOptions GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title
= "Tic Tac Toe"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("TIC TAC TOE OPTIONS")
TextWindow.WriteLine("") GetPlayers: TextWindow.CursorLeft = 3
TextWindow.WriteLine("With one player, you play against the
computer.") TextWindow.CursorLeft = 3
TextWindow.WriteLine("With two players, you play against a
friend.") TextWindow.CursorLeft = 3
TextWindow.Write("How many players do you want (1 or 2)?")
NumberPlayers = TextWindow.ReadNumber() If (NumberPlayers < 1
Or NumberPlayers > 2) Then Goto GetPlayers EndIf
If (NumberPlayers = 1) Then GetWhoFirst:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can go first or the computer can go
first.") TextWindow.CursorLeft = 3
TextWindow.Write("Who goes first (1‐You, 2‐Computer)?") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto
GetWhoFirst EndIf
If (T = 1) Then YouGoFirst = "true"
Else
YouGoFirst = "false"
EndIf
GetSmart: TextWindow.WriteLine("") TextWindow.CursorLeft =
3
TextWindow.WriteLine("Computer can make random moves or
smart moves.") TextWindow.CursorLeft = 3
TextWindow.Write("What do you want (1‐Random, 2‐Smart)?") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto GetSmart
EndIf
If (T = 2) Then SmartComputer = "true"
Else
SmartComputer = "false"
EndIf
EndIf
SetTitle() TextWindow.Hide() GraphicsWindow.Show() EndSub
This routine hides the graphics window, displays a text window and asks
the user questions necessary to establish the three options
(NumberPlayers, YouGoFirst, SmartComputer). Note, if two players are
selected, there is no need to ask who goes first or how smart the computer
should be. Once the questions are answered, the program returns to the
game in ‘stopped’ state with a new window title.
Save and Run the program. Click the Change Options button the change
options:
Make your choices and press Enter after each. The Tic Tac Toe game
window will again appear.
Here’s what I got for a single player (the only difference is in the title bar):
The code for clicking the Start Game button (to start the game) is much
more complicated. We will build it in several steps. First, we look at
switching the game from stopped to playing state.
Code Design – Stopped to Playing State When the user clicks the
Start Game button in the ‘stopped’ state, several things must happen to
switch the Tic Tac Toe game to ‘playing’ state:
We use two variables to help keep track of where we are in the game. If
XTurn is “true”, it is X’s turn, otherwise it is O’s turn. NumberClicks
keeps track of how many of the grid boxes have been clicked on (9
maximum).
Can you see how the needed steps are implemented in code?
Save and Run the program. Click Start Game and the game should switch
The game is waiting for the first player to click one of the grid locations
(we’ll write code for that soon). Notice clicking Stop Game does nothing at
the moment. Let’s fix that. Stop the program.
Code Design – Playing to Stopped State When the user clicks the
Stop Game button in the two player ‘playing’ state, we want the Tic Tac
Toe game to change to ‘stopped’ state. The steps for this are:
In the Tic Tac Toe two player game, when a player clicks a box in the grid,
we want the proper mark (X or O) to appear. After each mark, we then need
to see if anyone won. If there is no win, and there are still empty locations,
we switch to the next player. Recall, for reference purposes, the nine areas
So, when a box in the game grid is clicked, we follow these steps:
Let’s look at this code. Clicking the graphics window with the mouse will
call this subroutine. The first part of the code determines which grid box
area (if any) was clicked (the variable ClickedBox). If there is already a
mark there (not blank), the subroutine is exited. If blank, another subroutine
(MarkAndCheck) is called to do the actual marking and check for a win.
We use a subroutine for this step because later we will want a way for the
computer to mark the grid when it is the opponent.
Add the subroutine MarkAndCheck to your code (we are not checking for
a win yet): Sub MarkAndCheck NumberClicks = NumberClicks + 1
If (XTurn) Then BoxMark[ClickedBox] = "X"
DrawX() XTurn = "false"
Message = "O's Turn"
MessageX = 115
DisplayMessage() Else
BoxMark[ClickedBox] = "O"
DrawO() XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() EndIf
'check for win ‐ will establish a value for WhoWon CheckForWin() If
(WhoWon <> "") Then Message = WhoWon + " Wins!"
MessageX = 115
StopGame() ElseIf (NumberClicks = 9) Then 'draw
Message = "It's a Draw!"
MessageX = 95
StopGame() EndIf
EndSub
Sub DrawO
'draw blue O at Clicked Box GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 10
GraphicsWindow.DrawEllipse(BoxX[ClickedBox],
BoxY[ClickedBox], 80, 80) EndSub
These routines use thick lines for the X and a thick ellipse for the O.
We also need the CheckForWin subroutine. For now, just use this which
returns a blank for the WhoWon variable: Sub CheckForWin WhoWon =
""
EndSub
Save and Run the program. You should be able to click on each of the grid
locations, placing X’s and O’s there in alternate turns. Once you have filled
all the grid locations, the game will be returned to stopped state. Wins will
not be recognized. Here’s what I got when I tried it:
As expected, the computer completely missed the fact that O (Player 2) got
a Tic Tac Toe!! Let’s fix that. We will modify the CheckForWin
subroutine to determine a value for the WhoWon variable used in the code.
Code Design – Checking For Win The CheckForWin subroutine
examines the playing grid and determines if there is a winner. If so, the win
will be identified and the subroutine will establish a value for WhoWon – it
will hold the marker (X or O) for the winner or a blank if there is no
winner. Let’s establish a strategy for doing this.
So our win logic would be to go through each possible win and see if the
corresponding elements of BoxMark all contain the same mark (X or O,
but not blank). If so, a winner is declared.
Put the modified CheckForWin subroutine in your program (new lines are
shaded): Sub CheckForWin WhoWon = ""
'check all possible for win For I = 1 To 8
For J = 1 To 3
BoxNumber[J] = Text.GetSubText(PossibleWins[I], J, 1)
Mark[J] = BoxMark[BoxNumber[J]]
EndFor
If (Mark[1] = Mark[2] And Mark[1] = Mark[3] And Mark[2] =
Mark[3] And Mark[1] <> "") Then 'we have a winner
WhoWon = Mark[1]
For J = 1 To 3
GraphicsWindow.BrushColor = "Red"
GraphicsWindow.FillRectangle(BoxX[BoxNumber[J]] ‐
5, BoxY[BoxNumber[J]] ‐ 5, 90, 90) ClickedBox =
BoxNumber[J]
If (WhoWon = "X") Then DrawX() Else
DrawO() EndIf
EndFor
EndIf
EndFor
EndSub
This code goes through all the possible wins. If all the marks in a particular
horizontal, vertical or diagonal line match, the marks in that line are
redrawn in a red rectangle and the corresponding winner returned. Study the
code to see how it works. The BoxNumber array holds the indices of the
BoxMark array for each possible win.
Save and Run the program. You and a friend should be able to compete
with wins and draws properly determined. Here is a replay of the game I
tried before (notice the win by O is now declared):
The two player game is now complete. Let’s start looking at how to
implement a one player game versus a computer opponent. We’ll start easy,
just having the computer make random moves (no brains!). This will help
us establish the logic of switching players when the computer is one of
them.
Code Design – Random Computer Moves A big part of allowing the
computer to play against a human (you, the player) is to decide what
“thought processes” to give the computer. We’re allowing two choices: a
random computer and a smart computer. We’ll start by coding up the
random computer. This will get all the logic of implementing computer
moves along with human moves working properly. Then, we’ll move on to
a smart computer, developing a formidable opponent.
And, after a mark is placed by the human player, the computer needs to take
a turn. This logic is in the MarkAndCheck subroutine. The needed
changes are shaded: Sub MarkAndCheck NumberClicks = NumberClicks +
1
If (XTurn) Then BoxMark[ClickedBox] = "X"
DrawX() XTurn = "false"
Message = "O's Turn"
MessageX = 115
DisplayMessage() Else
BoxMark[ClickedBox] = "O"
DrawO() XTurn = "true"
Message = "X's Turn"
MessageX = 115
DisplayMessage() EndIf
'check for win ‐ will establish a value for WhoWon CheckForWin() If
(WhoWon <> "") Then Message = WhoWon + " Wins!"
MessageX = 115
StopGame() ElseIf (NumberClicks = 9) Then 'draw
Message = "It's a Draw!"
MessageX = 95
StopGame() EndIf
If (NumberPlayers = 1 And WhoWon = "") Then If (XTurn = "true"
And YouGoFirst = "false") Or (XTurn = "false" And YouGoFirst =
"true") Then ComputerTurn() EndIf
EndIf
EndSub
With the added code, if there is no win, the computer takes a turn when it
goes first and it’s X’s turn or takes a turn when the human goes first and it’s
O’s turn.
Save and Run the game. Click Change Options to change options. Choose
1 Player, You Go First and Random Computer. Each option requires
entering a 1:
Make sure things work properly, you should see the computer is pretty easy
to beat! Here’s a game I won when I went first:
So how do we make our computer a better Tic Tac Toe player? We try to
imbed choices we would make if we were playing the game. So for the
computer to be a smart player, the programmer needs to be a smart player.
This usually takes practice and study. For the game of Tic Tac Toe, we can
develop a fairly simple, yet very intelligent strategy. Let’s do it.
When it is the computer’s turn, what should its move be? The rules we will
use are (in order of choice):
1. If the computer can win with a move, make that move and the game
is over. So, if there’s a line with two of the computer’s markers and
an empty space, the empty space is the place to mark!
2. If the computer can block with a move, make that move and the
opponent can’t win on the next move. So, if there’s a line with two of
the human player’s markers and an empty space, the empty space is
the place to mark!
3. If there is no possible win or possible block, make a move in this
order: center square, one of the four corner squares, or one of the four
side squares.
I think you see this logic makes sense. You may wonder about Step 3 – why
we choose that particular order. Recall there are 8 possible ways to win in
Tic Tac Toe (3 horizontal, 3 vertical, 2 diagonal). The center square is
needed in 4 of these, any one corner is involved in 3 possibilities, while any
side is involved in just 2 wins. Hence, the order of choices is made on basic
probabilities. Let’s implement this logic in code.
Here is the modified ComputerTurn subroutine that implements this
‘smart’ logic. The changes are shaded: Sub ComputerTurn If
(SmartComputer <> "true") Then 'random logic
'put mark in Nth available square N =
Math.GetRandomNumber(9 ‐ NumberClicks) I = 0
For ClickedBox = 1 To 9
If (BoxMark[ClickedBox] = "") Then I = I + 1
If I = N Then Goto GotMark EndIf
EndIf
EndFor
GotMark: 'put mark in ClickedBox
MarkAndCheck() Else
'smart computer
BestMoves[1] = 5
BestMoves[2] = 1
BestMoves[3] = 3
BestMoves[4] = 7
BestMoves[5] = 9
BestMoves[6] = 2
BestMoves[7] = 4
BestMoves[8] = 6
BestMoves[9] = 8
'determine who has what mark If (YouGoFirst) Then
ComputerMark = "O"
PlayerMark = "X"
Else
ComputerMark = "X"
PlayerMark = "O"
EndIf
'Step 1 (K = 1) ‐ check for win ‐ see if two boxes hold computer
mark and one is empty 'Step 2 (K = 2) ‐ check for block ‐ see if
two boxes hold player mark and one is empty For K = 1 To 2
If K = 1 Then MarkToFind = ComputerMark Else
MarkToFind = PlayerMark EndIf
For I = 1 To 8
N=0
EmptyBox = 0
For J = 1 To 3
BoxNumber[J] = Text.GetSubText(PossibleWins[I], J,
1) Mark[J] = BoxMark[BoxNumber[J]]
If (Mark[J] = MarkToFind) Then N = N + 1
ElseIf (Mark[J] = "") Then EmptyBox =
BoxNumber[J]
EndIf
EndFor
If (N = 2 And EmptyBox <> 0) Then 'mark empty box to
win (K = 1) or block (K = 2) ClickedBox = EmptyBox
MarkAndCheck() Goto LeaveComputerMove EndIf
EndFor
EndFor
'Step 3 ‐ find next best move For I = 1 To 9
If (BoxMark[BestMoves[I]] = "") Then ClickedBox =
BestMoves[I]
MarkAndCheck() Goto LeaveComputerMove EndIf
EndFor
EndIf
LeaveComputerMove:
EndSub
In the ‘smart’ logic, we first find out whether the computer has X or O.
Steps 1 and 2 of the computer logic are done in a For loop with K as index.
In that loop, we go through all the possible wins looking for a line with 2
identical marks and an empty box. For K=1, we look for the computer’s
mark and an empty box – giving the computer a win on the next move. For
K=2, we look for the human’s mark and an empty box – giving the
computer a block on the next move. If neither Step 1 or Step 2 is successful,
we move to Step 3. The next best moves are listed in desired order in the
array BestMoves. In Step 3, we go through this array, finding the first
empty box available and move there.
Save and Run the program. The game is now fully functional. Try playing
it against the computer. You should find it can’t be beat. The best you can
do against the computer is a draw. Before leaving, let’s add a couple of
sounds.
Code Design – Adding Sounds
We know sounds make games a bit more fun. Let’s add a couple to the Tick
Tac Toe game. In the KidGamesSB\KidGamesSB Programs\TicTacToe
folder are two wav files that can be used for sound. The file beep.wav is a
sound we’ll use for games that end a draw. The tada.wav file is a
celebratory sound we’ll use for wins by either player. These files will be
loaded when the program starts. Copy the two sound files to your program’s
folder.
Save and Run the program. You should now have a complete, running
version of the Tic Tac Toe game. Have fun playing it! Again, you will see
the computer can’t be beat. Here’s a game I played against a ‘smart’
computer where I went first, taking the middle square:
I continued playing (moving to the right of the middle row and, following
the computer’s block, a move to the right of the bottom row) until finally
we ended in a draw:
I heard the little beep and the computer’s ready to play again.
Tic Tac Toe Game Program Listing Here is the complete listing of
the Tic Tac Toe Small Basic program: 'Tic Tac Toe
Sub DrawX
'draw blue X at ClickedBox GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 10
GraphicsWindow.DrawLine(BoxX[ClickedBox], BoxY[ClickedBox],
BoxX[ClickedBox] + 80, BoxY[ClickedBox] + 80)
GraphicsWindow.DrawLine(BoxX[ClickedBox], BoxY[ClickedBox] +
80, BoxX[ClickedBox] + 80, BoxY[ClickedBox]) EndSub
Sub DrawO
'draw blue O at Clicked Box GraphicsWindow.PenColor = "Blue"
GraphicsWindow.PenWidth = 10
GraphicsWindow.DrawEllipse(BoxX[ClickedBox], BoxY[ClickedBox],
80, 80) EndSub
While completing this program, new concepts and skills you should have
gained include:
➢ Use images in the grid. With such a change, you could use something
other than X’s and O’s to mark the squares. Try using small digital
photos (jpeg files).
➢ Add better messaging with a computer opponent. As implemented,
the computer quickly makes its move. Perhaps, add a delay (see the
Timer object) and perhaps some color changes in the grid so the
computer has time to tell you where its move will be.
➢ In the current computer logic (Step 3), the computer always picks
corners or sides in the same order. To make things a bit more
unpredictable, add logic so the computer makes corner or side moves
randomly based on the number of corner or side boxes that are
empty.
➢ The computer in this game is pretty smart, but can be made smarter.
Between Steps 2 and 3 in the current computer logic, we could add
another step where the computer would be more aggressive. In this
new step, have the computer search for horizontal, vertical or
diagonal lines with one of its markers and two empty squares. By
choosing one of the empty squares, the computer forces your next
move. Even better is to find a place where with an additional mark,
the computer sets up two wins, making it impossible for you to block
him.
➢ For little kids, maybe the computer is a bit too smart. The random
computer is an option, but goes to the other extreme of maybe not
being smart enough. A change would be to add levels of intelligence
– having the computer use its ‘smart’ logic sometimes and its
‘random’ logic sometimes. To do this, you could generate a random
number from 1 to 100 and based on some threshold, determine
whether to make a smart move or random move. By varying the
threshold, you can make the computer extremely smart or not so
smart. We implement such logic in the next game program, Match
Game.
7. Match Game Program
Review and Preview
In this chapter, we will build a Match Game. Ten pairs of photos are
hidden on a playing board. The object is to find matching pairs. Turns
alternate between players – an extra turn is earned with each match. The
version we build here allows two players to compete against each other or
to have a single player play a solitaire version or compete against the
computer.
There are a few options to choose. First, decide if you want one or two
players. If you choose one player, you next decide if you want to play alone
or play the computer. If playing the computer, as a last choice, you decide
how smart you want the computer to be (the difficulty). For this example, I
chose a one player game against a fairly smart computer:
After making your choices, the graphics window reappears with the game
still in the ‘stopped’ state.
Note the title bar reflects the options choices.
Click the Start Game button to start playing. The button choices change.
The message area says Pick a Box. When playing the computer, you go
first.
In this state, you pick two boxes to see what photos are behind them. If
there is a match, a ‘tada’ sound will be heard, the boxes are removed, your
score incremented and you are given another turn. If there is no match, a
different sound is heard, the boxes are recovered and it becomes the
computer’s turn. Play continues in this manner (alternating turns) until all
the matching photos are found or until Stop Game is clicked. Play is
similar for a two player game, alternating turns between the two people
playing. For a one player game, playing alone, the computer keeps track of
how many tries it takes you to find all 10 pairs of photos.
I selected the first two boxes and see:
It’s Seattle’s baseball field and one of my dogs; nice photos, but not a
match. I hear a ‘boing’ sound and the board returns to it’s covered state. You
will most likely see different photos when you run the game because we are
using random numbers.
It then becomes the computer’s turn. It’s choices are:
It’s two dogs – not a match. But, I recognize one of those dogs.
Picking the second box in the top row and the third box in the second row, I
get a match. The photos are removed, my score is incremented and it’s my
turn again:
The game continues in this same manner, alternating turns between you and
the computer. When there is a match, you or the computer get an additional
turn. I continued playing this game against a pretty smart computer. Once
all the matches were found, the final score was me 6 and the computer 4. I
won!
Notice the game returns to its stopped state to allow another game, change
options or to stop the program by clicking Exit.
Continue playing the game to understand its operation. Try using the two
player game and the one player game where you Play Alone. Or, in the one
player game against the computer, try different levels of difficulty. You will
find at the Hardest level, the computer is nearly impossible to beat. Click
Exit when you’re done to stop the game. Look over the code, if you like.
You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.
Here is a sketch for the window layout for the Match Game program:
The window used in this program is fairly large. We assume the photos you
use for the game are standard 4 x 6 photos, in landscape mode (width is
greater than height). We use 20 rectangular regions to display the photos in
the window. Identifying numbers are given to each box. These rectangles
are 150 pixels wide (BoxW) by 100 pixels high (BoxH) to maintain the
height-to-width ratio of the photos. On the right side of the pictures are
areas to keep score and display messages. Three button controls will be
used: one to start and stop the game, one to change options and one to exit
the program..
We will now begin writing code for the Match Game program. After
writing code for the first two programs, Safecracker and Tic Tac Toe, you
should know there are certain standard steps needed to get a working
program. Since you should be familiar with these steps by now, in
discussing the code for Match Game, we will combine some steps to speed
up the coding process.
We will write the code in several steps. As a first step, we will write the
code that initializes the game. We look at adding photos. Then, we look at
going from ‘stopped’ state to ‘playing’ state and back. During the code
development process, recognize you may modify a particular subroutine
several times before arriving at the finished product.
The first thing we need to do is draw the twenty picture boxes on the left
side of the window. The boxes are initially drawn with a cover graphic. The
file to do this (cover.bmp) is in the KidGamesSB\KidGamesSB
Programs\MatchGame folder. Copy this file to your program’s folder.
Save and Run the program. The boxes should appear nicely arranged:
If the cover graphic does not appear, make sure it is in your program’s
folder.
Window Design – Scores
The next elements to add to the window are the scores with corresponding
heading information. Add this code to InitializeProgram for the headings:
'headings
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
Heading[1] = Shapes.AddText("Player 1") Heading[2] =
Shapes.AddText("Player 2") Shapes.Move(Heading[1], 670, 5)
Shapes.Move(Heading[2], 670, 70) The headings are displayed using two
Shapes objects (Heading[1] and Heading[2]). Then, add the code to
display the scores (Score[1] and Score[2]): 'scores
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(670, 35, 100, 25)
GraphicsWindow.FillRectangle(670, 100, 100, 25)
GraphicsWindow.BrushColor = "Black"
Score[1] = 0
Score[2] = 0
ScoreDisplay[1] = Shapes.AddText(Score[1]) ScoreDisplay[2] =
Shapes.AddText(Score[2]) Shapes.Move(ScoreDisplay[1], 715, 35)
Shapes.Move(ScoreDisplay[2], 715, 100) Similar to the headings, we use
two Shapes objects (ScoreDisplay[1] and ScoreDisplay[2]) placed over
white rectangles to display the scores.
Save and Run. The scores and headings have been added to the window:
Window Design – Message Area
A message area is used to inform the player(s) what to do next. Add this
code to InitializeProgram: 'Draw message area
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FillRectangle(630, 250, 185, 45)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawRectangle(630, 250, 185, 45)
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 18
Message = "Game Stopped"
MessageX = 30
MessageArea = Shapes.AddText(Message) DisplayMessage() The
message to display is Message and its horizontal location is MessageX.
A Shapes object (MessageArea) displays the message in a black
bordered, yellow rectangle.
The subroutine DisplayMessage writes the message. Add this to your code:
Sub DisplayMessage Shapes.Move(MessageArea, 630 + MessageX, 260)
Shapes.SetText(MessageArea, Message) EndSub
Save and Run the program. You should see the initial ‘Game Stopped’
message:
Window Design – Add Buttons
The final item we need are three button controls used to start/stop the game,
change options and exit the program.
Any time we start a program, there are certain initializations that must take
place. Let’s look at the initializations needed in the Match Game. All
initializations are done in the first part of the program code (before any
subroutines).
We want to initialize the program options and use this to update the window
title. The options are the number of players (NumberPlayers), whether a
single player plays alone (PlayAlone) and how difficult you want a game
against the computer to be (Difficulty). Add this code to
InitializeProgram: 'Default Options
NumberPlayers = 2
PlayAlone = "true"
Difficulty = 1
SetTitle() GameStatus = "Stopped"
The option variables are initialized as is the window title based on the
options (using subroutine SetTitle). The GameStatus is set to “Stopped”.
Save and Run the program. You’ll see in the ‘stopped’ state (using default
properties), the Match Game looks like this:
Make sure you see how all these components were created in the code. As
desired, the game initializes in Two Players mode.
We have three choices at this point – either click Start Game to start, click
Change Options to change options, or click Exit to exit the program. We
will write code for each of these options in reverse order.
First, we need to be able to detect button clicks so add this line at the end of
InitializeProgram: Controls.ButtonClicked = ButtonClickedSub With this,
each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.
This simply says whenever Exit is clicked, the program ends. Run the
program. Click Exit to make sure the game stops.
If the user clicks Change Options, we want to provide the ability to change
program options. We will use the Small Basic text window to establish
game options. Add the shaded code to the ButtonClickedSub subroutine:
Sub ButtonClickedSub B = Controls.LastClickedButton If (GameStatus =
"Stopped") Then If (B = ExitButton) Then Program.End()
ElseIf (B = OptionsButton) Then SetOptions()
EndIf
EndIf
EndSub
The options are set in the SetOptions subroutine – add this routine: Sub
SetOptions GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title
= "Match Game"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("MATCH GAME OPTIONS")
TextWindow.WriteLine("") GetPlayers: TextWindow.CursorLeft = 3
TextWindow.WriteLine("With one player, you play alone or against
the computer.") TextWindow.CursorLeft = 3
TextWindow.WriteLine("With two players, you play against a
friend.") TextWindow.CursorLeft = 3
TextWindow.Write("How many players do you want (1 or 2)? ")
NumberPlayers = TextWindow.ReadNumber() If (NumberPlayers < 1
Or NumberPlayers > 2) Then Goto GetPlayers EndIf
If (NumberPlayers = 1) Then Heading[1] = "You"
GetPlayAlone: TextWindow.WriteLine("")
TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can play alone or play the
computer.") TextWindow.CursorLeft = 3
TextWindow.Write("Make your choice (1‐Play Alone, 2‐Play
Computer)? ") T = TextWindow.ReadNumber() If (T < 1 Or T >
2) Then Goto GetPlayAlone EndIf
If (T = 1) Then PlayAlone = "true"
Heading[2] = "Guesses"
Else
PlayAlone = "false"
Heading[2] = "Computer"
GetDifficulty: TextWindow.WriteLine("")
TextWindow.CursorLeft = 3
TextWindow.WriteLine("You can set the game difficulty.")
TextWindow.CursorLeft = 3
TextWindow.Write("Make your choice (1‐Easiest, 2‐Easy, 3‐
Hard, 4‐Hardest)? ") Difficulty = TextWindow.ReadNumber()
If (Difficulty < 1 Or Difficulty > 4) Then Goto GetDifficulty
EndIf
EndIf
Else
Heading[1] = "Player 1"
Heading[2] = "Player 2"
EndIf
SetTitle() DisplayHeadings() TextWindow.Hide()
GraphicsWindow.Show() EndSub
This routine hides the graphics window, displays a text window and asks
the user questions necessary to establish the three options
(NumberPlayers, PlayAlone, Difficulty). Note, if two players are selected,
there is no need to ask if you want to play alone or against the computer. If
playing alone, there is no need to ask how difficult you want the game to
be. Values are established for the score headings. For two players, the two
scoring boxes on the right of the window are headed Player 1 and Player 2.
For one player, the top scoring box is headed You. If playing alone, the
second is headed Guesses. If playing the computer, it is headed Computer.
Once the questions are answered, the program returns to the game in
‘stopped’ state.
Save and Run the program. Click the Change Options button the change
options:
Make your choices and press Enter after each. The Match Game window
will again appear.
Make sure the proper titling information appears based on your choices.
Here’s the window for two players (the default option):
Here’s the window for one player, playing alone:
And, here’s the window for one player, playing the computer:
The code for clicking the Start Game button (to start the game) is much
more complicated. We will build it in several steps. First, let’s look at
adding photos to the game. Then, we look at switching the game from
stopped to playing state.
Code Design – Adding Photos
One neat thing about this game is that you can use your own photos! This
personalizes the game that makes things a lot more fun. You need to select
10 photos (jpg files from your digital camera) that you want to use - make
sure these photos are stored somewhere on your computer. It works best if
they are Iandscape mode (wider than tall). If you don’t have photos to use,
we include ten sample photos in the KidGamesSB\KidGamesSB
Programs\MatchGame folder:
We will use these samples to demonstrate the steps needed to select photos.
And, these photos are used through the rest of this chapter to demonstrate
game play.
To use the sample photos, first copy the ten files to your program’s folder.
Next, find this line in the InitializeProgram subroutine: GameStatus =
"Stopped"
'load images
Photo[1] = ImageList.LoadImage(Program.Directory + "\clara.jpg")
Photo[2] = ImageList.LoadImage(Program.Directory + "\toby.jpg")
Photo[3] = ImageList.LoadImage(Program.Directory + "\Blue hills.jpg")
Photo[4] = ImageList.LoadImage(Program.Directory + "\Sunset.jpg")
Photo[5] = ImageList.LoadImage(Program.Directory + "\Water
lilies.jpg") Photo[6] = ImageList.LoadImage(Program.Directory +
"\Winter.jpg") Photo[7] = ImageList.LoadImage(Program.Directory +
"\spaceneedle.jpg") Photo[8] = ImageList.LoadImage(Program.Directory
+ "\market.jpg") Photo[9] = ImageList.LoadImage(Program.Directory +
"\safeco.jpg") Photo[10] = ImageList.LoadImage(Program.Directory +
"\qwest.jpg") This loads the photos from your program file into memory.
To use your own photos, simply copy them to your program’s folder, then
change the lines of code above to reference your photo file names rather
than the sample files.
Let’s check to make sure the photos loaded in correctly. Add these test lines
of code after the above lines: For I = 1 To 10
GraphicsWindow.DrawResizedImage(Photo[I], BoxX[I], BoxY[I],
BoxW, BoxH) EndFor
This code displays the ten photos in the first 10 rectangular photo boxes.
Save and Run the program. The photos should appear. If they don’t, make
sure they are in your program’s folder and the file names match the code.
Here are the samples:
We’re nearly ready to begin looking at the code behind the Start Game
button. A key step in starting this game is to ‘hide’ two copies of each photo
behind the 20 picture boxes. There are 10 photos, represented in the array
Photo, with indices from 1 to 10. We want to randomly place two copies of
each index in another array (with 20 elements). The elements of this second
array tell us which photo is behind which picture box. We need some way to
shuffle integer indices around. This is actually a very common game task
which can be used for shuffling cards, selecting multiple choice answers, or
here to hide photos. We will build a subroutine to perform this task.
Code Design – Integer Shuffling
We perform what is called a “one card shuffle.” In a one card shuffle, you
pull a single card (at random) out of the deck and lay it aside on a pile.
Repeat this 52 times and the cards are shuffled. Try it! I think you see this
idea is simple, but doing a one card shuffle with a real deck of cards would
be awfully time-consuming. We’ll use the idea of a one card shuffle here,
with a slight twist. Rather than lay the selected card on a pile, we will swap
it with the bottom card in the stack of cards remaining to be shuffled. This
takes the selected card out of the deck and replaces it with the remaining
bottom card. The result is the same as if we lay it aside.
You should be able to see each step of the shuffle subroutine. This
subroutine is general (sorting N integers) and can be used in other programs
requiring random lists of integers.
Let’s look at an example of how this works. If I run this snippet of code
through a little example, the 20 elements of PhotoIndex computed in one
particular call to NRandomIntegers are (arranged like our photo boxes):
You should see all the integers from 1 to 20. Now, subtracting 10 from each
value greater than 10 yields:
How do we know what photo is behind what picture box? Recall the 20
boxes are identified by these values:
Say we have a picture box, represented by index I. To determine the photo,
examine PhotoIndex[I]; call this value J. The photo behind this picture box
is then Photo[J], element J of the array holding the 10 photos being used.
To display this photo, the proper line of code is:
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[I]], BoxX[I],
BoxY[I], BoxW, BoxH) We can now use the shuffling function to start
building the code behind clicking the Start Game button to start.
Code Design – Stopped to Playing to Stopped State In the
Safecracker and Tic Tac Toe programs, we used the same button
(StartStopButton) to both start and stop the game. That is also the case
here. We will look at the code to both start and stop the game.
When the user clicks the Start Game button in the ‘stopped’ state, several
things must happen to switch Match Game to ‘playing’ state:
Conversely, when the user clicks the Stop Game button in ‘playing’ state,
these things must happen to switch Match Game to ‘stopped’ state:
First, let’s look at the code to start the game. We use several variables to
help keep track of where we are in the game. PhotosRemaining tells us
how many photos are still hidden, while the Score array holds the two
players scores (number of matched photos found). The PhotoFound array
tells us whether a photo behind the corresponding picture box has been
uncovered (so it can’t be clicked twice). PlayerNumber tells us whose turn
it is and ChoiceNumber tells whether it is the player’s first choice on the
playing board or second choice. The Choice array holds the indices of the
two picture boxes selected. CanClick is used to determine if it’s okay to
click on the picture boxes. It is “true” when playing, “false” (the initial
value) when stopped. We use this to make sure only two boxes are clicked.
The steps follow should be clear. Note especially where the “shuffling”
routine was used to form the PhotoIndex array.
Save and Run the program. Click Start Game and you should see:
The only noticeable changes are the two player message in the message
area (Player 1, Pick a Box) and the single button. Stop the program (you
can’t click Stop Game to stop yet) and try the other options if you’d like.
Save and Run the program. You should be able to now move from
‘stopped’ to ‘playing’ state and back. Let’s write the code for the two player
game, first looking at how to display a photo following a click on a picture
box.
Code Design – Displaying Photos
In the Match Game two player game, when a player clicks a picture box in
the window, we want the proper photo to appear. After clicking a second
box, another photo is displayed and we see if there is a match. If there is a
match, the photos are removed and the player is given another turn. If there
is no match, the photos are hidden again and we switch to the next player.
The first part of the code determines which picture box (if any) was clicked
(the variable BoxNumber). If it was already clicked, the subroutine is
exited. If an acceptable value, another subroutine (ShowPhotoAndCheck)
is called to show the picture and check for a match.
I know this is a lot of code to throw at you at once, but it’s simply a
straightforward implementation of the listed steps. Now that you’re
becoming a great game programmer, you should be able to follow the logic.
It’s similar to that used in the Tic Tac Toe game. Clicking any of the twenty
picture boxes used to display photos will invoke this subroutine. The first
part of the code determines the index of the picture box that was clicked
(the variable BoxNumber). If the box has already been clicked (or
CanClick is “false”), the subroutine is exited. Otherwise, the photo behind
the selected box (Photo[PhotoIndex[BoxNumber]]) is displayed. If this is
the first choice (ChoiceNumber = 1), we tell the player to pick again (using
the message area).
Following display of the second choice, we look to see if the two selections
match. The selected boxes are stored in the Choice array. If there is a
match, the photos are removed, a sound is played and we check to see if all
the photos have been selected. If photos remain, the same player is given
another turn. Similarly, for no match, a sound is heard, the photos are
recovered and players are swapped.
All of this code is for a two player game. Notice, however, we have left
“hooks” (represented by comment statements) for later modifications for a
one player game. It looks like everything should work just fine. Run and
Save the program. Click on one picture box. The photo should display.
Here’s my screen:
When you click on a second box, the picture doesn’t display, but the results
are still determined and play switches to Player 2. What happened?
We take a second approach – using the Timer object. This object allows us
to delay processing code (the code is in a subroutine tied to the Timer Tick
event) an amount of time specified by the Timer Interval property. Let’s
make the necessary changes. Once it’s time to display the second picture
box, we will delay for one seconds (1000 milliseconds).
At the top of the TickSub subroutine, add this line turning off the timer
before processing the code: Timer.Pause() To review what we’ve done.
Once it’s time for the second choice of picture, we turn on the timer object.
One second (1000 milliseconds) later, the timer is turned off and the code in
TickSub is executed. This delay allows all pictures to be properly
displayed.
Save and Run the program again. You and a friend should now be able to
play a two player version of Match Game with all pictures appearing
nicely. When a match is found, you will hear a ‘tada’ sound and the photos
will disappear. When no match is found, you will hear a ‘boing’ sound and
the photos will be recovered. When done, you’ll hear a crowd saying
“wow”. Give it a try. I played a two player game by myself. Here’s the
window after five matches have been found (3 by Player 1, 2 by Player 2)
and one box has been uncovered:
Playing the game to completion, the window looks like this, where we
could now select other options and play again:
Player 2 wins! Actually, I was Player 1 and Player 2. In such a case, when
you don’t have a playing partner, it’s fun to play alone or play the computer.
Let’s code up those options now.
Code Design – One Player, Solitaire Game
If the One Player, Play Alone options are selected in Match Game, a
single player tries to find matching photos on the playing form. The
computer keeps track of how many guesses it takes until all matches have
been found.
The steps in the one player, solitaire game following a click on a photo box
are:
Save and Run the game. Change the options to One Player and Play
Alone. Click Start Game to start the game. Here’s the first box I
uncovered:
From here on, you just keep uncovering photos. The computer keeps track
of how many guesses (photos uncovered) it took you to find all the
matches. Here’s the form once I finished (I did do okay – it took me 46
guesses):
Now, let’s see how to change the game to play against the computer.
Code Design – Computer Moves
For Match Game, we will still develop logic for a random choice
(minimum intelligence) and a smart choice (maximum intelligence) by the
computer. To give graduated levels of intelligence, we will decide how
often we want the computer to make a random choice versus how often it
will make a smart choice. That graduated level of intelligence is set as the
Difficulty variable when changing options.
The Difficulty variable can have one of four values: 1-Easiest, 2-Easy, 3-
Hard and 4-Hardest. We will set some rules for intelligence at each level.
Feel free to change these if you’d like. These rules establish what
percentage of computer moves are random and what percentage are smart.
Obviously lower levels of intelligence will have more random choices. The
rules selected are:
So even at the highest level of difficulty, we allow that the computer can
make a mistake.
In this code, if it’s the first choice (ChoiceNumber = 1), we decide whether
we have a smart computer for both computer selections. This is done by
establishing a Threshold (from 1 to 100) based on difficulty. The higher the
threshold, the smarter the computer. We then generate a random number
from 1 to 100. If this number is less than or equal to the threshold, we use a
smart computer (SmartComputer is “true”). In such a case, the
BoxNumber will be found using the SmartChoice subroutine (which has
no code yet). If SmartComputer is “false”, we obtain BoxNumber from
the RandomChoice subroutine (also empty). Once, we know BoxNumber,
we simulate a click on that box by calling the ShowPhotoAndCheck
subroutine.
The framework is in place. If you trying running the game, the Two Player
and One Player, Play Alone options will still work. Playing against the
computer will not work because we need code for the RandomChoice and
SmartChoice subroutines. We’ll do RandomChoice first.
Code Design – Random Computer
For random moves, the computer will simply choose (at random) one of the
available picture boxes in the window. This code is very similar to the
random move code for the Tic Tac Toe game.
We can test our random logic, but there’s one problem. If (in
ComputerTurn) we select a smart computer, there is no code in the
corresponding subroutine (SmartMove). To make things work, add this one
line of code to the SmartMove subroutine: Sub SmartChoice
RandomChoice()
EndSub
We’re simply making the smart computer be random (temporarily) to allow
testing of the computer move logic.
Save and Run the Match Game program. Select the One Player, Play
Computer options. Difficulty doesn’t matter since all code is random at the
moment. Click Start Game to start. You go first, trying to find matching
photos. Once it’s the computer’s turn, notice two things. First, the photos
are uncovered (in pairs) randomly, very seldom do they match. Second, the
photos appear and disappear fairly quickly.
Here’s another case where want to slow things down a bit. Since the
graphics appear okay, we can use the Small Basic Delay method here. Put
this line at the top of the ComputerMove subroutine: Program.Delay(1000)
This implements a one second delay before generating a computer move.
As mentioned earlier, sometimes the Delay method works okay, sometimes
not.
Save and Run the game again. As options, select One Player and Play
Computer. Again, Difficulty does not matter. Start the game (click Start
Game). You can now play against a random computer. You’ll see the
computer is not that smart, making it pretty easy for you to win. We’ll fix
that next by coding up a far more intelligent and formidable computer
opponent. Here’s a game I played (the computer did find one match!):
Code Design – Smart Computer
So how can we make the computer a better Match Game opponent? Well,
we could cheat! Since the computer generated the random numbers to hide
the photos behind the picture boxes, the computer knows where everything
is. Once it’s the computer’s turn, it could just go through that list and find
all the matching pairs. You could never win. Obviously, not a good
approach.
The approach we’ll take is to give the computer perfect memory. In other
words, once a photo has been uncovered, the computer will remember
where that photo is. Then, when the computer has a turn (as a smart
computer), it will search its memory for matches. If it finds a match, it will
take it. First, let’s code the memory.
We use an array (Memory) that stores the indices of photos behind the 20
picture boxes as each photo is uncovered. A zero value means the photo
behind the picture box has not yet been uncovered.
The values in the Memory array are set and reset in the
ShowPhotoAndCheck and TickSub event subroutines. The needed
changes are shaded: Sub ShowPhotoAndCheck 'one player/solitaire game
If (NumberPlayers = 1 and PlayAlone) Then Score[2] = Score[2] + 1
UpdateScores() EndIf
'show image behind selected Photo box (BoxNumber)
GraphicsWindow.DrawResizedImage(Photo[PhotoIndex[BoxNumber
]], BoxX[BoxNumber], BoxY[BoxNumber], BoxW, BoxH)
PhotoFound[BoxNumber] = "true"
Memory[BoxNumber] = PhotoIndex[BoxNumber]
If (ChoiceNumber = 1) Then Choice[1] = BoxNumber
ChoiceNumber = 2
If (NumberPlayers = 2) Then Message = "Player " +
PlayerNumber + ", Pick Another"
MessageX = 5
DisplayMessage() Else
'one player logic
If (PlayerNumber = 1) Then Message = "Pick Another Box"
MessageX = 25
DisplayMessage() Else
'play computer logic
Message = "Picking Another"
MessageX = 30
DisplayMessage() ComputerTurn() EndIf
EndIf
Else
CanClick = "false"
Timer.Resume() EndIf
EndSub
Now, how do we use the Memory array to make a smart move? The rules
we will use for the computer’s two choices are:
This routine does a simple comparison of all picture boxes looking for
matching non-zero values in the Memory array.
Save and Run the program. The game is now fully functional. Try playing
it against the computer with the Hardest difficulty. You should find it is
very hard to beat. Continue playing seeing how the various levels of
difficulty do indeed adjust the computer’s intelligence. Here’s a game I
played with Hard (Level 3) difficulty. I selected the first two boxes and see:
It’s Seattle’s baseball field and one of my dogs; nice photos, but not a
match.
It then becomes the computer’s turn. It’s choices are:
It’s two dogs – not a match. But, I recognize one of those dogs.
Picking the second box in the top row and the third box in the second row, I
get a match. The photos are removed, my score is incremented and it’s my
turn again:
Once all the matches were found, the final score was me 6 and the computer
4. I won!
Match Game Program Listing
Here is the complete listing of the Match Game Small Basic program: '
Match Game
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 825
GraphicsWindow.Height = 530
GraphicsWindow.BackgroundColor = "LightSkyBlue"
'initialize box locations with covers
Cover = ImageList.LoadImage(Program.Directory + "\cover.bmp")
BoxW = 150
BoxH = 100
x=5
y=5
For I = 1 To 20
BoxX[I] = x BoxY[I] = y
GraphicsWindow.DrawResizedImage(Cover, BoxX[I], BoxY[I],
BoxW, BoxH) x = x + BoxW + 5
If (x > 4 * BoxW) Then x = 5
y = y + BoxH + 5
EndIf
EndFor
'headings
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
Heading[1] = Shapes.AddText("Player 1") Heading[2] =
Shapes.AddText("Player 2") Shapes.Move(Heading[1], 670, 5)
Shapes.Move(Heading[2], 670, 70) 'scores
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(670, 35, 100, 25)
GraphicsWindow.FillRectangle(670, 100, 100, 25)
GraphicsWindow.BrushColor = "Black"
Score[1] = 0
Score[2] = 0
ScoreDisplay[1] = Shapes.AddText(Score[1]) ScoreDisplay[2] =
Shapes.AddText(Score[2]) Shapes.Move(ScoreDisplay[1], 715, 35)
Shapes.Move(ScoreDisplay[2], 715, 100) 'Draw message area
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FillRectangle(630, 250, 185, 45)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 2
GraphicsWindow.DrawRectangle(630, 250, 185, 45)
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 18
Message = "Game Stopped"
MessageX = 30
MessageArea = Shapes.AddText(Message) DisplayMessage() 'define
buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
StartStopButton = Controls.AddButton("Start Game", 630, 410)
OptionsButton = Controls.AddButton("Change Options", 630, 450)
ExitButton = Controls.AddButton("Exit", 630, 490) 'Default Options
NumberPlayers = 2
PlayAlone = "true"
Difficulty = 1
SetTitle() GameStatus = "Stopped"
'load images
Photo[1] = ImageList.LoadImage(Program.Directory + "\clara.jpg")
Photo[2] = ImageList.LoadImage(Program.Directory + "\toby.jpg")
Photo[3] = ImageList.LoadImage(Program.Directory + "\Blue hills.jpg")
Photo[4] = ImageList.LoadImage(Program.Directory + "\Sunset.jpg")
Photo[5] = ImageList.LoadImage(Program.Directory + "\Water
lilies.jpg") Photo[6] = ImageList.LoadImage(Program.Directory +
"\Winter.jpg") Photo[7] = ImageList.LoadImage(Program.Directory +
"\spaceneedle.jpg") Photo[8] = ImageList.LoadImage(Program.Directory
+ "\market.jpg") Photo[9] = ImageList.LoadImage(Program.Directory +
"\safeco.jpg") Photo[10] = ImageList.LoadImage(Program.Directory +
"\qwest.jpg") Controls.ButtonClicked = ButtonClickedSub
GraphicsWindow.MouseDown = MouseDownSub Timer.Interval = 1000
Timer.Pause() Timer.Tick = TickSub EndSub
The Match Game program is now complete. Save and Run the program
and make sure it works as promised. Check that all options work correctly.
While completing this program, new concepts and skills you should have
gained include:
There are several ways to improve the Match Game program. Some
possibilities are:
➢ Design a tool that allows for selection of photos used in the game.
This requires some advanced skills. Your tool would write a file with
the name of the 10 photos to use (and their location). Then when
Match Game begins, it would open that file and automatically load
the files. Reading and writing to files is briefly covered in our last
game program.
➢ Make the number of photo boxes adjustable for an added difficulty
adjustment (fewer boxes for little kids).
➢ Add additional levels of difficulty by having finer adjustments on the
threshold between random and smart computer moves.
➢ As written, a player could theoretically find all ten pairs without
giving the other player a chance. Perhaps, rewrite the game so a
player only gets one extra turn after a match.
➢ The computer in this game is pretty smart, but it can be smarter. How
you ask? If the computer uncovers a photo that has no match, its next
choice could be a photo that’s already been uncovered. This would
not give the computer any more information about hidden photos, but
it also does not give you, the opponent, any needed information
either.
8. Pizza Delivery Program
Review and Preview
The program teaches mental math, logical thinking skills and good business
practices. We’ll see how to use a Timer to control many events.
Pizza Delivery Program Preview
In the message area under the orders, you are told the current location of the
car in the grid. At the beginning of the program, the car is at the pizza parlor
(marked by an X on the grid). You are shown how many pizzas are baked
and ready and how many are in the car. To load pizzas in the car, click the
Load button. To tell the car where to go, click on the grid position. The car
will travel to the desired position. When it arrives, the car's horn will sound
and tell you the result of the delivery. There are four possible results: (1)
on-time delivery, (2) late delivery, (3) not enough pizzas in the car to make
the delivery, or (4) no pizza ordered at the given location. If you make a
successful delivery, the amount of sales (displayed at the top of the
window) is updated. When you need to return to the pizza parlor to load
more pizzas, click the location marked by X.
You also need to control the pizza oven to make sure there are always
pizzas available for delivery. To bake pizzas, click Add Pizza for each
pizza you want to bake (pizzas can’t be taken out once they’re in). When
the oven is loaded, click Bake Pizza. You will be told when the pizzas are
ready. When the pizzas are done, a bell will ring and the pizzas are moved
to the ready area. The Baked box always displays how many pizzas are
available for loading into the car. At any time during the program, you may
pause the action by clicking Pause Game. To restart, click Restart Game.
To stop the program before 11:00, click Stop Game. Once the program
stops, a summary screen will show your sales and costs results and compute
your profits (if any). After reading the results, press Enter.
This may seem like lots of instructions but the process becomes fairly
obvious as you play the game. Run the program (press <F5>). The game
will appear in its ‘stopped’ state and the delivery grid will appear. At this
point, you simply click Start Game to get things going. There are no
options to select. The randomness inherent in the Pizza Delivery game
makes each new game a different experience. Once the game starts, the first
thing you notice is the phone starts ringing with orders. Here’s my window
after a couple of orders have come in:
At 6:06, an order for 1 pizza was taken for delivery to Row 6, Column N
(also marked on grid). At 6:09, 5 pizzas were ordered at 12 H.
Right now, I don’t have pizzas to deliver. The game starts with 8 pizzas
ready to go. If I click Load (the car can only be loaded at the pizza parlor),
those pizzas are put in the car. Then, if I click 8 K on the grid, my car goes
there, beeps and makes a delivery. Then, I see:
The pizza was delivered on-time and I made $10. Another order came in
while I was traveling. Next, I deliver 5 pizzas to 12 H, followed by 2 pizzas
at 10 J. At that point, I am out of pizzas. I click the X mark at 19 D to return
to the pizza parlor.
So, in Pizza Delivery, you keep baking pizzas, loading the car and sending
the pizzas out to the waiting deliveries. Late deliveries are penalized and if
you’re too late, the customer gives up and cancels the order – just like the
real world. After playing for a little over an hour, my window looks like
this:
I’ve got lots of orders and lots of pizzas going. The customer at 10 S has
been waiting a while (noted by the red grid background). I need to rush
those pizzas out.
I ran Pizza Delivery until a little after 9 o’clock (closing before the usual
11:00).
Looking at the window, I still had lots of deliveries to make and lots of
wasted pizza. I probably could have made a lot more money in the last two
hours.
At that point, I clicked Stop Game and the following text window
appeared:
I did okay, netting $200.30
Continue playing the game to understand its operation. Try playing all the
way to 11:00 to see how much money you can make. Orders stop at 10:30
to allow you to finish deliveries. Click Exit when you’re done to stop the
game. Skim over the code, if you like.
Simulations like Pizza Delivery are lots of fun. You get to see how your
decisions affect your bottom line – net profits. And, programming such
simulations are fun too – you get to make the rules to try to make the
program realistic. As we build this program, we’ll discuss such rules in
detail. You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.
We address window design. We discuss the code needed to build both the
delivery window (a graphics window) and the results window (a text
window). For the delivery window, we will show you how to draw the
delivery grid and establish initial conditions. And, we address code design.
We discuss how to implement the various aspects of the game: running the
clock, establishing phone orders, running the pizza oven, storing pizzas,
loading the car, moving the car and seeing delivery results. We will see how
to display a fixed sized list of items (the orders), how to handle multiple
events with a single timer object.
Pizza Delivery Window Design
Here is a sketch for the window layout for the Pizza Delivery program:
The delivery grid is sketched on the left. The clock and sales values are at
the top right. Under that is a box to list orders and car location/status. Under
that is the pizza oven (with two button controls) that shows pizzas baking in
the oven. Next is a display for the number of baked pizzas. Then, a display
of the number of pizzas in the car (with a button to load the car). Two
button controls complete the design: one to start, pause and restart the game
and one to stop a game or exit the program.
We will now begin writing code for the Pizza Delivery program. We will
write the code in several steps. As a first step, we will write the code the
defines the delivery grid and other window components. Then, the code that
initializes the game. Then, we add additional elements to the game, one at a
time. During the code development process, recognize you may modify a
particular procedure several times before arriving at the finished product.
Start a new program in Small Basic. Once started, we suggest you
immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Building Delivery Grid
For the Pizza Delivery game, we want a delivery grid that looks like this:
Notice we have labeling information for the columns and rows and a 20 x
20 grid used to display orders. Individual elements in the grid are referred
to by a row number and a column letter. We will build this grid using 441
(21 x 21) rectangles. Let’s see how to do this.
We will use the 0th elements of these arrays to represent the row and column
labels. We ignore the [0][0] elements.
Use this code to establish the delivery grid and its labels: ' Pizza Delivery
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 715
GraphicsWindow.Height = 520
GraphicsWindow.Title = "Pizza Delivery"
'draw new delivery grid
DrawGrid()
EndSub
Save and Run the program. Like magic, you should see the grid:
We will now begin writing the remaining code for the game. We will write
the code in several steps. As a first step, we will finish writing the code
draws the window.
Window Design – Clock and Sales Display
The first elements on the right side of the window are the display areas for
the clock and sales information. Add this code to the InitializeProgram
subroutine: 'draw clock and sales
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 5, 100, 60)
GraphicsWindow.FillRectangle(610, 5, 100, 60)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
GraphicsWindow.DrawText(510, 5, "Time")
GraphicsWindow.DrawText(615, 5, "Sales") ClockTime = "6:00"
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
TimeDisplay = Shapes.AddText(ClockTime) Shapes.Move(TimeDisplay,
535, 30) TotalSales = 0
'format as $0.00
Amount = TotalSales FormatAmount() SalesDisplay =
Shapes.AddText(AmountText) Shapes.Move(SalesDisplay, 620, 30) We
draw the headings, initialize a couple of variables (ClockTime and
TotalSales) and display them using the two Shapes objects TimeDisplay
and SalesDisplay.
Notice how we separate an Amount into its Dollars and Cents, then
properly display them in a text variable (AmountText).
Save and Run the program. You will now see the Time and Sales
displayed:
Window Design – Message Area
Under the Time and Sales displays are two boxes that will be used to
display orders and messages about car location. Initially, they are just blank
rectangles. Add this code to InitializeProgram: 'draw message area
GraphicsWindow.BrushColor = "LightYellow"
GraphicsWindow.FillRectangle(505, 190, 205, 50)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(505, 190, 205, 50)
GraphicsWindow.DrawRectangle(505, 70, 205, 120) Save and Run to
see the message area:
Window Design – Pizza Oven
The pizza oven is used to manage the pizza baking process. It is rectangular
and has two buttons to control adding pizzas and baking pizzas. Add this
code to InitializeProgram: 'draw pizza oven
DrawBlueOven() 'add pizza button
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
AddPizzaButton = Controls.AddButton("Add Pizza", 510, 380)
Controls.SetSize(AddPizzaButton, 95, 33) 'bake pizza button
BakePizzaButton = Controls.AddButton("Bake Pizza", 610, 380)
Controls.SetSize(BakePizzaButton, 95, 33) The oven is drawn in its
initial condition (off and blue in color) using DrawBlueOven: Sub
DrawBlueOven 'draw pizza oven
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 245, 205, 170)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(510, 245, "Oven Off") EndSub
Save and Run to see the cold oven with its two buttons (AddPizzaButton
and BakePizzaButton):
Window Design – Pizza Loading Boxes
Under the oven are two message areas that inform the player of how many
pizzas are baked and how many are in the car. The car box also has a button
control for loading the car. Add this code to InitializeProgram: 'draw pizza
loading boxes
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 420, 70, 60)
GraphicsWindow.FillRectangle(580, 420, 130, 60)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(510, 420, "Baked")
GraphicsWindow.DrawText(585, 420, "Pizzas in Car") PizzasReady = 0
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = 20
PizzasReadyDisplay = Shapes.AddText(PizzasReady)
Shapes.Move(PizzasReadyDisplay, 535, 445) PizzasInCar = 0
PizzasInCarDisplay = Shapes.AddText(PizzasInCar)
Shapes.Move(PizzasInCarDisplay, 615, 445) 'load button
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
LoadButton = Controls.AddButton("Load", 660, 445)
Controls.SetSize(LoadButton, 45, 33) This code initializes a couple of
variables (PizzasReady and PizzasInCar) and displays them using
PizzasReadyDisplay and PizzasInCarDisplay: Save and Run the
program. The new information (with the new button, LoadButton)
displays appear:
Window Design – Remaining Buttons
The Pizza Delivery game uses several buttons. We have already added the
two used in the pizza oven and the button used to load the car. There is also
a button to start, pause, and restart the game, and one to stop the game and
exit the program. Let’s add these.
Any time we start a program, there are certain initializations that must take
place. We have already initialized a few variables (ClockTime, TotalSales,
PizzasReady, PizzasInCar) while building the window. Let’s look at
additional initializations needed in the Pizza Delivery game. All
initializations are done in the first part of the program code (before any
subroutines).
When initialized, we need to make sure the only thing a user can do is click
on Start Game or Exit. They should not be able to operate the pizza oven
or load the car. Add these lines of code to InitializeProgram (after code
creating buttons) to hide the pizza oven buttons and the button to load the
car. We also set GameStatus is set to “Stopped”:
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) GameStatus = "Stopped"
Save and Run the program making sure the oven and car loading buttons
are hidden:
We now begin adding other elements to our simulation, one at a time. We
add code for running the clock, accepting phone orders, running the pizza
oven, loading the car, moving the car and evaluating the deliveries. Each
element will require certain “tuning” parameters – values that define how
the simulation works. Every simulation has such parameters. These are
constants you adjust as you define the program. In the code here, we give
you values of such constants we use. Feel free to change them as you
choose.
Code Design – Clock
The first element we add to the Pizza Delivery program is the clock that
keeps track of time. Recall the clock starts at 6:00 and stops at 11:00. We
don’t want the game to actually last five hours, so we speed things up a bit.
We need to decide how fast we want the five hours to really go by and still
be able to play the game. This is one of the tuning parameters we discussed.
The clock is controlled by the Timer object. Recall this object generates a
Tick event every Interval (a Timer property) milliseconds. We want to
determine how many milliseconds should elapse for each minute on the
clock. We chose to take approximately 15 minutes to play a complete game,
or to simulate 300 minutes (5 hours x 60 minutes/hour) of pizza deliveries.
So, we need invoke the Tick event 300 times in 900000 milliseconds (15
minutes x 60 seconds/minute x 1000 milliseconds/second). So we should
set Interval to 3000 (900000 / 300). Or should we?
In the Pizza Delivery game, the Timer object will be used to control more
than just the clock. It will also be used to monitor the orders phoned in, the
oven baking the pizzas, and the motion of the car. When multiple events are
controlled by a single Timer, we need to choose a value for Interval that
handles the ‘fastest’ event, or the one that needs to be updated most often.
Then, the slower events are updated at a rate that is some multiple of the
fastest event. In this game, the car motion is the fastest event. We choose to
update car motion every 0.5 seconds or use an Interval value of 500
milliseconds. With such a value, the clock is updated every six updates of
the car motion, giving it a ‘perceived interval’ of 3000.
Let’s implement the clock update logic, but first you may wonder how did
we come up with all these timing numbers? They were developed as the
game was built. Recognizing there were multiple events to be handled by a
single Timer, we defined variables that could be easily changed as the
game was tested and built. The numbers used here are the final values we
chose to make Pizza Delivery a workable game. You may find values that
better suit your needs. Feel free to change anything.
Add this code at the end of InitializeProgram: Timer.Interval = 500
Timer.Pause() Timer.Tick = TimerTickSub ClockTicksMax = 6
Now, we’ll write the code that starts, pauses, restarts and stops the clock in
Pizza Delivery. We also add code that exits the game. Two buttons control
the game, StartPauseButton and ExitStopButton. These buttons have
certain interactions. The StartPauseButton can have one of three possible
actions based on GameStatus. If the GameStatus is “Stopped” when the
button is clicked, the game is initialized and put in playing mode using:
➢ Change GameStatus to “Playing”
➢ Change caption to Pause Game.
➢ Change caption of ExitStopButton to Stop Game.
➢ Initialize time to 6:00.
➢ Initialize ClockTicks to 0.
➢ Start Timer.
Save and Run the program. Click Start Game and the clock should begin
counting up the minutes. Try the pause and restart features. How long does
it take one hour to go by? It should take about 3 minutes based on our
values of Interval and ClockTicksMax. Here’s the window after running a
little over one hour of game time:
The Stop Game button doesn’t work yet – let’s fix that.
Modify the ButtonClickSub routine with the shaded code to detect clicks
on the ExitStopButton: Sub ButtonClickedSub B =
Controls.LastClickedButton If (B = StartPauseButton) Then ' start, stop,
pause button
StartPauseButtonClick()
ElseIf (B = ExitStopButton) Then 'exit, stop button
ExitStopButtonClick()
EndIf
EndSub
which uses the StopGame subroutine that implements the listed steps for
stopping: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") EndSub
Save and Run Pizza Delivery. You should now be able to start the game,
pause the game, restart the game and stop the game. You can also stop the
program. Make sure everything works as desired. Make sure you hear a
‘tada’ sound when the game is ended.
Before leaving the clock, let’s make one last change. Recall the game lasts
from 6:00 to 11:00. As coded, the program will continue forever! We need
logic to stop at 11:00. Add the shaded code to the TimerTickSub to
accomplish this: Sub TimerTickSub 'Clock Update
ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If
(ClockMinute < 10) Then ClockTime = ClockTime + ":0" +
ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime) EndIf
EndSub
Save the program. You should now run the program to make sure it
automatically stops once the clock reaches 11:00. But, you don’t really want
to sit around for 15 minutes to see that happen. To speed things up,
temporarily set the Interval to 100 and ClockTicksMax to 1 (yielding a
clock update every 0.1 seconds). Then, Run the program, click Start Game
and watch time fly by! Once the clock hits 11:00, a sound will be played
and the program should return to stopped state:
Here’s another place where I just made up some rules for the orders – feel
free to change them if you like. The rules implemented for pizza phone
orders are:
Two arrays will be used to keep track of order information. Pizzas is a two-
dimensional array that says how many pizzas were ordered at a grid
location and PizzaTime is a two-dimensional array holding the
corresponding order time (in minutes).
The Timer object will govern how often orders arrive. Since we assume
phone orders arrive in random 1 to 7 minute intervals, we define a
PhoneTicksMax variable that is a multiple of the ClockTicksMax
variable: PhoneTicksMax = Math.GetRandomNumber(7) * ClockTicksMax
Then, with each call to the TimerTickSub, we will increment a
PhoneTicks variable. When its value equals PhoneTicksMax, a new order
will be generated.
We need to make certain initializations for the order process. Make the
shaded modifications to the StartPauseButtonClick subroutine to set the
initial PhoneTicksMax (1 to 7) and to clear any past orders from the grid:
Sub StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus
= "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
'initialize clock
ClockHour = 6
ClockMinute = 0
ClockTime = "6:00"
Shapes.SetText(TimeDisplay, ClockTime) ClockTicks = 0
'initialize phone
PhoneTicks = 0
PhoneTicksMax = Math.GetRandomNumber(7) *
ClockTicksMax 'new grid
DrawGrid()
'clear order area
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110)
NumberOrders = 0
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) Timer.Resume() EndIf
EndSub
Add the two shaded lines to the DrawGrid subroutine to initialize the two
added variables: Sub DrawGrid GraphicsWindow.BrushColor =
"SteelBlue"
GraphicsWindow.FillRectangle(0, 0, 500, 520) 'GridR is row, GridC
is column; build one row at a time GridW = 22
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
For GridR = 0 To 20
For GridC = 0 To 20
DeliveryGridX[GridR][GridC] = 10 + GridC * GridW
DeliveryGridY[GridR][GridC] = 20 + GridR * GridW
Pizzas[GridR][GridC] = 0
PizzaTime[GridR][GridC] = 0
If (GridR = 0) Then If (GridC <> 0) Then 'column letters
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(DeliveryGridX[GridR]
[GridC] + 5, DeliveryGridY[GridR][GridC],
Text.GetCharacter(GridC + 64)) EndIf
ElseIf (GridC = 0) Then If (GridR <> 0) Then 'row numbers
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(DeliveryGridX[GridR]
[GridC], DeliveryGridY[GridR][GridC], GridR)
EndIf
Else
DeliveryGridColor[GridR][GridC] = "White"
DeliveryGridText[GridR][GridC] = ""
DrawGridSquare() EndIf
EndFor
EndFor
EndSub
When an order comes in, we will play a phone sound. We use the
phone.wav file for this sound. It is in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder. Copy the file to your program’s folder.
In this code, we play the phone sound. If it is past 10:30, the routine is
exited. Next, we select a random unselected row (GridR) and a random
column (GridC) for the order. Using the specified percentages, the number
of pizzas ordered is stored in the Pizzas array. Likewise, the order time is
stored in the PizzaTime array. The corresponding grid location is marked
with a dark green background and the number of pizzas ordered. Before
leaving the subroutine, a new random PhoneTicksMax value is computed.
This gives us the delay (between 1 and 7 minutes) until the next order is
phoned in.
Save and Run the program. Click Start Game and the phone should start
ringing, with orders shown in the delivery grid area. Here’s what my
window looked like after 10 orders or so:
Check that you can pause, restart and stop the game. The current code does
not list the orders in the message area. Let’s correct that. One problem is
that the message area is limited in size, holding only five orders. What if
there are more than five orders? We choose to list the five “oldest” orders.
These are the orders requiring the more immediate attention.
Add the shaded code to TimerTickSub to form the text string representing
the order and displaying it: Sub TimerTickSub 'Clock Update
ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf
ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If
(ClockMinute < 10) Then ClockTime = ClockTime + ":0" +
ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime) EndIf
'Phone Update
PhoneTicks = PhoneTicks + 1
If (PhoneTicks >= PhoneTicksMax) Then PhoneTicks = 0
Sound.Stop(Program.Directory + "\phone.wav")
Sound.Play(Program.Directory + "\phone.wav") If (ClockHour =
10 and ClockMinute >= 30) Then Goto LeavePhone EndIf
GetLocation: GridR = Math.GetRandomNumber(20) GridC =
Math.GetRandomNumber(20) If (Pizzas[GridR][GridC] <> 0) Then
Goto GetLocation EndIf
P = Math.GetRandomNumber(100) If (P >= 1 And P <= 30)
Then Pizzas[GridR][GridC] = 1
ElseIf (P >= 31 And P <= 50) Then Pizzas[GridR][GridC] = 2
ElseIf (P >= 51 And P <= 70) Then Pizzas[GridR][GridC] = 2
ElseIf (P >= 71 And P <= 85) Then Pizzas[GridR][GridC] = 2
Else
Pizzas[GridR][GridC] = 5
EndIf
PizzaTime[GridR][GridC] = ClockMinute + 60 * ClockHour
'build string listing order
NumberOrders = NumberOrders + 1
OrderString = ClockTime + " | "
If (ClockHour < 10) Then OrderString = " " + OrderString EndIf
If (GridR < 10) Then OrderString = OrderString + " "
EndIf
OrderString = OrderString + GridR + " "
OrderString = OrderString + Text.GetCharacter(GridC + 64) + "
‐> " + Pizzas[GridR][GridC] + " pizza(s)"
Order[NumberOrders] = OrderString DisplayOrders()
'print new order on grid
DeliveryGridColor[GridR][GridC] = "DarkGreen"
DeliveryGridText[GridR][GridC] = Pizzas[GridR][GridC]
DrawGridSquare() PhoneTicksMax =
Math.GetRandomNumber(7) * ClockTicksMax EndIf
LeavePhone:
EndSub
Notice how the grid column (GridC) is converted to a letter using the
GetCharacter method. The NumberOrders variable tells us how many
orders we have. The Order array holds the order strings. We put the newest
orders at the end of the array, hence the first five elements hold the five
oldest orders.
These oldest orders are listed in the message area using the DisplayOrders
subroutine: Sub DisplayOrders 'Display oldest five orders
'print orders ‐ clear first
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(510, 75, 190, 110) y = 80
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 14
For K = 1 To 5
If (K <= NumberOrders) Then GraphicsWindow.DrawText(525,
y, Order[K]) y = y + 20
EndIf
EndFor
EndSub
Save and Run the program again. Each order (up to five maximum) will
now show in the message area. Here’s a run with about 10 orders:
Now that we know where the orders are coming from, we need to get some
pizzas baked. The rectangle under message area holds the oven. We can
bake, at most, eight pizzas at a time. This is another one of those rules we
chose – you can change it if you like. You would need to resize the pizza
graphic file -pizza.jpg. It is in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder. Copy the file to your program’s folder.
Once the pizzas are done baking (taking 10 minutes), they are placed in the
Baked area for storage. Up to 20 pizzas can be stored. Any pizzas baked
that cannot fit in this area are thrown out, costing you money. Add these
lines (in InitializeProgram) to set these rules and to load the pizza graphic:
'game variables
PizzasReadyMax = 20
PizzasBakingMax = 8
BakingTime = 10
PizzaImage = ImageList.LoadImage(Program.Directory + "\pizza.jpg")
We use one variable (PizzasBaking) to keep track of pizzas in the oven
and another (PizzasReady) to specify the number of pizzas baked and
stored. TotalPizzasBaked will keep track of all pizzas baked during a
single game. BakingMinutesLeft is used to tell us how many minutes
are left in the baking process.
When we start a game, we make sure the Add Pizza and Bake Pizza
buttons appear so pizzas can be baked. We also initialize two variables
(AddPizzaVisible and BakePizzaVisible) to know if either or both buttons
are visible. These values are used when switching from “Playing” mode to
“Paused” mode and back. When we go to “Paused” mode, we want the
buttons to be hidden so they cannot be clicked. Then, when we return to
“Playing” mode, we use these variables to return the buttons to their pre-
paused mode, visible or not.
We make the shaded changes to the StopGame subroutine to hide the oven
buttons when the game is stopped: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
'hide other buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
EndSub
Save and Run the program. Make sure the oven buttons appear when the
game starts, disappear when it is paused and reappear when the game is
restarted. Let’s add functionality to the buttons Pizzas are added to the oven
by clicking the Add Pizza button (AddPizzaButton) in the oven. With
each click of the button, we follow these steps:
➢ Increment PizzasBaking.
➢ Add a PizzaImage to the display.
➢ If maximum number of pizzas reached, hide AddPizzaButton.
Save and Run the program. Click Start Game, then click Add Pizza a few
times. You should now be able to load the oven. Here I’ve put six pizzas in:
Make sure the Add Pizza button disappears when you reach eight pizzas in
the oven. Notice, too, that the Baked area reflects the initial load of eight
pizzas.
Once the oven is loaded, baking begins by clicking the Bake Pizza button.
The steps to follow once this button is clicked are:
In this code, we redraw the pizza oven (and pizzas) with a red background
and hide the buttons. Notice how we use various time variables to
determine and format the time the pizzas will leave the oven Save and Run
the program again. You should now be able load the oven and start the
baking process. Here’s my six pizzas baking:
Always remember, a red oven is a baking oven; a blue oven is a cold oven.
Sometimes when playing the game, you forget to start the baking process.
The Timer object will be used to time the baking process. We will check
this process every minute (the same as the clock), so all code for the baking
will be within the “clock loop” in the TimerTickSub subroutine. If
OvenGoing is “true”:
Notice, when the baking is done, we will play a ding sound. We use the
ding.wav file for this sound. It is in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder. Copy the file to your program’s folder.
Add the shaded code to the ‘Clock Update’ section of the TimerTickSub
subroutine (we don’t show the entire subroutine – it’s getting very long!):
'Clock Update
ClockTicks = ClockTicks + 1
If (ClockTicks >= ClockTicksMax) Then ClockTicks = 0
ClockMinute = ClockMinute + 1
If (ClockMinute > 59) Then ClockMinute = 0
ClockHour = ClockHour + 1
If (ClockHour = 11) Then ClockTime = "11:00"
Shapes.SetText(TimeDisplay, ClockTime) StopGame()
EndIf
EndIf
ClockTime = ""
ClockTime = Text.Append(ClockTime, ClockHour) If (ClockMinute
< 10) Then ClockTime = ClockTime + ":0" + ClockMinute Else
ClockTime = ClockTime + ":" + ClockMinute EndIf
Shapes.SetText(TimeDisplay, ClockTime)
'pizzas in oven
If (OvenGoing) Then BakingMinutesLeft = BakingMinutesLeft ‐ 1
If (BakingMinutesLeft = 0) Then Sound.Stop(Program.Directory
+ "\ding.wav") Sound.Play(Program.Directory + "\ding.wav")
OvenGoing = "false"
PizzasReady = PizzasReady + PizzasBaking
TotalPizzasBaked = TotalPizzasBaked + PizzasBaking If
(PizzasReady > PizzasReadyMax) Then PizzasReady =
PizzasReadyMax EndIf
Shapes.SetText(PizzasReadyDisplay, PizzasReady)
DrawBlueOven() PizzasBaking = 0
Controls.ShowControl(AddPizzaButton) AddPizzaVisible =
"true"
Controls.ShowControl(BakePizzaButton) BakePizzaVisible =
"true"
EndIf
EndIf
EndIf
We are almost ready to test everything, but need one more change. Notice if
we stop the game while the oven is running, the oven will still be red with
pizzas in it. Make the shaded changes in the StopGame subroutine to
handle this possibility: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") 'hide other
buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
OvenGoing = "false"
DrawBlueOven()
EndSub
Save and Run the program. Click Start Game, then click Add Pizza some
number of times. Click Bake Pizza and wait. After 10 minutes elapse (may
be 11 minutes depending on just when you click Bake Pizza), you will hear
a ding sound and the pizzas you baked will be moved to the Baked area.
Here’s my screen after baking six pizzas (the Baked area now shows 14);
notice, too, a few orders have come in:
Continue baking pizzas if you like – remember you can only store 20
pizzas. Make sure you can pause, restart and stop the game. Next, we see
how to move pizzas into the car and start delivering them.
Code Design – Load Car
A delivery car is available to take pizzas from the pizza parlor to the order
locations on the grid. A first step in the delivery process is to load pizzas
from the Baked area into the car. This is done by clicking Load button in
the Pizzas In Car box. We use a variable PizzasInCar to keep track of how
many pizzas are in the car. We assume a maximum of 10 pizzas can fit in
the car. Add this line (in InitializeProgram) with other program variables:
PizzasInCarMax = 10
As stated, to load the car, you click the Load button in the box Pizzas In
Car. The steps followed (assuming there are pizzas to load) are simple. If
the maximum number of pizzas to load are available, load that number in
the car, otherwise load all the ready pizzas. Add shaded code to the
ButtonClickSub subroutine to detect clicks on the LoadButton: Sub
ButtonClickedSub B = Controls.LastClickedButton If (B =
StartPauseButton) Then ' start, stop, pause button
StartPauseButtonClick() ElseIf (B = ExitStopButton) Then 'exit,
stop button
ExitStopButtonClick() ElseIf (B = AddPizzaButton) Then 'add
pizza button
AddPizzaButtonClick() ElseIf (B = BakePizzaButton) Then
'bake pizza button
BakePizzaButtonClick()
ElseIf (B = LoadButton) Then 'load car button
LoadButtonClick()
EndIf
EndSub
Notice we hide the Load button once the pizzas are loaded. In the motion
code, we use the LoadVisible status of this button to tell us whether the car
has pizzas available for delivery.
Save and Run the program. Start the game, bake some pizzas and load the
car. In this screen, I baked six pizzas, giving me 14 baked pizzas. I then
clicked the Load button. The car now has the maximum of 10 pizzas and
there are 4 pizzas remaining in the Baked area:
Next, let’s start delivering pizzas by driving the car around the delivery
grid.
Code Design – Move Car
Once there are pizzas in the car, we’re ready to start deliveries. Click on a
location on the delivery grid and the car (represented by a little yellow
image) travels from the pizza parlor to that location. You follow the same
process to have the car return to the pizza parlor when you need more
pizzas. There are lots of things to do here: define the pizza parlor location
(randomly set), detect clicks on the delivery grid, identify the clicked grid
location, and then move the car to the clicked location.
We need several variables to keep track of the car. PizzaR and PizzaC are
the row and column numbers for the pizza parlor location in the delivery
grid (marked by an X). DeliveryR and DeliveryC are the row and column
numbers for the delivery (the clicked location). CarR and CarC are the
row and column numbers for the current car location. DeltaR and DeltaC
are the difference between the car and delivery rows and columns. Lastly,
Mileage is the number of grid locations the car has moved through and
CarMoving indicates if the car is currently moving.
The pizza parlor is placed somewhere on the interior of the grid and marked
by an X (the corresponding Pizzas array element is set to -1 to mark this as
the pizza parlor). The car is positioned at this location and the mileage
initialized. A message is posted announcing the car is at the pizza parlor.
The two-lined message is displayed with this subroutine: Sub
DisplayMessage 'clear first
GraphicsWindow.BrushColor = "LightYellow"
GraphicsWindow.FillRectangle(505, 190, 205, 50)
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 14
GraphicsWindow.DrawText(510, 195, Message1)
GraphicsWindow.DrawText(510, 215, Message2) EndSub
Save and Run the program. Click Start Game to make sure the pizza
parlor is marked and the proper message appears. Here’s my form:
The parlor is at location 18 P. That is also the car’s initial location (see the
displayed message). Let’s see how to indicate where we want the car to go
to and how to move the car.
Once orders come in and there are pizzas in the car, we can start making
deliveries. To move the car to a desired location on the delivery grid, we
simply click that location. When a grid location is clicked, we follow these
steps:
Look at the math that converts a clicked (x, y) coordinate to row and
column values. We simply determine the distance of the clicked point from
the grid border in each direction and divide that by the width of a grid
square. The Math.Floor method knocks off any decimal result to give us a
whole number result. It’s pretty cool!
Save and Run the game. Click Start Game, click Load. You should now
be able to click the grid and have the clicked location appear in the message
area. Here’s my window after I clicked the square in Row 14, Column R:
This may seem like a lot of steps, but they are straightforward. Notice, in
particular, we display LoadButton when we return to the pizza parlor to
allow reloading of the car.
Notice, when the car stops, we will play a beep sound. We use the
carbeep.wav file for this sound. It is in the KidGamesSB\KidGamesSB
Programs\PizzaDelivery folder. Copy the file to your program’s folder.
Add this ‘Car Update’ code at the end of the TimerTickSub subroutine
after the labeled LeavePhone: line(again, we don’t show the entire
subroutine). This code implements the above steps: 'Car Update ‐ updated
each tick
If (CarMoving) Then ''replace what is there
GridR = CarR
GridC = CarC
DrawGridSquare() 'move vertically first
If (DeltaR <> 0) Then Mileage = Mileage + 1
CarImage = VCarImage If (DeltaR > 0) Then CarR = CarR + 1
Else
CarR = CarR ‐ 1
EndIf
DeltaR = DeliveryR ‐ CarR
Else
Mileage = Mileage + 1
CarImage = HCarImage If (DeltaC > 0) Then CarC = CarC + 1
Else
CarC = CarC ‐ 1
EndIf
DeltaC = DeliveryC ‐ CarC
EndIf
GraphicsWindow.DrawImage(CarImage, DeliveryGridX[CarR]
[CarC] + 3, DeliveryGridY[CarR][CarC] + 3) If (CarR = DeliveryR
And CarC = DeliveryC) Then CarMoving = "false"
Sound.Stop(Program.Directory + "\carbeep.wav")
Sound.Play(Program.Directory + "\carbeep.wav") If (CarR =
PizzaR And CarC = PizzaC) Then Message1 = "Car at Pizza
Parlor:"
Message2 = CarR + " " + Text.GetCharacter(CarC + 64)
DisplayMessage() GridR = CarR
GridC = CarC
DrawGridSquare() PizzasInCar = 0
Shapes.SetText(PizzasInCarDisplay, PizzasInCar)
Controls.ShowControl(LoadButton) LoadVisible = "true"
Else
'check delivery status
EndIf
EndIf
EndIf
Notice once the car starts moving, it doesn’t stop until it reaches the clicked
location.
Save and Run the program. Click Start Game, then click Load to put
some pizzas in the car. Now, click a location on the grid and watch the car
go there. Here’s my window as the car is on its way to an order for 2 pizzas
at Row 5, Column A:
And, once the car arrives, I hear a beep and the window shows:
Now, click the pizza parlor (marked by an X) – you need to do this when
you need more pizzas to deliver. The car will return and disappear from the
screen. The message will indicate the car is at the pizza parlor. The Load
button will be visible and you will have zero pizzas in the car. As
mentioned, if the car returns with any pizzas, they must be thrown away due
to health department rules. At this point, you need to bake more pizzas and
reload the car if you want to go back on the road.
We’re getting close to being done. Just two more steps. We need to check
the status of any deliveries made and, lastly, we need to present the final
sales results when a game is stopped.
Code Design - Deliveries
Once the car arrives at a selected location, we need check the status of the
delivery at that location. We’ll also determine how the delivery affects our
earnings. The rules used for deliveries are:
The above rules are implemented in several variables. Add these lines in
InitializeProgram with the other variable definitions: OrderMaxTime = 60
OrderLateTime = 30
NetSoldPizza = 10
NetLatePizza = 5
CostMissedPizza = 1
PizzaCost = 3
MileageCost = 0.1
➢ Check to see if 60 minutes have elapsed for the first item in the
Order array. This is the oldest order and the only candidate for
removal. If 60 minutes have elapsed, increment MissedDeliveries by
the proper number of pizzas and remove the order from the delivery
grid and array.
➢ For all remaining array items, check to see if 30 minutes have
elapsed. If so, and the background isn’t already red, change it to red.
Note how we extract the row (GridR) and column (GridC) information
from the array item Order[I]. In the code, we use the previously defined
variables for on-time and late delivery times. The top item (ItemToRemove
= 1) is removed from the Order array using: Sub RemoveItem 'remove
ItemToRemove from Orders
If (ItemToRemove <> NumberOrders And NumberOrders <> 1)
Then For J = ItemToRemove To NumberOrders ‐ 1
Order[J] = Order[J + 1]
EndFor
EndIf
NumberOrders = NumberOrders ‐ 1
DisplayOrders() EndSub
This simply removes ItemToRemove from the Order array and moves the
rest of the array up one position. We will also use this routine when
processing orders.
Save and Run the game. Click Start Game. Watch as orders start out
green. After 30 minutes, they should turn red. After 60 minutes, they should
disappear from the grid. Make sure the program is working as desired. You
might like to change the ClockTicksMax value (temporarily) to a smaller
number to speed things up. Here’s my window after an hour and a half of
running time showing several ‘red’ orders (making no deliveries):
Any orders received between 6:00 and 6:30 have been removed from the
order list since they are older than one hour.
As seen previously, once the car reaches a delivery location, a check on the
delivery status is done. This check is completed in the ‘Car Update’
section of the TImerTickSub subroutine (we left a “hook” for this code).
Using our rules, the steps followed are:
➢ If the delivery location did not order any pizzas, post message and
exit.
➢ If the delivery location needs more pizza than is available, post
message and exit.
➢ If on-time delivery, increment PizzasOnTime by number of pizzas
ordered. Increment TotalSales accordingly.
➢ If late delivery, increment PizzasLate by number of pizzas ordered.
Increment TotalSales accordingly.
➢ If successful delivery (whether on-time or late), decrement
PizzasInCar and remove order from delivery grid and Order array.
Notice how we search through the Order array to find the item
corresponding (matching row and column) to remove.
Run and Save the program. At long last, you can run the entire simulation.
You can accept orders, bake pizzas, load the car and direct the car to orders.
You can return to the pizza parlor when you need more pizzas. Try playing
for a while. Here’s my window after delivering pizzas for a little over an
hour:
Stop the game and program when you’re ready to go on. When you stop the
game, the only results currently shown are the total sales. A total financial
analysis should include costs to determine net profits. We’ll use a separate
window (a text window) to present this analysis.
Window Design – Sales Results
We will use a text window to display the sales results. Like the graphics
window, it helps to first make a sketch of the desired layout. Here is the
sketch for the Sales Results window:
At the top, we display the start and stop times. The left side of the window
displays sales information and the right side displays cost information.
Profits are displayed at the bottom.
Code Design – Sales Results
Add the shaded line to the StopGame subroutine to display the sales result
window: Sub StopGame GameStatus = "Stopped"
Timer.Pause() Sound.Stop(Program.Directory + "\tada.wav")
Sound.Play(Program.Directory + "\tada.wav")
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") 'hide other
buttons
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) OvenGoing = "false"
DrawBlueOven() CarMoving = "false"
SalesResults()
EndSub
We will build the SalesResults subroutine in stage. First, let’s just display
the header information: Sub SalesResults GraphicsWindow.Hide()
TextWindow.Show() TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Clear() TextWindow.Title = "Pizza Delivery Sales
Results"
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 2
TextWindow.WriteLine("PIZZA DELIVERY SALES RESULTS:")
TextWindow.WriteLine("") TextWindow.CursorLeft = 2
TextWindow.WriteLine("Start Time: 6:00 Stop Time: " + ClockTime)
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("")
TextWindowTextWindow..CursorLeftCursorLeft == 2
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 23
TextWindow.Write("Press Enter to Return to Pizza Delivery") T =
TextWindow.Read() TextWindow.Hide() GraphicsWindow.Show()
EndSub
We hide the graphics window and show the text window. Using the
CursorLeft and CursorTop properties, we position text in the window.
When done, we display ‘Press Enter to Return to Pizza Delivery’.
Save and Run the program. Click Start Game. Let the game run for a bit.
Then, click Stop Game. The results window with times will display:
Add the shaded code to SaleResults to compute and print sales information:
Sub SalesResults GraphicsWindow.Hide() TextWindow.Show()
TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Clear() TextWindow.Title = "Pizza Delivery Sales
Results"
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 2
TextWindow.WriteLine("PIZZA DELIVERY SALES RESULTS:")
TextWindow.WriteLine("") TextWindow.CursorLeft = 2
TextWindow.WriteLine("Start Time: 6:00 Stop Time: " + ClockTime)
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("")
'sales
TextWindow.CursorLeft = 2
TextWindow.WriteLine("Sales:") TextWindow.WriteLine("") 'on‐time
pizzas
T = PizzasOnTime + " On‐Time Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = PizzasOnTime * NetSoldPizza
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'late pizzas
T = PizzasLate + " Late Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = PizzasLate * NetLatePizza
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'total sales
TextWindow.WriteLine("") TextWindow.CursorLeft = 14
TextWindow.Write("Total Sales") Amount = TotalSales
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 23
TextWindow.Write("Press Enter to Return to Pizza Delivery") T =
TextWindow.Read() TextWindow.Hide() GraphicsWindow.Show()
EndSub
Save and Run. Play the game for a bit until you make a few deliveries.
Click Stop Game to see the added Sales:
Note how the dollar amounts are right justified to column 35.
Lastly, add the shaded code to SaleResults to display cost and profit
information: Sub SalesResults GraphicsWindow.Hide()
TextWindow.Show() TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Clear() TextWindow.Title = "Pizza Delivery Sales
Results"
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 2
TextWindow.WriteLine("PIZZA DELIVERY SALES RESULTS:")
TextWindow.WriteLine("") TextWindow.CursorLeft = 2
TextWindow.WriteLine("Start Time: 6:00 Stop Time: " + ClockTime)
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("") 'sales
TextWindow.CursorLeft = 2
TextWindow.WriteLine("Sales:") TextWindow.WriteLine("") 'on‐time
pizzas
T = PizzasOnTime + " On‐Time Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = PizzasOnTime * NetSoldPizza
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'late pizzas
T = PizzasLate + " Late Deliveries"
TextWindow.CursorLeft = 25 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = PizzasLate * NetLatePizza
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'total sales
TextWindow.WriteLine("") TextWindow.CursorLeft = 14
TextWindow.Write("Total Sales") Amount = TotalSales
FormatAmount() TextWindow.CursorLeft = 35 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'costs
TextWindow.CursorLeft = 40
TextWindow.CursorTop = 7
TextWindow.WriteLine("Costs:") TextWindow.WriteLine("") 'pizzas
baked
T = TotalPizzasBaked + " Pizzas Baked"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = TotalPizzasBaked * PizzaCost
FormatAmount() TextWindow.CursorLeft = 70 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'mileage
T = Mileage + " Units Driven"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = Mileage * MileageCost
FormatAmount() TextWindow.CursorLeft = 70 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'missed deliveries
T = MissedDeliveries + " Missed Deliveries"
TextWindow.CursorLeft = 60 ‐ Text.GetLength(T)
TextWindow.Write(T) Amount = MissedDeliveries *
CostMissedPizza FormatAmount() TextWindow.CursorLeft = 70 ‐
Text.GetLength(AmountText) TextWindow.WriteLine(AmountText)
'total costs
TextWindow.WriteLine("") TextWindow.CursorLeft = 49
TextWindow.Write("Total Costs") Costs = TotalPizzasBaked *
PizzaCost + Mileage * MileageCost + MissedDeliveries *
CostMissedPizza Amount = Costs FormatAmount()
TextWindow.CursorLeft = 70 ‐ Text.GetLength(AmountText)
TextWindow.WriteLine(AmountText) TextWindow.WriteLine("")
TextWindow.CursorLeft = 2
TextWindow.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐") TextWindow.WriteLine("") Amount =
TotalSales ‐ Costs FormatAmount() TextWindow.CursorLeft = 10
TextWindow.Write("Total Profits: " + AmountText) If (ClockHour) >
6 Then 'only show hourly profits if been selling for more than one
hour Amount = (TotalSales ‐ Costs) / (ClockHour ‐ 6 + ClockMinute
/ 60) FormatAmount() TextWindow.CursorLeft = 40
TextWindow.Write("Hourly Profits: " + AmountText) EndIf
TextWindow.CursorLeft = 2
TextWindow.CursorTop = 23
TextWindow.Write("Press Enter to Return to Pizza Delivery") T =
TextWindow.Read() TextWindow.Hide() GraphicsWindow.Show()
EndSub
Save and Run the program one last time. It is now complete. You should be
able to play a full game of Pizza Delivery and receive a sales report. Here’s
my window after a couple of orders have come in:
At 6:06, an order for 1 pizza was taken for delivery to Row 6, Column N
(also marked on grid). At 6:09, 5 pizzas were ordered at 12 H. I click Load
to get some pizzas. Then, I click 6 N on the grid.
My car goes there, beeps and makes a delivery. Then, I see:
The pizza was delivered on-time and I made $10. Next, I deliver 5 pizzas to
12 H, followed by 2 pizzas at 10 J. At that point, I am out of pizzas. I click
the X mark at 19 D to return to the pizza parlor.
I click the Add Pizza button 8 times to load the oven, then click Bake
Pizza to start the oven:
I could have started the baking process while I was out on the road,
speeding things up a bit. Now, I’m forced to wait several minutes while the
pizzas bake.
After playing for a little over an hour, my window looks like this:
I’ve got lots of orders and lots of pizzas going. The customer at 10 S has
been waiting a while (noted by the red grid background). I need to rush
those pizzas out.
I ran Pizza Delivery to 9:00 (closing before the usual 11:00). At that point,
I clicked Stop Game and the sales results window appears:
I did okay, making $200.30.
Pizza Delivery Program Listing
Here is the complete listing of the Pizza Delivery Small Basic program: '
Pizza Delivery
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 715
GraphicsWindow.Height = 520
GraphicsWindow.Title = "Pizza Delivery"
'draw new delivery grid
DrawGrid()
'draw clock and sales
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 5, 100, 60)
GraphicsWindow.FillRectangle(610, 5, 100, 60)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
GraphicsWindow.DrawText(510, 5, "Time")
GraphicsWindow.DrawText(615, 5, "Sales") ClockTime = "6:00"
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = 20
GraphicsWindow.FontBold = "false"
TimeDisplay = Shapes.AddText(ClockTime) Shapes.Move(TimeDisplay,
535, 30) TotalSales = 0
'format as $0.00
Amount = TotalSales FormatAmount() SalesDisplay =
Shapes.AddText(AmountText) Shapes.Move(SalesDisplay, 620, 30)
'draw message area
GraphicsWindow.BrushColor = "LightYellow"
GraphicsWindow.FillRectangle(505, 190, 205, 50)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(505, 190, 205, 50)
GraphicsWindow.DrawRectangle(505, 70, 205, 120) 'draw pizza oven
DrawBlueOven() 'add pizza button
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
AddPizzaButton = Controls.AddButton("Add Pizza", 510, 380)
Controls.SetSize(AddPizzaButton, 95, 33) 'bake pizza button
BakePizzaButton = Controls.AddButton("Bake Pizza", 610, 380)
Controls.SetSize(BakePizzaButton, 95, 33) 'draw pizza loading boxes
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(505, 420, 70, 60)
GraphicsWindow.FillRectangle(580, 420, 130, 60)
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.DrawText(510, 420, "Baked")
GraphicsWindow.DrawText(585, 420, "Pizzas in Car") PizzasReady = 0
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FontSize = 20
PizzasReadyDisplay = Shapes.AddText(PizzasReady)
Shapes.Move(PizzasReadyDisplay, 535, 445) PizzasInCar = 0
PizzasInCarDisplay = Shapes.AddText(PizzasInCar)
Shapes.Move(PizzasInCarDisplay, 615, 445) 'load button
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 16
LoadButton = Controls.AddButton("Load", 660, 445)
Controls.SetSize(LoadButton, 45, 33) 'start/pause button
StartPauseButton = Controls.AddButton("Start Game", 505, 485)
Controls.SetSize(StartPauseButton, 110, 33) 'exit/stop button
ExitStopButton = Controls.AddButton("Exit", 620, 485)
Controls.SetSize(ExitStopButton, 90, 33)
Controls.HideControl(AddPizzaButton)
Controls.HideControl(BakePizzaButton)
Controls.HideControl(LoadButton) GameStatus = "Stopped"
'game variables
PizzasReadyMax = 20
PizzasBakingMax = 8
BakingTime = 10
PizzaImage = ImageList.LoadImage(Program.Directory + "\pizza.jpg")
PizzasInCarMax = 10
HCarImage = ImageList.LoadImage(Program.Directory + "\hcar.bmp")
VCarImage = ImageList.LoadImage(Program.Directory + "\vcar.bmp")
OrderMaxTime = 60
OrderLateTime = 30
NetSoldPizza = 10
NetLatePizza = 5
CostMissedPizza = 1
PizzaCost = 3
MileageCost = 0.1
Timer.Interval = 500
Timer.Pause() Timer.Tick = TimerTickSub ClockTicksMax = 6
Controls.ButtonClicked = ButtonClickedSub
GraphicsWindow.MouseDown = MouseDownSub EndSub
The Pizza Delivery game program is now complete. Save and Run the
program and make sure it works as promised. Check that all functions work
correctly.
While completing this program, new concepts and skills you should have
gained include:
There are some ways to change the Pizza Delivery program. Some
possibilities are:
➢ The game difficulty can be adjusted if you like. By varying the time
between phone orders, the size of orders, the time needed to make a
delivery and the speed of the car, you can make the game easier or
harder. You would need some way for the player to select a difficulty.
➢ The current car cannot be re-routed once it starts. Modify the click
logic to re-route the car if desired.
➢ Once business builds, you might need a second car. Think of ways
you might be able to implement and control more than one car.
➢ This particular pizza parlor only makes one kind of pizza. This
simplifies the simulation somewhat. The car can stay out on the road
and deliver whatever pizzas are in the car. The oven can just keep
cranking out pizzas. It would be interesting to make different types of
pizzas available for order. You would have to know how many of
each are ordered, bake different types and load different types into
the car. This would be more like a real pizza delivery process.
9. Moon Landing Program
Review and Preview
Like the Pizza Delivery game in the last chapter, there’s lots going on in the
Moon Landing game. So, before running the game, let’s describe its
operation. Prior to starting your descent to the moon, click Options to
choose your pilot level: Beginner, Novice, Junior, Senior, or Advanced.
Decide if you want Auto-Pilot On. And, select the type of distance units:
Meters or Feet.
The idea under each option is the same. Your vehicle is some height above
the surface of the moon at zero speed. Due to gravity (about one-sixth the
gravity on earth), you begin to accelerate toward the surface with a
corresponding change (goes negative) in your speed (a negative speed
indicates descent -positive speed indicates ascent). The current altitude and
speed are always displayed. You slow your descent by clicking on the
vertical thruster (Down button). This thruster counteracts gravity effects.
You must also adjust the lander’s lateral position relative to the landing pad.
Your current lateral position (- if to the left of the pad, + if to the right) and
lateral speed (- if moving to the left, + if moving to the right) are displayed.
Lateral motion of the lander is controlled using the two thruster controls
with Left and Right. Note the left thruster accelerates the lander to the right
and the right thruster accelerates the lander to the left. All thrusters operate
in ‘impulse’ mode. That is they just fire momentarily, changing the lander
speed in the corresponding direction. In ‘rocket scientist’ talk, we say the
thrusters impart a ‘delta V’ (change in velocity) to the lander.
The end goal is to be over the landing pad and going at a slow descent
speed (and slow lateral speed) by the time your altitude (height above the
landing pad) reaches zero. A safe landing is one where the final speed is
between 0 and -3 m/s (-10.0 ft/s); higher descent speeds result in a crash!
There are no crash penalties for missing the pad - your astronauts will just
have a long walk back to the home base!!
Then, the Senior option offers one more concern. With the Senior (and
Advanced) option, the fuel gauge shows you how much fuel you have
remaining. Each thruster burn uses some fuel (the vertical thruster uses
twice as much as the left and right thrusters). So now, you must land at a
safe speed, over the landing pad without running out of fuel. Once you run
out of fuel, your vehicle will just accelerate toward the lunar surface, most
likely resulting in a crash. The final level is Advanced, where your
thrusters work in a random manner, removing predictability from the
program. Constant adjustments are needed to keep the vehicle over the pad
and within speed limits. The program offers an Auto-Pilot mode to
demonstrate how the computer lands the vehicle. It actually does a fairly
decent job.
At any time during the program, you may pause the action by clicking
Pause Game. To restart, click Restart Game. To stop the program before
landing, click Stop Game. Once a landing is complete, the program stops
and you may view the final positions, speeds and fuel consumption. You
can then play again. Though this is lots of explanation – the Moon Landing
game is simple to operate. Start it, then use the three thruster buttons to
change the Altitude and Lateral position of the lander.
For now, click Options to change options. A text window will appear:
There are three options to set. First, choose your pilot level: Beginner,
Novice, Junior, Senior, or Advanced. Decide if you want Auto-Pilot On.
And, select the type of units for distance: Meters or Feet. For this example,
I chose the Senior level, with Auto-Pilot On and Meters as units:
After making your choices, the graphics window reappears with the game
still in the ‘stopped’ state. Click Start Game to get things going. Here’s the
game after 4.0 seconds (an update is given every 0.5 seconds) of running (I
paused at this point):
The graphic on the left shows the current position of the lander. Below this
are two small boxes, one green and one red. The red box indicates the
landing pad lateral location, while the green box marks the moon lander’s
current lateral position. When the two boxes coincide, the lander is over the
pad. Data on the right shows the lander is 558 meters above the pad,
dropping at 6.2 meters/second. It is 188 meters to the right (lateral position
is a negative number) of the pad. The auto-pilot is applying some left thrust,
accelerating the lander to a lateral speed of 2.2 meters/second. The fuel tank
appears full. Below the fuel gauge is a “trajectory plot,” showing past
vehicle positions (the circles) relative to the landing pad (with a suggested
straight-line descent trajectory). The thruster controls don’t appear since we
are using auto-pilot mode.
The computer has applied several bursts of vertical thrust to keep the lander
vertical speed reasonable and used a few right thrusts to move the lander to
the left, toward the pad. But, now it’s applying a left thrust to move it to the
right a little.
And, at 65.5 seconds:
The computer is still giving thrust adjustments to finalize landing. The pad
is nearby and things are looking good.
Finally, at 92.5 seconds, the lander is safely on the pad:
This a near perfect landing, under the safe landing speed of -3.0 m/s and
almost on top of the pad. Notice how all the graphic depictions of lander
position coincide with the numerical values.
You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.
Here is a sketch for the window layout for the Moon Landing program:
The rectangle to the left will display the lander animation. On the right side
of the window are several numerical displays for time and lander position
and speed. A fuel gauge may appear depending on options. Under the fuel
gauge is an area for drawing the lander trajectory. Thrust control buttons (if
present) are below this area. Three other button controls will be used: one to
start and stop the game, one to change options and one to exit the program.
We will now begin writing the code for Moon Landing. We will write the
code in several steps. As a first step, we will write the code that sets the
various window components, Then, we do some initial coding for the
start/pause and exit/stop buttons. Then, we add additional elements to the
game, one at a time. During the code development process, recognize you
may modify a particular subroutine several times before arriving at the
finished product.
Start a new program in Small Basic. Once started, we suggest you
immediately save the program with a name you choose. This sets up the
folder and file structure needed for your program.
Window Design – Lander Viewer
We first establish the viewing area for the lander as it descends to the
landing pad. We also draw the guide (with the little green and red boxes)
underneath the viewing area.
The green box (representing lander position) and red box (representing
landing pad position) are in arbitrary locations. They will be correctly
positioned following initialization.
Window Design – Status Display
We use five pieces of information to provide the lander status: current time,
vertical position and speed, lateral position and speed. There is also a fuel
gauge (for higher pilot levels). Titling information for this display depends
on selected options:
This routine calls the UpdateStatus subroutine which for now is empty:
Sub UpdateStatus
EndSub
Add this new code. Then, Save and Run the program. You should see the
empty status boxes properly labeled (no fuel gauge since it is Beginner
level):
Window Design – Trajectory Display
Below the displayed values, we will show the trajectory followed by the
lander as it descends. For now, it is just a blank, black rectangle.
The Moon Landing game uses six different button controls. Three buttons
are used to control thrust (LeftThrustButton, DownThrustButton,
RightThrustButton). Depending on program options, one, two, three, or
none of the thrust buttons may appear.
Save and Run the program. For the default options, a single thrust button
(DownThrustButton) will appear along with the three program control
buttons:
The program begins in ‘stopped’ state. We have three choices – either click
Start Game to start, click Options to change options, or click Exit to exit
the program. We will write code for each of these options in reverse order.
But before we do, add this line at the end of InitializeProgram to set the
GameStatus: GameStatus = "Stopped"
First, we need to be able to detect button clicks so now add this line at the
end of InitializeProgram: Controls.ButtonClicked = ButtonClickedSub
With this, each time a ButtonClicked event occurs, the subroutine named
ButtonClickedSub is called.
Run the program. Click Exit to make sure the game stops.
If the user clicks Options, we want to change program options. We will use
the Small Basic text window to establish game options. Add the shaded
code to the ButtonClickedSub subroutine: Sub ButtonClickedSub B =
Controls.LastClickedButton If (B = ExitStopButton) Then 'exit, stop button
ExitStopButtonClick()
ElseIf (B = OptionsButton) Then 'change options
SetOptions()
EndIf
EndSub
The options are set in the SetOptions subroutine – add this routine: Sub
SetOptions
GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title =
"Moon Landing"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("MOON LANDING OPTIONS")
TextWindow.WriteLine("") GetPilotLevel:
TextWindow.CursorLeft = 3
TextWindow.WriteLine("What level pilot do you want?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Beginner, 2‐Novice, 3‐Junior, 4‐Senior, 5‐
Advanced) ") PilotLevel = TextWindow.ReadNumber() If (PilotLevel
< 1 Or PilotLevel > 5) Then Goto GetPilotLevel EndIf
GetAutoPilotOn:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("Do you want Auto‐Pilot on?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Yes, 2‐No) ") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto
GetAutoPilotOn EndIf
If (T = 1) Then AutoPilotOn = "true"
Else
AutoPilotOn = "false"
EndIf
GetUnits: TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("What units of distance do you want to
use?") TextWindow.CursorLeft = 3 <</p> TextWindow.Write("(1‐
Meters, 2‐Feet) ")
T = TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto
GetUnits
EndIf
If (T = 1) Then MetricUnits = "true"
Else
MetricUnits = "false"
EndIf
SetDisplay()
TextWindow.Hide() GraphicsWindow.Show() EndSub
This routine hides the graphics window, displays a text window and asks
the user questions necessary to establish the three options (PilotLevel,
AutoPilotOn, MetricUnits). Once the questions are answered, the display
is reset and the program returns to the game in ‘stopped’ state.
We will do the calculations in this program in metric units. This means all
positions will be in meters and all speeds will be in meters/second. If a user
selects ‘Feet’ units, we need to multiply all results by the number than
converts meters to feet. This number will be stored in a variable Multiplier.
Find this segment of code in SetDisplay: If (MetricUnits) Then
GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf
If (MetricUnits) Then
Multiplier = 1.0
GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
Multiplier = 3.2808
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf
The Multiplier is 1.0 for metric units (meters) and 3.2808 for units of feet.
This says there are 3.2808 feet in a meter.
Save and Run the program. Click the Options button the change options:
Make your choices and press Enter after each. The Moon Landing
window will again appear.
Timer.Interval = 500
Timer.Tick = TimerTickSub Timer.Pause() We will update the program
every 500 milliseconds (0.5 seconds). Add the TimerTickSub
subroutine: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
UpdateStatus()
EndSub
This updates the time at each Tick event and calls UpdateStatus where
Time is displayed in its location in the window.
We’re almost ready to see the time displayed. We need some way to turn on,
pause and restart the timer. Two buttons control the game,
StartPauseButton and ExitStopButton. These buttons have certain
interactions. The StartPauseButton can have one of three possible actions
based on GameStatus. If the GameStatus is “Stopped” when the button is
clicked, the game is initialized and put in playing mode using:
And, finally, the code that covers the above steps is in the
StartPauseButtonClick subroutine: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then
GameStatus = "Paused"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton,
"Restart Game") Controls.HideControl(ExitStopButton)
Controls.HideControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.HideControl(RightThrustButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton) 'show other buttons if
they were showing before
If (LeftThrustVisible) Then
Controls.ShowControl(LeftThrustButton) EndIf
If (DownThrustVisible) Then
Controls.ShowControl(DownThrustButton) EndIf
If (RightThrustVisible) Then
Controls.ShowControl(RightThrustButton) EndIf
Timer.Resume() EndIf
EndSub
Save and Run the program. Make sure the clock time is increasing in 0.5
second increments. Here’s the window for a Senior level, no auto-pilot and
Feet units after 5.5 seconds:
As expected, all thruster controls appear, as does the fuel gauge. Make sure
the Pause Game and Restart Game buttons affect the clock and buttons
correctly. The Stop Game button doesn’t work yet – let’s fix that.
When a player clicks Stop Game (the ExitStopButton in “Playing”
mode), the following should happen:
Save and Run Moon Landing. You should now be able to start the game,
pause the game, restart the game and stop the game. You can also stop the
program. Make sure everything works as desired. Next, let’s write the code
that implements the math and physics behind the lunar module motion.
Code Design – Physics of Moon Landing
Are you ready for a little physics and math? Don’t worry it won’t be too
scary. We want to write the equations that describe the position and speed of
the landing vehicle as it descends to the moon. As a first step, we need to
define a coordinate system to do our computations. We assume all graphics
elements (the lander, the thrust flames, the pad) are contained within a
rectangular region named Landscape:
A point within this region is specified by a “Cartesian” pair, (x, y). In the
diagram, note the x (horizontal) coordinate increases from left to right,
starting at 0 and extending to LandscapeWidth - 1. The y (vertical)
coordinate increases from top to bottom, starting at 0 and ending at
LandscapeHeight - 1. All measurements are integers and in units of pixels.
In this program, we will assume one pixel corresponds to one meter of
distance.
Knowing T, the X and Y position of the lander are updated each clock cycle
using: LanderX = LanderX + SpeedX * T
You should see that SpeedX * T is the horizontal distance traveled by the
lander in one clock cycle and SpeedY * T is the corresponding vertical
distance.
The vertical speed of the lander (LanderYSpeed) also changes with each
clock cycle. Gravity tends to accelerate (increase speed) the lander toward
the moon surface. If the gravitational acceleration is Gravity, in T seconds,
the speed is increased according to: LanderYSpeed = LanderYSpeed +
Gravity * T
The gravity on the moon is about 1/6th the gravity on earth (which is 9.8
meters per second per second; the vertical speed changes 9.8 m/s every
second). So, in our program, we will use: Gravity = 9.8 / 6.0
You can change this if you like to simulate other planets or see how fast a
lander descends on the earth (just use 9.8).
This completes the “update” equations for the lunar lander’s position and
speed. Let’s modify the program to include these equations and get the
lander moving. We initialize LanderX, LanderY, SpeedX, and SpeedY in
the StartPauseButtonClick subroutine. For now, we set all the variables to
zero. Later, we will randomly assign LanderX. The shaded changes are (we
don’t show the entire subroutine, just the modified part): Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
LanderX = 0
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub
Each of these numbers (except Gravity) was found by trial and error. You
may want to make changes – feel free.
These routines update the different speeds due to thrust (when GameStatus
is “Playing”).
Recall both lander position and speed are updated in the TimerTickSub
subroutine. The steps to follow in this subroutine are:
Add this code segment at the end of the UpdateStatus subroutine to display
lander status. This code displays position and speed information (converting
to proper units using the Multiplier variable): 'positions
Shapes.SetText(DisplayVerticalPosition, Math.Floor(LanderY *
Multiplier)) Shapes.SetText(DisplayLateralPosition,Math.Floor(LanderX
* Multiplier)) 'speeds
NumberToFormat = LanderYSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayVerticalSpeed, NumberText) NumberToFormat =
LanderXSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayLateralSpeed, NumberText) Save and Run the
program. Select Junior Pilot Level. Click Start Game. The time will
increment, as will the position and speed in the vertical direction (labeled
as Altitude). Click the down thrust button and see the vertical speed
decrease. Try the horizontal thrusters to make sure you can move the
lander left and right (labeled as Lateral). Here’s the middle of a run I
made:
Believe it or not, the basics of the moon landing program are done – we can
control the lander and see its location and speed (in displayed values). But
there is still a lot of work to be done to make this an appealing, useful
game. Let’s outline the needed work, then get started.
We need to modify the game to account for differences among the various
pilot levels, including monitoring fuel consumption. And, of course, we
need some sounds. After this, we will have a working ‘text version’ of the
game.
The text version of the game is acceptable, but graphics elements add that
extra flair. The first graphic element we add is the trajectory display under
the status displays. After tackling the trajectory display, we move on to the
animated display of the lander moving across the landscape to the landing
pad And the final addition to Moon Landing will be development of an
auto-pilot. This serves two purposes. First, the auto-pilot is actually needed
for the Novice pilot level (where you control horizontal thrust, while the
computer handles the vertical thrust). Second, auto-pilot mode is a good
way to learn how to control the landing vehicle.
As noted, the current displayed values do not answer the question – how far
are we from the landing pad? Let’s add the Pad element (a red rectangle) to
the landscape element and determine what these distances are. The Pad
element is located at (PadX, PadY), has width PadWidth and height
PadHeight:
In this sketch, we’ve added two distances. Altitude specifies how far the
lander is above the pad. It is the distance from the bottom of the lander to
the top of the pad: Altitude = (LandscapeHeight ‐ PadHeight) ‐ (LanderY +
LanderHeight) Notice Altitude decreases as the lander goes down
(LanderY increases). This is opposite of our basic coordinate system, but it
makes sense here. Altitude represents the height above the pad – it
approaches zero as the lander gets closer to the pad.
The other distance, Lateral, specifies the horizontal distance from the
lander to the pad. It is the distance from the middle of the lander to the
middle of the pad: Lateral = (LanderX + (LanderWidth / 2)) ‐ (PadX +
(PadWidth / 2)) Notice Lateral is positive if the lander is the right of the
pad, negative if it is to the left of the pad. Lateral is zero if the lander is
directly centered over the pad.
We can add these equations to our program to get proper indication of
Altitude and Lateral, but there’s one problem. We don’t know the sizes of
the various elements (Landscape, Pad, Lander). We’ll fix that now. The
Landscape will simply be a black rectangular area 640 pixels wide by 700
pixels high. Recall we assume one pixel equals one meter in distance.
Similarly, the landing pad (Pad) will be a red rectangle 105 pixels wide (the
width of the Lander) and 15 pixels high.
Having the display element dimensions now allows us to modify the code
to include computations and display of Altitude and Lateral. The
computations of Altitude and Lateral will be placed in the UpdateStatus
subroutine. Make the shaded changes to this subroutine: Sub UpdateStatus
'Time
NumberToFormat = Time DecimalFormat()
Shapes.SetText(DisplayTime, NumberText) 'Positions
Altitude = (LandscapeHeight ‐ PadHeight) ‐ (LanderY +
LanderHeight) Lateral = (LanderX + (LanderWidth / 2)) ‐ (PadX +
(PadWidth / 2)) If (Altitude > 0) Then
Shapes.SetText(DisplayVerticalPosition, Math.Floor(Altitude *
Multiplier))
Else
Shapes.SetText(DisplayVerticalPosition, 0) EndIf
If Math.Abs(Lateral) < 1 Then
Shapes.SetText(DisplayLateralPosition, "Above") Else
Shapes.SetText(DisplayLateralPosition, Math.Floor(Lateral *
Multiplier))
EndIf
'speeds
NumberToFormat = ‐LanderYSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayVerticalSpeed, NumberText)
NumberToFormat = LanderXSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayLateralSpeed, NumberText) EndSub
We have the equations for Altitude and Lateral. For the vertical position
label, LanderY has been replaced by Altitude (limiting the value to zero).
In the vertical speed label, a negative sign has been added to show negative
speed is altitude descent. For horizontal position, LanderX has been
replaced by Lateral (with a note of Above if within 1 meter).
We can almost test the changes. We need to place the pad on the landscape.
With each new game, we will randomly set the horizontal position of the
pad (and the lander) within the landscape rectangle. The pad will be placed
on the bottom of the rectangle. Make the shaded changes in the
StartPauseButtonClick subroutine: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
PadX = Math.GetRandomNumber(LandscapeWidth ‐ PadWidth)
‐1
PadY = LandscapeHeight ‐ PadHeight
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub
These new lines randomly place the lander and pad within the bounds of the
Landscape width.
Save and Run the program. Again, chose Junior level pilot and click Start
Game. You will now see the altitude drop as the speed becomes larger in a
negative sense (descent). The lateral position will approach zero as the
lander gets closer to the pad. Here’s my screen after 9.5 seconds:
Code Design – Landing Detection
If you continue to run the game as programmed, Altitude will stop at zero
(it takes around 26 to 27 seconds), but the speed will continue to increase
and you can still apply thrust. We need someway to detect a landing and
determine if it is a safe landing. We will do this in the TimerTickSub
subroutine. In InitializeProgram, add this variable (with other such
variables) defining the maximum acceptable landing speed:
SafeLandingSpeed = 3.0
In this code, once Altitude reaches zero, the Timer is paused, the thruster
buttons are removed and the appropriate landing message is displayed
based on the vertical speed (and based on whether auto-pilot is on). No
penalty is incurred for missing the landing pad (large value of Lateral).
Save and Run the program again. Now, once the lander altitude reaches
zero, the program will stop and display status upon landing. Here’s my
screen:
I crashed badly. At this point, you can choose to play another game, set
options or exit the program.
One little problem. If you click Start Game, the “You Crashed” message
will still be there. Add the shaded line to StartPauseButtonClick
subroutine to erase this message when starting a new game: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
'clear any previous message from viewer
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop,
ViewerWidth, 60) Controls.SetButtonCaption(StartPauseButton,
"Pause Game") Controls.SetButtonCaption(ExitStopButton, "Stop
Game") Controls.HideControl(OptionsButton) 'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
PadX = Math.GetRandomNumber(LandscapeWidth ‐ PadWidth)
‐1
PadY = LandscapeHeight ‐ PadHeight UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub
If you like rerun the previous example, then press Start Game to make sure
the message disappears.
These calculations are ‘relative to’ the Guide area, or assume the upper left
corner of Guide is at (0, 0). Prior to using them for positioning the boxes,
they are offset by the true upper corner (GuideLeft, GuideTop).
Add this code segment at the end of the UpdateStatus subroutine: 'location
box
LanderBoxX = (LanderX + LanderWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ LanderBoxWidth / 2
If (LanderBoxX < 0) Then LanderBoxX = 0
ElseIf (LanderBoxX > (GuideWidth ‐ LanderBoxWidth)) Then
LanderBoxX = GuideWidth ‐ LanderBoxWidth EndIf
Shapes.Move(LanderBox, GuideLeft + LanderBoxX, GuideTop) The
code makes sure LanderBox stays within Guide.
Save and Run the program. The green and red boxes will show the relative
horizontal location of the lander to the pad. Here’s my screen:
The lander (green) is to the right of the pad (red). This is also reflected in
the positive Lateral value of 204 meters.
If I apply right thrust, the lander will move to the left nearing the pad.
Here’s the screen a little later:
I’m now just 98 meters to the right, moving to the left. I think you see how
the graphic indicators are really nice. We’ll add even nicer ones (trajectory
panel and animated graphics) later. But, first, just a few more changes to
complete needed coding.
Code – Pilot Levels and Sounds
The Moon Landing game is becoming more complete. The last big change
is adding the graphics features. Before doing that we need to add just a few
other changes.
Lastly, the fuel gauge is updated in the UpdateStatus subroutine. Add this
code segment at the end of the subroutine: 'fuel
If (PilotLevel > 3) Then If (FuelRemaining > 0) Then FuelValue =
(FuelRemaining / MaximumFuel) * FuelWidth Else
FuelValue = 0
EndIf
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(FuelLeft + FuelValue, FuelTop,
FuelWidth ‐ FuelValue, FuelHeight) EndIf
We ‘black’ out the portion of the Fuel area corresponding to fuel used.
Save and Run the program. Select Senior pilot level. As the lander
descends, apply horizontal and vertical thrust and watch the fuel gauge
drop. Here’s my window after several bursts of thrust:
In the lowest pilot level (Beginner; PilotLevel = 1), the landing pad needs
to be directly under the lander, since horizontal thrusters are not available.
This is done in the StartPauseButtonClick subroutine (new code shaded):
Sub StartPauseButtonClick If (GameStatus = "Stopped") Then .
.
.
'initialize values
Time = 0.0
LanderX = Math.GetRandomNumber(LandscapeWidth ‐
LanderWidth) ‐ 1
LanderY = 0
LanderXSpeed = 0
LanderYSpeed = 0
If (PilotLevel <> 1) Then
PadX = Math.GetRandomNumber(LandscapeWidth ‐
PadWidth) ‐ 1
Else
PadX = LanderX + (LanderWidth / 2) ‐ PadWidth / 2
EndIf
PadBoxX = (PadX + PadWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ PadBoxWidth / 2
Shapes.Move(PadBox, GuideLeft + PadBoxX, GuideTop) PadY
= LandscapeHeight ‐ PadHeight FuelRemaining = MaximumFuel
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Green"
GraphicsWindow.FillRectangle(FuelLeft, FuelTop,
FuelWidth, FuelHeight) EndIf
UpdateStatus()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
.
Else
.
.
.
EndIf
EndSub
Save and Run the program. Select Beginner level. Click Start Game.
Make sure the pad is under the lander. Here’s what I see:
Notice Lateral position is listed as Above. Also note the red box
(representing the pad) under the viewer area completely covers the green
box.
The last change we need to make regarding pilot level is with the
Advanced level. In this level, we want the thrusters to be unpredictable,
generating random amounts of thrust. For horizontal and vertical thrust, we
will have anywhere from 0 to twice the maximum available delta in speed.
These changes are made in the thruster button click events. The changes are
shaded: Sub DownThrustButtonClick If (GameStatus = "Playing") Then If
(FuelRemaining > 0) Then
If (PilotLevel <> 5) Then
LanderYSpeed = LanderYSpeed ‐ YDelta
Else
LanderYSpeed = LanderYSpeed ‐ 2 * YDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
VFuel EndIf
EndIf
EndIf
EndSub
Save and Run the program. Try the Advanced level and watch the fuel go
down very fast. This completes all but one change needed for pilot level.
The one change still needed is related to the Novice level (PilotLevel = 2).
At that level, you only control the horizontal thrusters to practice moving in
the lateral direction. The vertical thrust is controlled by the computer auto-
pilot. Since we haven’t coded the auto-pilot yet, you are guaranteed to crash
at Novice level (until we’ve completed the Moon Landing program, that
is).
One last change before tackling all the graphic effects – let’s add sounds. In
the KidGamesSB\KidGamesSB Programs\MoonLanding folder are four
wav files. The file vthrust.wav is played when vertical thrust is applied,
hthrust.wav is played when horizontal thrust is applied, safe.wav is played
following a safe landing, while crash.wav is played is you crash. Copy the
four files to your program’s folder.
The vertical thrust sound is played when vertical (down) thrust is applied.
Add the two shaded lines to the DownThrustButtonClick subroutine: Sub
DownThrustButtonClick If (GameStatus = "Playing") Then If
(FuelRemaining > 0) Then
Sound.Stop(Program.Directory + "\vthrust.wav")
Sound.Play(Program.Directory + "\vthrust.wav")
If (PilotLevel <> 5) Then LanderYSpeed = LanderYSpeed ‐
YDelta Else
LanderYSpeed = LanderYSpeed ‐ 2 * YDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
VFuel EndIf
EndIf
EndIf
EndSub
The horizontal thrust sound is played when either left or right thrust is
applied. Add the shaded lines to the LeftThrustButtonClick and
RightThrustButtonClick subroutines: Sub LeftThrustButtonClick If
(GameStatus = "Playing") Then If (FuelRemaining > 0) Then
Sound.Stop(Program.Directory + "\hthrust.wav")
Sound.Play(Program.Directory + "\hthrust.wav")
If (PilotLevel <> 5) Then LanderXSpeed = LanderXSpeed +
XDelta Else
LanderXSpeed = LanderXSpeed + 2 * XDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
HFuel EndIf
EndIf
EndIf
EndSub
Save and Run the program. Select a pilot level and play a game. Make sure
you hear sounds when the thrusters are applied. Make sure the proper
landing sound plays. You’ll have to figure out how to do a safe landing
(speed under -3 meters/second) to hear the safe landing sound!
The first display we will develop is in the Trajectory rectangle on the right
side of the window. In this rectangle, we will draw a line indicating the
desired path from the lander to the pad. This line will connect the initial
lander position with the landing pad position to give you (and later the auto-
pilot) a suggested trajectory (path) to follow while landing. It only needs to
be drawn once (at the beginning of the descent). We will also draw the path
followed by the lander as it descends.
Let’s look a sketch of the initial lander and pad location on the Landscape
element:
The line we want to draw is shown in black, connecting the bottom middle
of the lander with the top center of the pad. The Cartesian pair at the bottom
of the lander is: X = LanderX + LanderWidth / 2
Y = LanderY + LanderHeight And the middle of the landing pad:
X = PadX + Pad.Width / 2
Y = PadY + PadHeight The coordinates given are relative to the size of
the landscape element and we want to draw the line in the trajectory
element (we know the dimensions of both). Hence, prior to drawing the
line, we need to scale the X and Y coordinates to fit the points within the
Trajectory rectangle. Each X coordinate is multiplied by
TrajectoryXScale: TrajectoryXScale = TrajectoryWidth /
LandscapeWidth and the Y coordinate is multiplied by
TrajectoryYScale: TrajectoryYScale = TrajectoryHeight /
LandscapeHeight Calculations assume the upper left corner of
Trajectory is at (0, 0). Prior to using computed points for drawing a line,
they are offset by the true upper corner (TrajectoryLeft,
TrajectoryTop).
Let’s make the code modifications to get the line drawn. Create a new
subroutine (UpdateTrajectory) with the code to draw the trajectory line:
Sub UpdateTrajectory TrajectoryXScale = TrajectoryWidth /
LandscapeWidth TrajectoryYScale = TrajectoryHeight / LandscapeHeight
If (Time = 0.0) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight) GraphicsWindow.PenColor =
"Red"
GraphicsWindow.PenWidth = 2
'four points for red trajectory line
x1 = TrajectoryLeft + TrajectoryXScale * (LanderX +
LanderWidth / 2) y1 = TrajectoryTop + TrajectoryYScale *
(LanderY + LanderHeight) x2 = TrajectoryLeft +
TrajectoryXScale * (PadX + PadWidth / 2) y2 = TrajectoryTop +
TrajectoryYScale * (PadY + PadHeight)
GraphicsWindow.DrawLine(x1, y1, x2, y2) EndIf
EndSub
This code compute the trajectory line endpoints and connects them with a
red line. Right now, this subroutine is only used for the initial line. We will
modify it soon to display the trajectory followed by the lander.
Save and Run the program. Select a pilot level and click Start Game. You
should now see the trajectory to the pad in the Trajectory area. Here’s my
example:
The circle is centered at the bottom of the lander graphic element. That
point was earlier defined by: X = LanderX + LanderWidth / 2
Y = LanderY + LanderHeight Recall this position is relative to the
landscape element hence each point needs to be scaled to fit within the
Trajectory element.
A circle is drawn with each new lander position update. Place the shaded
line in the TimerTickSub subroutine: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory()
'check for landing
If (Altitude <= 0) Then .
.
.
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub
Save and Run the program. Select a pilot level, click Start Game. Try to
land safely using the thrusters. You should see that the Trajectory display
provides a useful indication of where the lander is located relative to the
pad. And you get a plot of the trajectory followed to landing. Here’s a run I
made (Junior pilot level):
I didn’t stay real close to the suggested trajectory, but I made a pretty good
landing!
The trajectory display is useful in helping land on the moon safely. But, we
can do better. Let’s develop an animated display of the lander as it descends
onto the landing pad. We place this animation in the Viewer region on the
left of the window.
Code Design – Lander Animation
We will use the Shapes object Move method to position this in the Viewer
region. The lander.gif file included in the KidGamesSB\KidGamesSB
Programs\MoonLanding folder. Copy it to your program’s folder.
The Viewer region moves within the Landscape element (which includes
the entire area the lander can move within). We choose to keep the lander
image centered within the Viewer (if possible). Superimposing the viewer
on the landscape (also showing the lander in the green box, we have:
Notice we said we would center the lander in the viewer, if possible. There
are four cases where we will not be able to center the lander, each related to
being beyond one of the four borders of the landscape. Let’s look at each
border and the limiting values of LandscapeX and LandscapeY: Left
border, LandscapeX > 0
Right border, LandscapeX < LandscapeWidth – ViewerWidth Top
border, LandscapeY > 0
Bottom border, LandscapeY < LandscapeHeight – ViewerHeight In
these limiting cases, we will relax the need to center the lander and allow
it to move freely (although always keeping it in the viewer).
Now, let’s get the lander moving. Add this code in InitializeProgram (after
the lines setting dimensions of the landscape and lander) to create the
Lander shape and initially place it at the top center of the viewer. We also
compute CenterX and CenterY: 'Create shapes
Lander = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\lander.gif")) Shapes.Move(Lander, ViewerLeft + 0.5 * (ViewerWidth ‐
LanderWidth), ViewerTop) CenterX = (ViewerWidth ‐ LanderWidth) / 2
CenterY = (ViewerHeight ‐ LanderHeight) / 2
Double-check that you copied the lander graphics file to your program’s
folder.
Save and Run the program to make sure the lander appears:
Add a subroutine (UpdateViewer) for the code associated with the landing
animation: Sub UpdateViewer
'position lander
ViewLanderX = CenterX
ViewLanderY = CenterY
'adjust landscape background
LandscapeX = LanderX ‐ CenterX
If (LandscapeX <= 0) Then LandscapeX = 0
ViewLanderX = LanderX
EndIf
If (LandscapeX >= LandscapeWidth ‐ ViewerWidth) Then
LandscapeX = LandscapeWidth ‐ ViewerWidth ViewLanderX =
LanderX ‐ LandscapeX
EndIf
LandscapeY = LanderY ‐ CenterY
If (LandscapeY <= 0) Then LandscapeY = 0
ViewLanderY = LanderY
EndIf
If (LandscapeY >= LandscapeHeight ‐ ViewerHeight) Then
LandscapeY = LandscapeHeight ‐ ViewerHeight ViewLanderY =
LanderY ‐ LandscapeY
EndIf
'keep lander in borders
If (ViewLanderX < 0) Then ViewLanderX = 0
ElseIf (ViewLanderX + LanderWidth > ViewerWidth) Then
ViewLanderX = ViewerWidth ‐ LanderWidth EndIf
If (ViewLanderY < 0) Then ViewLanderY = 0
EndIf
'show lander
Shapes.Move(Lander, ViewerLeft + ViewLanderX, ViewerTop +
ViewLanderY) EndSub
The code above determines LandscapeX and LandscapeY (being
cognizant of the borders). We also determine the lander position
(ViewLanderX, ViewLanderY). We adjust this position if we have moved
past any of the borders of the landscape. The Lander shape is then placed
in the viewer.
And, the viewer updates are done in the TimerTickSub subroutine (add
shaded line): Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory()
UpdateViewer()
'check for landing
If (Altitude <= 0) Then .
.
.
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub
Save and Run the program. Start a game with Junior Level. Immediately
click Pause Game. Here’s my screen:
You should now see a very nice animation of the landing process. Here’s
my screen:
Click Restart. As the lander nears the bottom on the landscape (eventually
we will have the landing pad appear in the viewer), it will no longer be
centered since the landscape is near its lower limit. Here’s my screen after a
crash landing:
Notice the lander moved a little toward the left – I applied some thrust to do
that.
Adding thruster flames is a cool effect. There are two files (hthrust.gif and
vthrust.gif) in the KidGamesSB\KidGamesSB Programs\MoonLanding
folder used for this effect. Copy these images to your program’s folder.
This image will be used for both the left and right thrust. The vertical thrust
image (vthrust.gif) is 24 pixels by 32 pixels (also twice actual size):
LeftThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\hthrust.gif")) RightThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\hthrust.gif")) DownThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\vthrust.gif")) Shapes.HideShape(LeftThrust)
Shapes.HideShape(RightThrust) Shapes.HideShape(DownThrust)
HThrustWidth = 32
HThrustHeight = 16
VThrustWidth = 24
VThrustHeight = 32
Drawing the thrust graphics in the viewer is straightforward. All of the code
goes in the UpdateViewer subroutine. Before modifying this subroutine,
we need one little change. To add thruster graphics to the animation, we
need to know if thrust is being applied. We use three variables
(DownThrustOn, LeftThrustOn, RightThrustOn) for this purpose.
Then, in each of the corresponding thrust control button subroutines, set the
value of these variables (shaded lines): Sub DownThrustButtonClick If
(GameStatus = "Playing") Then If (FuelRemaining > 0) Then
Sound.Stop(Program.Directory + "\vthrust.wav")
Sound.Play(Program.Directory + "\vthrust.wav")
DownThrustOn = "true"
If (PilotLevel <> 5) Then LanderYSpeed = LanderYSpeed ‐
YDelta Else
LanderYSpeed = LanderYSpeed ‐ 2 * YDelta *
Math.GetRandomNumber(100) / 100
EndIf
If (PilotLevel > 3) Then FuelRemaining = FuelRemaining ‐
VFuel EndIf
EndIf
EndIf
EndSub
Upon landing, we want to make sure the thrusters are off. Add the shaded
code change to the TimerTickSub subroutine: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory() UpdateViewer()
'check for landing
If (Altitude <= 0) Then
LeftThrustOn = "false"
RightThrustOn = "false"
DownThrustOn = "false"
UpdateViewer()
.
.
.
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub
Note we need to update the viewer after turning the thrusters off to make
sure they do not appear.
Here, the thrust shapes are added to the viewer (if the corresponding
thruster is on). The positions of the shapes were obtained by trial and error.
Save and Run the program. Start a game. Try out the thrusters. Here’s my
screen after applying a bit of right thrust:
Code Design – Displaying Pad
As the lander nears the bottom of the landscape, we want the landing pad (a
red rectangle) to appear in the viewer. To do this, we need to do a little bit
of math.
Here’s a sketch of the landscape, viewer and pad just as the pad enters the
bottom right of the viewer:
From this sketch, we see all or some of the Pad is in the Viewer when each
of these conditions holds: PadX >= LandscapeX
PadX <= LandscapeX + ViewerWidth
PadY > LandscapeY
PadY < LandscapeY + ViewerHeight
How much of the Pad is in the viewer (the red area in the sketch)? The
width (W) is: W = LandscapeX + ViewerWidth ‐ PadX
From this sketch, we see all or some of the Pad is in the Viewer when each
of these conditions holds: PadX + PadWidth > LandscapeX
PadX + PadWidth < LandscapeX + ViewerWidth
PadY > LandscapeY
PadY < LandscapeY + ViewerHeight
With this configuration, how much of the Pad is in the viewer (the red area
in the sketch)? The width (W) is: W = PadX + PadWidth ‐ LandscapeX
Save and Run the program. Try landing. As you near the bottom of the
landscape (Altitude under 100 meters or so), the landing pad should begin
to appear. Here is a run I made:
The lander is approaching the pad. I think you’ll agree you have a nice
game by now. We need one last change to make it complete. We need to
code the autopilot option.
Code Design - Autopilot
The auto-pilot option allows you to see how the computer controls the
lander as it descends to the moon. With auto-pilot, the computer controls
the horizontal and vertical thrusters in attempt to make a safe landing. The
goal is to be under a safe vertical landing speed (3 meters/second), while
being near the landing pad. We will develop the vertical and horizontal
thruster auto-pilots separately.
Like the game playing logic in Tic Tac Toe and Match Game, there are no
rigid rules for developing an auto-pilot. Like those games, I tried to develop
rules for how I (a human) might control the lander and put those rules into
code. Feel free to change any of the auto-pilot code as you see fit.
Here are the rules I use to automatically control the vertical (down) thruster
control:
In this new code, when the computer needs to apply thrust, it makes a direct
call to the DownThrustButtonClick subroutine. Notice we use auto-pilot
when AutoPilotOn is “true” or when PilotLevel = 2 (when you, the
human, only control horizontal thrust).
Save and Run the program. Click Options. Select Beginner pilot level.
Select the Auto-Pilot On option. Click Start Game. The computer takes
over (the first burst of thrust will occur when the downward speed exceeds
12 meters/sec) and brings the lander to a safe landing:
Run the game again, this time with Novice pilot level and auto-pilot off.
Make sure the computer provides the needed vertical thrust as you control
the horizontal thrust. Here’s my run with Novice level (not a bad job):
Now, let’s complete this game with some automatic horizontal thrust
control.
Or
As an aside, this is similar to logic used in the thermostat used to heat your
home. When the temperature is lower than the thermostat setting, the
furnace is turned on. When the temperature exceeds the setting, the furnace
is turned off. But, the furnace doesn’t turn on if the temperature is just
below the setting. It waits until the temperature difference (Miss) is about 2
degrees or so. The same difference in temperature is used before turning the
furnace back off. This keeps your furnace from just cycling on and off.
Let’s code the final element of the Moon Landing game – the horizontal
autopilot. The initial altitude and lateral distance are established in the
UpdateTrajectory subroutine (shaded changes): Sub UpdateTrajectory
TrajectoryXScale = TrajectoryWidth / LandscapeWidth TrajectoryYScale =
TrajectoryHeight / LandscapeHeight If (Time = 0.0) Then
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight) GraphicsWindow.PenColor = "Red"
GraphicsWindow.PenWidth = 2
'four points for red trajectory line
x1 = TrajectoryLeft + TrajectoryXScale * (LanderX +
LanderWidth / 2) y1 = TrajectoryTop + TrajectoryYScale * (LanderY +
LanderHeight) x2 = TrajectoryLeft + TrajectoryXScale * (PadX +
PadWidth / 2) y2 = TrajectoryTop + TrajectoryYScale * (PadY +
PadHeight) GraphicsWindow.DrawLine(x1, y1, x2, y2)
Altitude0 = Altitude Lateral0 = Lateral
EndIf
'location of circles
x1 = TrajectoryXScale * (LanderX + LanderWidth / 2) ‐ 3
If (x1 < 0) Then x1 = 0
ElseIf (x1 > TrajectoryWidth ‐ 6) Then x1 = TrajectoryWidth ‐ 6
EndIf
y1 = TrajectoryYScale * (LanderY + LanderHeight) ‐ 3
If (y1 < 0) Then y1 = 0
EndIf
'light green circles 6 x 6 pixels
GraphicsWindow.PenColor = "LightGreen"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawEllipse(TrajectoryLeft + x1, TrajectoryTop +
y1, 6, 6) EndSub
The code for the horizontal auto-pilot is placed under the vertical auto-pilot
code in the TimerTickSub subroutine. The additions are noted by the
shaded code: Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000)
LanderY = LanderY + LanderYSpeed * (Timer.Interval / 1000)
UpdateStatus()
UpdateTrajectory() UpdateViewer()
'check for landing
If (Altitude <= 0) Then .
.
.
EndIf
'autopilot or Novice level ‐ adjust vertical thrust If (AutoPilotOn Or
PilotLevel = 2) Then If (Altitude > 300) Then If (LanderYSpeed >
12) Then DownThrustButtonClick() EndIf
ElseIf Altitude > 100 Then If LanderYSpeed > 6 Then
DownThrustButtonClick() EndIf
Else
If LanderYSpeed > (2 + 0.04 * Altitude) Then
DownThrustButtonClick() EndIf
EndIf
EndIf
'autopilot ‐ adjust horizontal thrust
If (AutoPilotOn) Then Miss = Lateral ‐ Altitude * (Lateral0 /
Altitude0) If (Miss > 2) Then RightThrustButtonClick() ElseIf (Miss
< ‐2) Then LeftThrustButtonClick() EndIf
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub
Save the program one last time. Run the program. Select Senior pilot level,
and turn Auto-Pilot On. Here’s the game after 4.0 seconds of running (I
paused at this point):
The auto-pilot is applying some left thrust, accelerating the lander to a
lateral speed of 2.2 meters/second, moving the lander toward the trajectory
line (see trajectory display).
The computer has applied several bursts of vertical thrust to keep the lander
vertical speed reasonable and used a few horizontal thrusts to keep the
lander near the desired trajectory.
A near perfect landing under the safe landing speed of -3.0 m/s and almost
right on top of the pad.
The game is now complete. As you play, it will become obvious that there
are many ways to obtain a safe landing with the vehicle. Without a fuel
constraint, you can take forever to land. A more interesting problem is to try
to land as fast as possible. This is the so-called minimum time problem.
Or try to land using the least fuel possible - an important problem in space
travel where you don't want to launch a lot of unnecessary weight.
Try a so-called ‘coast and burn’ approach. That is, let your lander keep
dropping until some point where you apply nearly constant vertical thrust
until landed. This approach needs to be used in space vehicles where
thrusters can only be turned on, but never off (like solid rocket motors).
Moon Landing Game Program Listing
Here is the complete listing of the Moon Landing Small Basic program: '
Moon Landing
InitializeProgram() Sub InitializeProgram 'graphics window
GraphicsWindow.Width = 600
GraphicsWindow.Height = 400
GraphicsWindow.Title = "Moon Landing"
GraphicsWindow.BackgroundColor =
GraphicsWindow.GetColorFromRGB(192, 192, 255) ' draw view screen
GraphicsWindow.BrushColor = "Blue"
GraphicsWindow.FillRectangle(0, 0, 300, 400)
GraphicsWindow.BrushColor = "Black"
ViewerLeft = 10
ViewerTop = 10
ViewerWidth = 280
ViewerHeight = 360
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop, ViewerWidth,
ViewerHeight) GraphicsWindow.BrushColor = "SlateGray"
GuideLeft = 10
GuideTop = 370
GuideWidth = 280
GuideHeight = 20
GraphicsWindow.FillRectangle(GuideLeft, GuideTop, GuideWidth,
GuideHeight) GraphicsWindow.BrushColor = "Red"
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
PadBox = Shapes.AddRectangle(15, 20) GraphicsWindow.BrushColor =
"Green"
LanderBox = Shapes.AddRectangle(15, 20) Shapes.Move(PadBox, 20,
GuideTop) Shapes.Move(LanderBox, 100, GuideTop) PadBoxWidth =
15
LanderBoxWidth = 15
'Default Options
PilotLevel = 1
AutoPilotOn = "false"
MetricUnits = "true"
'create display shapes
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
DisplayTime = Shapes.AddText("") Shapes.Move(DisplayTime, 420, 30)
DisplayVerticalPosition = Shapes.AddText("")
Shapes.Move(DisplayVerticalPosition, 420, 75) DisplayVerticalSpeed =
Shapes.AddText("") Shapes.Move(DisplayVerticalSpeed, 520, 75)
DisplayLateralPosition = Shapes.AddText("")
Shapes.Move(DisplayLateralPosition, 420, 100) DisplayLateralSpeed =
Shapes.AddText("") Shapes.Move(DisplayLateralSpeed, 520, 100)
'define buttons
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 16
'thrust buttons
LeftThrustButton = Controls.AddButton("Left", 360, 320)
DownThrustButton = Controls.AddButton("Down", 425, 320)
RightThrustButton = Controls.AddButton("Right", 490, 320)
Controls.SetSize(LeftThrustButton, 60, 31)
Controls.SetSize(DownThrustButton, 60, 31)
Controls.SetSize(RightThrustButton, 60, 31) 'Other buttons
StartPauseButton = Controls.AddButton("Start Game", 305, 360)
Controls.SetSize(StartPauseButton, 110, 31) OptionsButton =
Controls.AddButton("Options", 417, 360) ExitStopButton =
Controls.AddButton("Exit", 485, 360) Controls.SetSize(ExitStopButton,
110, 31) SetDisplay()
GameStatus = "Stopped"
'Simulation variables
XDelta = 1.2
YDelta = 2.4
Gravity = 9.8 / 6.0
Drag = 0.1
SafeLandingSpeed = 3.0
MaximumFuel = 100
HFuel = 0.5
VFuel = 1.0
'Set dimensions
LandscapeWidth = 640
LandscapeHeight = 700
LanderWidth = 105
LanderHeight = 115 PadWidth = LanderWidth PadHeight = 15
'Create shapes
Lander = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\lander.gif")) Shapes.Move(Lander, ViewerLeft + 0.5 * (ViewerWidth ‐
LanderWidth), ViewerTop) LeftThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\hthrust.gif")) RightThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\hthrust.gif")) DownThrust =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\vthrust.gif")) Shapes.HideShape(LeftThrust)
Shapes.HideShape(RightThrust) Shapes.HideShape(DownThrust)
HThrustWidth = 32
HThrustHeight = 16
VThrustWidth = 24
VThrustHeight = 32
CenterX = (ViewerWidth ‐ LanderWidth) / 2
CenterY = (ViewerHeight ‐ LanderHeight) / 2
Controls.ButtonClicked = ButtonClickedSub Timer.Interval = 500
Timer.Tick = TimerTickSub Timer.Pause() EndSub
Sub SetDisplay
'clear what is there first
GraphicsWindow.BrushColor = GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(300, 0, 300, 400) 'titling information
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontBold = "false"
GraphicsWindow.FontSize = 20
T = "Landing Control ‐ "
If (PilotLevel = 1) Then T = T + "Beginner"
ElseIf (PilotLevel = 2) Then T = T + "Novice"
ElseIf (PilotLevel = 3) Then T = T + "Junior"
ElseIf (PilotLevel = 4) Then T = T + "Senior"
ElseIf (PilotLevel = 5) Then T = T + "Advanced"
EndIf
GraphicsWindow.DrawText(310, 0, T) GraphicsWindow.FontSize = 16
GraphicsWindow.DrawText(310, 30, "Time (s)") If (MetricUnits) Then
Multiplier = 1.0
GraphicsWindow.DrawText(390, 50, "Position (m)")
GraphicsWindow.DrawText(490, 50, "Speed (m/s)") Else
Multiplier = 3.2808
GraphicsWindow.DrawText(390, 50, "Position (ft)")
GraphicsWindow.DrawText(490, 50, "Speed (ft/s)") EndIf
GraphicsWindow.DrawText(310, 75, "Altitude")
GraphicsWindow.DrawText(310, 100, "Lateral") 'rectangles for data
display
GraphicsWindow.BrushColor = "White"
GraphicsWindow.FillRectangle(390, 30, 90, 20)
GraphicsWindow.FillRectangle(390, 75, 90, 20)
GraphicsWindow.FillRectangle(390, 100, 90, 20)
GraphicsWindow.FillRectangle(490, 75, 90, 20)
GraphicsWindow.FillRectangle(490, 100, 90, 20)
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(390, 30, 90, 20)
GraphicsWindow.DrawRectangle(390, 75, 90, 20)
GraphicsWindow.DrawRectangle(390, 100, 90, 20)
GraphicsWindow.DrawRectangle(490, 75, 90, 20)
GraphicsWindow.DrawRectangle(490, 100, 90, 20) 'fuel display
FuelLeft = 350
FuelTop = 130
FuelWidth = 240
FuelHeight = 20
If (PilotLevel > 3) Then GraphicsWindow.BrushColor = "Black"
GraphicsWindow.DrawText(310, 130, "Fuel")
GraphicsWindow.PenColor = "Black"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawRectangle(FuelLeft, FuelTop, FuelWidth,
FuelHeight) EndIf
'trajectory screen
TrajectoryLeft = 310
TrajectoryTop = 160
TrajectoryWidth = 280
TrajectoryHeight = 150
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(TrajectoryLeft, TrajectoryTop,
TrajectoryWidth, TrajectoryHeight) 'thrust buttons
If (AutoPilotOn) Then Controls.HideControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.HideControl(RightThrustButton) LeftThrustVisible = "false"
DownThrustVisible = "false"
RightThrustVisible = "false"
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FontSize = 20
GraphicsWindow.DrawText(390, 320, "Auto‐Pilot On") Else
'buttons based on level
If (PilotLevel = 1) Then Controls.HideControl(LeftThrustButton)
Controls.ShowControl(DownThrustButton)
Controls.HideControl(RightThrustButton) LeftThrustVisible =
"false"
DownThrustVisible = "true"
RightThrustVisible = "false"
ElseIf (PilotLevel = 2) Then
Controls.ShowControl(LeftThrustButton)
Controls.HideControl(DownThrustButton)
Controls.ShowControl(RightThrustButton) LeftThrustVisible =
"true"
DownThrustVisible = "false"
RightThrustVisible = "true"
Else
Controls.ShowControl(LeftThrustButton)
Controls.ShowControl(DownThrustButton)
Controls.ShowControl(RightThrustButton) LeftThrustVisible =
"true"
DownThrustVisible = "true"
RightThrustVisible = "true"
EndIf
EndIf
UpdateStatus()
EndSub
Sub UpdateStatus
'Time
NumberToFormat = Time DecimalFormat()
Shapes.SetText(DisplayTime, NumberText) 'Positions
Altitude = (LandscapeHeight ‐ PadHeight) ‐ (LanderY + LanderHeight)
Lateral = (LanderX + (LanderWidth / 2)) ‐ (PadX + (PadWidth / 2)) If
(Altitude > 0) Then Shapes.SetText(DisplayVerticalPosition,
Math.Floor(Altitude * Multiplier)) Else
Shapes.SetText(DisplayVerticalPosition, 0) EndIf
If Math.Abs(Lateral) < 1 Then Shapes.SetText(DisplayLateralPosition,
"Above") Else
Shapes.SetText(DisplayLateralPosition, Math.Floor(Lateral *
Multiplier)) EndIf
'speeds
NumberToFormat = ‐LanderYSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayVerticalSpeed, NumberText) NumberToFormat =
LanderXSpeed * Multiplier DecimalFormat()
Shapes.SetText(DisplayLateralSpeed, NumberText) 'location box
LanderBoxX = (LanderX + LanderWidth / 2) * (GuideWidth /
LandscapeWidth) ‐ LanderBoxWidth / 2
If (LanderBoxX < 0) Then LanderBoxX = 0
ElseIf (LanderBoxX > (GuideWidth ‐ LanderBoxWidth)) Then
LanderBoxX = GuideWidth ‐ LanderBoxWidth EndIf
Shapes.Move(LanderBox, GuideLeft + LanderBoxX, GuideTop) 'fuel
If (PilotLevel > 3) Then If (FuelRemaining > 0) Then FuelValue =
(FuelRemaining / MaximumFuel) * FuelWidth Else
FuelValue = 0
EndIf
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(FuelLeft + FuelValue, FuelTop,
FuelWidth ‐ FuelValue, FuelHeight) EndIf
EndSub
Sub SetOptions
GraphicsWindow.Hide() TextWindow.Show() TextWindow.Title =
"Moon Landing"
TextWindow.CursorLeft = 3
TextWindow.CursorTop = 3
TextWindow.WriteLine("MOON LANDING OPTIONS")
TextWindow.WriteLine("") GetPilotLevel:
TextWindow.CursorLeft = 3
TextWindow.WriteLine("What level pilot do you want?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Beginner, 2‐Novice, 3‐Junior, 4‐Senior, 5‐
Advanced) ") PilotLevel = TextWindow.ReadNumber() If (PilotLevel < 1
Or PilotLevel > 5) Then Goto GetPilotLevel EndIf
GetAutoPilotOn:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("Do you want Auto‐Pilot on?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Yes, 2‐No) ") T = TextWindow.ReadNumber() If
(T < 1 Or T > 2) Then Goto GetAutoPilotOn EndIf
If (T = 1) Then AutoPilotOn = "true"
Else
AutoPilotOn = "false"
EndIf
GetUnits:
TextWindow.WriteLine("") TextWindow.CursorLeft = 3
TextWindow.WriteLine("What units of distance do you want to use?")
TextWindow.CursorLeft = 3
TextWindow.Write("(1‐Meters, 2‐Feet) ") T =
TextWindow.ReadNumber() If (T < 1 Or T > 2) Then Goto GetUnits
EndIf
If (T = 1) Then MetricUnits = "true"
Else
MetricUnits = "false"
EndIf
SetDisplay()
TextWindow.Hide() GraphicsWindow.Show() EndSub
Sub TimerTickSub
'Clock Update
Time = Time + Timer.Interval / 1000
LanderX = LanderX + LanderXSpeed * (Timer.Interval / 1000) LanderY
= LanderY + LanderYSpeed * (Timer.Interval / 1000) UpdateStatus()
UpdateTrajectory() UpdateViewer()
'check for landing
If (Altitude <= 0) Then LeftThrustOn = "false"
RightThrustOn = "false"
DownThrustOn = "false"
UpdateViewer()
'display message
If (AutoPilotOn) Then Message = "Auto‐Pilot "
Else
Message = "You "
EndIf
'crash?
If (LanderYSpeed > SafeLandingSpeed) Then
Sound.Stop(Program.Directory + "\crash.wav")
Sound.Play(Program.Directory + "\crash.wav") Message = Message
+ "Crashed!"
Else
Sound.Stop(Program.Directory + "\safe.wav")
Sound.Play(Program.Directory + "\safe.wav") Message =
Message + "Landed Safely"
EndIf
'display message
GraphicsWindow.BrushColor = "Yellow"
GraphicsWindow.FontSize = 24
GraphicsWindow.DrawText(20, 30, Message) StopGame()
EndIf
'autopilot or Novice level ‐ adjust vertical thrust If (AutoPilotOn Or
PilotLevel = 2) Then If (Altitude > 300) Then If (LanderYSpeed > 12)
Then DownThrustButtonClick() EndIf
ElseIf Altitude > 100 Then If LanderYSpeed > 6 Then
DownThrustButtonClick() EndIf
Else
If LanderYSpeed > (2 + 0.04 * Altitude) Then
DownThrustButtonClick() EndIf
EndIf
EndIf
'autopilot ‐ adjust horizontal thrust
If (AutoPilotOn) Then Miss = Lateral ‐ Altitude * (Lateral0 / Altitude0)
If (Miss > 2) Then RightThrustButtonClick() ElseIf (Miss < ‐2) Then
LeftThrustButtonClick() EndIf
EndIf
'horizontal drag
If (LanderXSpeed > 0) Then LanderXSpeed = LanderXSpeed ‐ Drag
ElseIf (LanderXSpeed < 0) Then LanderXSpeed = LanderXSpeed +
Drag EndIf
'gravity
LanderYSpeed = LanderYSpeed + Gravity * (Timer.Interval / 1000)
EndSub
Sub DecimalFormat
WholeNumber = Math.Floor(NumberToFormat) Decimal =
Math.Floor(10 * (NumberToFormat ‐ WholeNumber)) NumberText =
Text.Append(WholeNumber, ".") If (Decimal = 0) Then NumberText =
Text.Append(NumberText, "0") Else
NumberText = Text.Append(NumberText, Decimal) EndIf
EndSub
Sub StopGame
GameStatus = "Stopped"
Timer.Pause() Controls.SetButtonCaption(StartPauseButton, "Start
Game") Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.ShowControl(OptionsButton) EndSub
Sub UpdateViewer
'position lander
ViewLanderX = CenterX
ViewLanderY = CenterY
'adjust landscape background
LandscapeX = LanderX ‐ CenterX
If (LandscapeX <= 0) Then LandscapeX = 0
ViewLanderX = LanderX
EndIf
If (LandscapeX >= LandscapeWidth ‐ ViewerWidth) Then LandscapeX
= LandscapeWidth ‐ ViewerWidth ViewLanderX = LanderX ‐
LandscapeX
EndIf
LandscapeY = LanderY ‐ CenterY
If (LandscapeY <= 0) Then LandscapeY = 0
ViewLanderY = LanderY
EndIf
If (LandscapeY >= LandscapeHeight ‐ ViewerHeight) Then LandscapeY
= LandscapeHeight ‐ ViewerHeight ViewLanderY = LanderY ‐
LandscapeY
EndIf
'keep lander in borders
If (ViewLanderX < 0) Then ViewLanderX = 0
ElseIf (ViewLanderX + LanderWidth > ViewerWidth) Then
ViewLanderX = ViewerWidth ‐ LanderWidth EndIf
If (ViewLanderY < 0) Then ViewLanderY = 0
EndIf
'show lander
Shapes.Move(Lander, ViewerLeft + ViewLanderX, ViewerTop +
ViewLanderY) 'add thrusters if on
If (DownThrustOn) Then Shapes.Move(DownThrust, ViewerLeft +
ViewLanderX + 0.5 * LanderWidth ‐ 0.5 * VThrustWidth, ViewerTop +
ViewLanderY + LanderHeight ‐ VThrustHeight)
Shapes.ShowShape(DownThrust) DownThrustOn = "false"
Else
Shapes.HideShape(DownThrust) EndIf
If (LeftThrustOn) Then Shapes.Move(LeftThrust, ViewerLeft +
ViewLanderX ‐ 5, ViewerTop + ViewLanderY + 40)
Shapes.ShowShape(LeftThrust) LeftThrustOn = "false"
Else
Shapes.HideShape(LeftThrust) EndIf
If (RightThrustOn) Then Shapes.Move(RightThrust, ViewerLeft +
ViewLanderX + LanderWidth ‐ HThrustWidth + 5, ViewerTop +
ViewLanderY + 40) Shapes.ShowShape(RightThrust) RightThrustOn =
"false"
Else
Shapes.HideShape(RightThrust) EndIf
'see if landing pad is in landscape
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop, ViewerWidth,
ViewerHeight) If (PadX >= LandscapeX And PadX <= LandscapeX +
ViewerWidth) Then If (PadY > LandscapeY And PadY < LandscapeY +
ViewerHeight) Then 'at right or completely in window
GraphicsWindow.BrushColor = "DarkRed"
W = LandscapeX + ViewerWidth ‐ PadX
If (W > PadWidth) Then W = PadWidth EndIf
H = LandscapeY + ViewerHeight ‐ PadY
GraphicsWindow.FillRectangle(ViewerLeft + PadX ‐
LandscapeX, ViewerTop + PadY ‐ LandscapeY, W, H) EndIf
ElseIf (PadX + PadWidth > LandscapeX And PadX + PadWidth <
LandscapeX + ViewerWidth) Then If (PadY > LandscapeY And PadY <
LandscapeY + ViewerHeight) Then 'at left
GraphicsWindow.BrushColor = "DarkRed"
W = PadX + PadWidth ‐ LandscapeX
H = LandscapeY + ViewerHeight ‐ PadY
GraphicsWindow.FillRectangle(ViewerLeft, ViewerTop + PadY ‐
LandscapeY, W, H) EndIf
EndIf
EndSub
Moon Landing Game Program Review
The Moon Landing game program is now complete. Save and Run the
program and make sure it works as promised. Check that all options work
correctly.
While completing this program, new concepts and skills you should have
gained include:
There are some ways to change the Moon Landing program. Some
possibilities are:
➢ It would be nice if the options selections you make are saved from
one game to the next. This requires the use of files which are
discussed in the next chapter.
➢ Add more elaborate graphic effects upon crash landings.
➢ Add keyboard control for the thrusters.
➢ Add a way to graphically see how close you are to a safe landing
speed (rather than just display the number).
➢ As implemented, you may notice a bit of a delay between hearing a
thruster and seeing the graphic display. This delay is because the
sound and drawing of the thrust are in two different subroutines. I
kind of like the delay – you hear the sound, then pretty soon the
flames start flying. If the delay bothers you, try to put the sound and
graphics in the same routine.
➢ The current game gives minimal evaluation of the landing, just
checking to see if the vertical speed is acceptable. Expand the
definition of a safe landing to include horizontal position and speed.
You might like to add some comments. In the original text versions
of this game, comments on the landing were quite cynical. Some
example comments for bad landings from these old programs are:
The game features fun graphics and multiple levels for challenging play.
While building the program, you learn more graphics capabilities and how to
work with data files (for saving high scores).
Leap Frog Program Preview
In this chapter, we will build a Leap Frog game. In the game, you move a
frog across a busy road, past a roaming snake and through a river with
interesting currents, to reach home safely. Once five frogs are safe, you
achieve a new level.
Now, click Start Game, then immediately click Pause Game to see what
the game screen looks like while playing:
That’s better – there’s things to see now. Let’s describe how the game is
played.
As you see, your frog starts out at the bottom. You use the keyboard arrow
keys to move the frog from the bottom of the screen into one of the safe
homes at the top. The first challenge is cross road with cars, trucks and
semis. The first two lanes travel right-to-left, while the third travels left-to-
right. If a vehicle collides with the frog or the frog collides with a vehicle, a
beep is heard and the frog’s journey stops. You lose a frog and try again (the
number of frogs you have remaining is shown in the upper right corner).
Restart the game and try to get the frog through the traffic. Pause the game
once you make it. Here’s what things look like after I made it (you can use
the up, down, left or right arrow keys to avoid traffic):
My score is up to 402 points. Notice the snake that just went by. Once you
cross the highway, this snake will pop up randomly, traveling left-to-right. If
the snake and frog collide, a sound is heard, the journey ends and a new frog
tries the trip.
After crossing the road and avoiding the snake, the frog needs to cross the
river by jumping onto floating logs to reach home. The Leap Frog game
features a river with unique current characteristics. As you go up, the first
row of logs travels left-to-right, the second travels right-to-left and the final
row travels left-to-right. Your job is to maneuver the frog across the logs and
move him into one of the homes at the top of the screen. If you miss a log,
miss home or float off the edge of the screen, a splashing sound is heard, the
journey ends and another frog gives it a try. If you successfully reach home,
the frog “ribbits,” you are given bonus points and another frog appears at the
bottom of the screen. Fill all five homes with frogs and you move to the next
level. As you go to higher levels, game play gets faster, more vehicles and
fewer logs appear.
Restart the game and try to get a frog home. You’ll find the home on the left
is the hardest to reach. Here’s my screen after getting four frogs home:
Then, when I get the final frog home, the game switches to Level 2:
A log has been removed and things are faster. I’ve been lucky so far and still
have all my frogs left.
As seen, at any time during the program, you may pause the action by
clicking Pause Game. To restart, click Restart Game. To stop the program
before running out of frogs, click Stop Game. Once a game is stopped, your
score is checked against other scores to see if you have one of the ten highest
scores. When I click Stop Game, after playing a bit longer, this text window
appears:
Continue playing Leap Frog to understand its operation. You’ll find it’s
quite addictive as you try to beat your past scores. Click Exit when you’re
done to stop the program. Look over the code, if you like.
You will now build this program in stages. As you build Small Basic
programs, we always recommend taking a slow, step-by-step process. It
minimizes programming errors and helps build your confidence as things
come together in a complete program.
Before beginning the Leap Frog program, we need to talk a bit about game
design. In this game (and all arcade type games), things are constantly
moving around and the code is checking to see where things are located and
whether they are colliding with other things. To do all this, we need specific
information about the size of the objects used in the game.
In Leap Frog, the basic object will be the frog. The program uses several
images to represent the frog moving up, down, left, right or sitting at home.
Each of these images is 40 pixels by 40 pixels. For example, the frog moving
up (FrogUp.gif, in the KidGamesSB\KidGamesSB Programs\LeapFrog
folder) is:
This frog needs to fit in a highway lane, in the area with the snake, on a
floating log in the river and in the home location at the top of the screen.
Hence, in designing the game form, each element, whether it is a panel
hosting graphics or an element within the panel (vehicle, snake, log), will be
sized with this basic ‘frog element’ in mind.
Three vehicles are used the game, a car, a truck and a semi, each vehicle
having a left moving image and a right moving image. The car is 40 pixels
by 40 pixels. Here is the left moving car (LeftCar.gif, in the
The truck is 80 pixels by 40 pixels (2 ‘frog units’). Here is the left moving
truck (LeftTruck.gif, in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder):
And, the semi is 120 pixels by 40 pixels (3 ‘frog units’). Here is the left
moving semi (LeftSemi.gif, in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder):
Similarly, three log sizes are used in the game. The smallest log is 40 pixels
by 40 pixels (SmallLog.gif, in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder):
Two snake images are used to give a slithering appearance. Each of these is
111 pixels by 24 pixels. Here is one of the images (Snake1.gif, in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder):
This images does violate our rule of being based on ‘frog units,’ but since we
only look for collisions with the snake, the rule is easily worked around.
Now, let’s start the game window, assigning specific sizes to the panel areas
based on these graphic elements.
Leap Frog Window Design
Here is a sketch for the window layout for the Leap Frog program:
The basic window layout is quite simple. There are areas at the top to keep
track of game scores. Then, several ‘panels’ are used to display the graphics
used in Leap Frog. The frog moves up the screen. The Start panel at the
bottom(green; 640 x 40 pixels) is where the frog begins its journey. The next
panel up is the Road (gray; 640 x 140 pixels) which has the moving traffic.
Then, a Grass panel (green; 640 x 40 pixels) with a snake, a River panel
(blue; 640 x 120 pixels) with floating logs and the Home panel (green; 640 x
80 pixels) has frog finishing spots. Two buttons at the bottom are used to
start/pause the game and to stop the game or exit the program. And a button
is used to display high scores.
We will now begin writing the code for the game. We will write the code in
several steps. We’ll start with the graphics elements. We have many things
moving around. In the previous chapter, we used the Shapes object and
introduced the idea of animation using the Move method. We do the same
here. First, we program the moving vehicles. Then, we add additional
elements to the game, one at a time. During the code development process,
recognize you may modify a particular subroutine several times before
arriving at the finished product.
As a first step, we build the basic game window and add the controlling
buttons. Put this code in the code window: ' Leap Frog
InitializeProgram()
And, add the three empty subroutines for each individual button click: Sub
StartPauseButtonClick EndSub
We will add code to each of these subroutines as we build the Leap Frog
game.
Save and Run the program. The three buttons will appear:
Code Design – Road Panel
In Leap Frog, the vehicles will move in the Road panel and motion will be
governed by the Small Basic Timer object. There are three different vehicles
(car, truck, semi), each with the capability of moving left or right. The
images used for each vehicle/direction are found in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder:
Recall cars are 40 pixels by 40 pixels, trucks are 80 pixels by 40 pixels and
semis are 120 pixels by 40 pixels. The program will assume these files are in
your program’s folder. Copy the six files to that folder.
The road panel will have three lanes (each 40 pixels high). In the top lane,
vehicles will travel from left to right. In the bottom two lanes, vehicles will
travel from right to left. Recall the road panel is 140 pixels high, 120 pixels
for the three travel lanes and the additional pixels for lane markings. The
layout of the road panel is (not to scale):
The border area of each lane is 5 pixels high. Make sure you see how the
total height is 140 pixels.
We will use 12 vehicles (at most, lower game levels will have fewer), four in
each lane. The vehicles will be represented by an array (Vehicle) of Shapes
objects. The assignments I made are (feel free to change these if you like):
Vehicle[1]: Semi, Top Lane Vehicle[2]: Truck, Top Lane Vehicle[3]: Car,
Top Lane Vehicle[4]: Car, Top Lane Vehicle[5]: Truck, Middle Lane
Vehicle[6]: Car, Middle Lane Vehicle[7]: Truck, Middle Lane Vehicle[8]:
Truck, Middle Lane Vehicle[9]: Car, Bottom Lane Vehicle[10]: Semi,
Bottom Lane Vehicle[11]: Car, Bottom Lane Vehicle[12]: Truck, Bottom
Lane Add this code to InitializeProgram to establish the Road panel and
images used for the vehicles: 'Vehicles on road
RoadTop = 290
RoadHeight = 140
DrawRoad()
NumberOfVehicles = 12
Vehicle[1] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightSemi.gif")) Vehicle[2] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightTruck.gif")) Vehicle[3] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightCar.gif")) Vehicle[4] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\RightCar.gif")) Vehicle[5] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[6] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[7] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[8] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) Vehicle[9] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[10] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftSemi.gif")) Vehicle[11] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftCar.gif")) Vehicle[12] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LeftTruck.gif")) For I = 1 to 12
Shapes.HideShape(Vehicle[I]) VehicleIsVisible[I] = "false"
EndFor
This defines the size and position of the Road panel (RoadTop,
RoadHeight) and draws the empty road (DrawRoad subroutine). That
subroutine is: Sub DrawRoad
GraphicsWindow.BrushColor = "DimGray"
GraphicsWindow.FillRectangle(0, RoadTop, GraphicsWindow.Width,
RoadHeight) 'draw road lines
GraphicsWindow.PenColor = "White"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawLine(0, RoadTop + 2, GraphicsWindow.Width,
RoadTop + 2) GraphicsWindow.DrawLine(0, RoadTop + RoadHeight
‐ 2, GraphicsWindow.Width, RoadTop + RoadHeight ‐ 2)
GraphicsWindow.DrawLine(0, RoadTop + 92,
GraphicsWindow.Width, RoadTop + 92) GraphicsWindow.PenColor =
"Yellow"
GraphicsWindow.DrawLine(0, RoadTop + 47,
GraphicsWindow.Width, RoadTop + 47)
GraphicsWindow.DrawLine(0, RoadTop + 49,
GraphicsWindow.Width, RoadTop + 49) EndSub
White lines are used to define the sides of the road and to separate the two
lower lanes. Two yellow lines separate the traffic moving in opposite
directions. After drawing the road, this code defines the 12 Shapes objects
(Vehicle array) we will use for the vehicles. Note the code expects all image
files to be in your program folder. After the vehicles are created, they are
hidden until the game begins. If we don’t do this, all the images will appear
in the upper left corner of the window (try it if you like). The array
VehicleIsVisible is used to indicate if a particular vehicle is visible.
Save and Run the program. You will see an empty road:
The vehicle positions are initialized when the Start Game button is clicked.
Let’s do that.
Save and Run the program. Click Start Game. The vehicles will appear on
a mainly empty window:
Notice the lane assignments, the directions and the nice initial spacing.
Check that the StartPauseButton caption properly reflects the current
status. Let’s get the vehicles moving.
The Timer object defines the motion of the vehicles (and all other motions
in the Leap Frog game). Add this code at the end of InitializeProgram:
Timer.Interval = 100
Timer.Tick = TimerTickSub Timer.Pause() This establishes the Interval,
assigns the TimerTickSub subroutine to the Tick event and turns off the
Timer initially.
We need code to turn the timer on and off at the proper times. Add the
shaded lines to the StartPauseButtonClick subroutine to accomplish this:
Sub StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus
= "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
PositionVehicles()
For I = 1 To NumberOfVehicles Shapes.ShowShape(Vehicle[I])
VehicleIsVisible[I] = "true"
EndFor
Timer.Resume()
ElseIf (GameStatus = "Playing") Then
Timer.Pause()
GameStatus = "Paused"
Controls.SetButtonCaption(StartPauseButton, "Restart Game")
Controls.HideControl(ExitStopButton) Else
'game restarted
GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.ShowControl(ExitStopButton)
Timer.Resume()
EndIf
EndSub
Once the timer is on, with each Tick event, each vehicle is repositioned
using the Move method of the Shapes object (and the Speed property).
Eventually, a vehicle will leave the road panel. What do we do once a
vehicle leaves the road panel? One possibility would be to immediately
restart the vehicle at the opposite end of the panel. The problem with this
approach is that if a large vehicle (say a semi) leaves the panel followed
immediately by a smaller vehicle, the two vehicles will overlap as they are
redrawn on the opposite end of the panel. To avoid this overlap, we will
‘delay’ redrawing cars by 80 pixels and ‘delay’ drawing trucks by 40 pixels.
This way, each vehicle is in its own buffer of 120 pixels (the size of a semi)
and no overlap will occur.
Add this code to the TimerTickSub subroutine. This code moves each
vehicle (if its VehicleIsVisible property is “true”). If a vehicle leaves the
right side of the form, it is repositioned to the left side of the form (VehicleX
= - 120 pixels, to maintain the 120 pixel buffer zone). If a vehicle leaves the
left side of the form, it is repositioned to the right side of the form (VehicleX
dependent on vehicle width, maintaining a 120 pixel buffer): Sub
TimerTickSub
'Road Update
For I = 1 To NumberOfVehicles If VehicleIsVisible[I] Then
VehicleX[I] = VehicleX[I] + VehicleSpeed[I]
Shapes.Move(Vehicle[I], VehicleX[I], VehicleY[I]) If
(VehicleX[I] > GraphicsWindow.Width And VehicleSpeed[I] >
0) Then VehicleX[I] = ‐120
EndIf
If (VehicleX[I] < ‐VehicleW[I] And VehicleSpeed[I] < 0) Then
VehicleX[I] = GraphicsWindow.Width + (120 ‐ VehicleW[I])
EndIf
EndIf
EndFor
EndSub
Study this code to make sure you see how things work.
Save and Run the program. Click Start Game and you have moving
vehicles! Notice how there is never any overlap in vehicles:
Make sure you can pause and restart the motion. The Stop Game button
doesn’t work yet – let’s fix that.
which uses the StopGame subroutine that implements the listed steps for
stopping: Sub StopGame
Timer.Pause() GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit") EndSub
Save and Run the program. Make sure you can start, pause and stop the
game. Make sure you can stop the game and stop the program.
Before moving on, let’s make one more change. The Leap Frog game will
have levels of play, starting out easy (Level 1) and getting progressively
harder as you play. We will discuss these levels in more detail later. In the
first level, if all 12 vehicles are used, it makes it very hard for the frog to get
across the road. We will start the game with just 7 vehicles, removing
vehicles 1, 4, 5, 7 and 11 (some from each lane).
Save and Run the program again, making sure only 7 vehicles appear. There
will be 2 vehicles in the top lane, 2 in the middle lane and 3 in the bottom
lane:
Let’s move to the next graphical element, the moving logs in the river panel.
You’ll see the coding process is nearly identical to that for the vehicles.
Code Design – River Panel
The logs move in the River panel and motion is governed by the same
Timer object. There are three size logs – there is no distinction between
direction motion. The images are found in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder:
The river panel will have three rows (each 40 pixels high). In the top and
bottom rows, logs will travel from left to right. In the middle row, logs will
travel from right to left. The river is 120 pixels high – there are no border
areas like we used in the road panel.
We will use 12 logs (at most, higher game levels will have fewer). There will
be five logs in the top row, four logs in the middle row and three in the
bottom row. The logs will be represented by an array (Log) of Shapes
objects. The assignments I made are: Log(1): Medium Log, Top Row
Log(2): Large Log, Top Row Log(3): Small Log, Top Row Log(4): Medium
Log, Top Row Log(5): Medium Log, Top Row Log(6): Small Log, Middle
Row Log(7): Large Log, Middle Row Log(8): Medium Log, Middle Row
Log(9): Large Log, Middle Row Log(10): Large Log, Bottom Row
Log(11): Medium Log, Bottom Row Log(12): Large Log, Bottom Row I put
more logs in the top row to make it easier for a frog to get home.
Let’s code the moving logs. Add this code to InitializeProgram to draw the
river and establish the Log Shapes objects: 'logs in river
RiverTop = 130
RiverHeight = 120
GraphicsWindow.BrushColor =
GraphicsWindow.GetColorFromRGB(128, 128, 255)
GraphicsWindow.FillRectangle(0, RiverTop, GraphicsWindow.Width,
RiverHeight) NumberOfLogs = 12
Log[1] = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[2] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[3] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\SmallLog.gif")) Log[4] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[5] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[6] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\SmallLog.gif")) Log[7] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[8] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[9] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[10] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) Log[11] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\MediumLog.gif")) Log[12] =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\LargeLog.gif")) For I = 1 to 12
Shapes.HideShape(Log[I]) LogIsVisible[I] = "false"
EndFor
Notice the image files must be in your program’s folder. Like the vehicles,
the logs are hidden until the game begins. The array LogIsVisible is used to
indicate if a particular vehicle is visible.
Logs in the top row are assigned a speed of +5 (moving to the right), logs in
the middle row have a speed of -3 (moving to the left), and logs in the
bottom row have a speed of 2 (moving to right). Each log is initially placed
to give a uniform spacing within the row.
The code to move the logs is identical to that used to move the vehicles.
With each Tick event, each log is repositioned using the Move method of
the Shapes object (and the Speed property). When a log leaves the panel, it
wraps around to the other side (using the same 120 pixel buffer zone to
avoid overlap). Add this shaded code to the TimerTickSub subroutine: Sub
TimerTickSub
'Road Update
.
.
'River Update
For I = 1 To NumberOfLogs If (LogIsVisible[I]) Then LogX[I] =
LogX[I] + LogSpeed[I]
Shapes.Move(Log[I], LogX[I], LogY[I]) If (LogX[I] >
GraphicsWindow.Width And LogSpeed[I] > 0) Then LogX[I]
= ‐120
EndIf
If (LogX[I] < ‐LogW[I] And LogSpeed[I] < 0) Then LogX[I]
= GraphicsWindow.Width + (120 ‐ LogW[I]) EndIf
EndIf
EndFor
EndSub
Save and Run the program. Click Start Game and both the vehicles and
logs are moving!
Make sure you can pause and restart the motion. One more moving object to
code (the snake), then we can start programming our leaping frog!
Code Design – Grass Panel (Snake)
Just to make it a little more difficult for a frog to make the journey home, we
will have a snake randomly appear between the road and river. It will always
move from left to right. The snake moves in the Grass panel and motion is
governed by the Timer object. To give the snake a slithering effect, we will
alternate between two snake images (found in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder):
Each snake is 111 pixels by 24 pixels. These images will be used to define
our Shapes object. The program will assume these files are in your
program’s folder. Copy the two files to that folder.
The grass panel is 40 pixels high (to hold a frog eventually). We will
vertically center the snake image within this panel. The snake will have a
speed of 5 and randomly appear from the left side of the panel.
This specifies the location of the Grass panel and defines the Shapes objects
(Snake1 and Snake2) we will use to display the snake. It also sizes,
positions and hides the snake.
The code to move the snake is in the TimerTickSub subroutine. Here’s the
code (shaded) I used: Sub TimerTickSub
'Road Update
.
.
'River Update
.
.
'snake update
If (SnakeIsVisible = "false") Then If (Math.GetRandomNumber(50))
= 1 Then SnakeX = ‐SnakeW
Snake = Snake1
Shapes.Move(Snake, SnakeX, SnakeY)
Shapes.ShowShape(Snake) SnakeIsVisible = "true"
EndIf
Else
Shapes.HideShape(Snake) If Snake = Snake1 Then Snake =
Snake2
Else
Snake = Snake1
EndIf
SnakeX = SnakeX + SnakeSpeed Shapes.Move(Snake, SnakeX,
SnakeY) Shapes.ShowShape(Snake) If (SnakeX >
GraphicsWindow.Width) Then Shapes.HideShape(Snake)
SnakeIsVisible = "false"
EndIf
EndIf
EndSub
The snake will appear randomly. To decide if a snake should appear, I used a
random number from 1 to 50. When that number is one, I start a snake
moving. This means a snake will start (on average) every 50 tick events.
Once a snake is started, it is positioned just off the left of the form and
drawn. Once a snake is moving (SnakeIsVisible is “true”), each subsequent
call to the subroutine updates its position using the Move method,
alternating between the two shape objects to give the slithering effect. Once
the snake leaves the right side of the form, it is removed from the screen
(there is no wrapping around like the logs and vehicles). At this point, the
program waits for another snake to appear.
Make the shaded change to the StopGame subroutine to clear the snake (if
there) when the game is stopped: Sub StopGame
Timer.Pause() GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Shapes.HideShape(Snake) SnakeIsVisible = "false"
EndSub
Save and Run the program. Click Start Game. The vehicles and logs start
moving and eventually a snake appears from the left side of the form:
Make sure you can pause and restart the motion. Now that we’ve
programmed the vehicles and snake for the frog to avoid and the logs to hop
on, it’s time to program the leaping frog.
Code Design – Moving the Frog
The frog will be able to leap from panel to panel and move horizontally
across panels. We will use a Shapes object to represent the frog. Four
images will be used to depict the frog depending on its direction of motion.
The images are in the KidGamesSB\KidGamesSB Programs\LeapFrog
folder):
Each frog is 40 pixels by 40 pixels. The program will assume these files are
in your program’s folder. Copy the four files to that folder.
The frog begins its journey on the Start panel at the bottom of the window
and ends its journey (if successful) on the Home panel at the top of the
window. In between, the frog traverses the three lanes in the Road panel, the
Grass panel with the moving snake and the three rows of logs in the River
panel. We define a variable (FrogLocation) to keep track of what panel (and
where on the panel in the case of the road and river) the frog is on. The
values for this variable and corresponding locations are (note FrogLocation
increases as the frog moves up the screen):
FrogLocation Location
8 Home
7 River (top row)
6 River (middle row)
5 River (bottom row)
4 Grass panel
3 Road (top lane)
2 Road (middle lane)
1 Road (bottom lane)
0 Start
For horizontal motion within a panel, the frog will leap in units of 40 pixels.
Hence, when a game begins, we want the frog to be near the center of the
start panel at an even multiple of 40 pixels. We choose an initial location of
320 pixels.
Let’s code the frog graphics and set up the start and home panels. Add this
code to InitializeProgram: 'Frogs
FrogUp = Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogUp.gif")) FrogDown =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogDown.gif")) FrogLeft =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogLeft.gif")) FrogRight =
Shapes.AddImage(ImageList.LoadImage(Program.Directory +
"\FrogRight.gif")) Shapes.HideShape(FrogUp)
Shapes.HideShape(FrogDown) Shapes.HideShape(FrogLeft)
Shapes.HideShape(FrogRight) FrogW = 40
FrogH = 40
StartTop = 430
StartHeight = 40
HomeTop = 50
HomeHeight = 80
This defines the Shapes object (Frog) we will use for the ‘current’ frog, the
four shapes (FrogUp, FrogLeft, FrogDown and FrogUp) to display the
frog, and variables defining the start and home panels, respectively. Again,
the graphics files must be in your program folder. For now, we treat the
home panel as an empty rectangular area. We will build a more complete
home area after discussing frog movement and collision detection (to see if a
frog makes it home).
Save and Run the program. Click Start Game. The ‘up frog’ will appear
ready to start its journey:
Let’s get the frog moving. For now, we’ll let it move with no worries about
getting hit by a vehicle or falling in the river. Later, we’ll code this
‘collision’ logic. To control motion of the frog, we will use the cursor control
arrows of the keyboard and the KeyDown event.
To move a frog from one panel to the next (changing the FrogLocation
variable) or left/right with a panel, we use the Shapes Move method. Within
a panel, we will move the frog 40 pixels in the appropriate direction (making
sure it stays on the panel). You may choose to change this value if you like.
We only allow frog movement if the game is not stopped or paused. We will
use the GameStatus variable to tell us if a game is in progress.
We’ll add a little ‘hop’ sound each time the frog moves. The sound file
Hop.wav is included in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder. Copy this file to your program’s folder.
Add this line at the end of InitializeProgram: GraphicsWindow.KeyDown =
KeyDownSub With this, each time a KeyDown event occurs, the subroutine
named KeyDownSub is called.
Now, add this code (there is a lot of it) to the KeyDownSub subroutine: Sub
KeyDownSub
KD = GraphicsWindow.LastKey If (GameStatus = "Playing") Then
'Clear from current location
Shapes.HideShape(Frog) If (KD = "Up") Then
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogUp
FrogLocation = FrogLocation + 1
If (FrogLocation > 8) Then FrogLocation = 8
EndIf
ElseIf (KD = "Left") Then Sound.Stop(Program.Directory +
"\Hop.wav") Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogLeft If FrogX > 0 Then FrogX = FrogX ‐ FrogW
EndIf
ElseIf (KD = "Down") Then Sound.Stop(Program.Directory +
"\Hop.wav") Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogDown FrogLocation = FrogLocation ‐ 1
If FrogLocation < 0 Then FrogLocation = 0
EndIf
ElseIf (KD = "Right") Then Sound.Stop(Program.Directory +
"\Hop.wav") Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogRight If (FrogX < GraphicsWindow.Width ‐ FrogW) Then
FrogX = FrogX + FrogW
EndIf
EndIf
'put in new location
DrawFrog()
EndIf
EndSub
This code uses a subroutine (DrawFrog) to do the movement. Add this: Sub
DrawFrog
If (FrogLocation = 0) Then FrogY = StartTop ElseIf (FrogLocation =
1 Or FrogLocation = 2 Or FrogLocation = 3) Then FrogY = RoadTop
+ 140 ‐ 45 * FrogLocation ElseIf (FrogLocation = 4) Then FrogY =
GrassTop ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or
FrogLocation = 7) Then FrogY = RiverTop + 120 ‐ 40 *
(FrogLocation ‐ 4) ElseIf (FrogLocation = 8) Then FrogY =
HomeTop + 40
EndIf
Shapes.Move(Frog, FrogX, FrogY) Shapes.ShowShape(Frog)
EndSub
Let’s look at what’s going on here. First, notice no key down events are
allowed unless the GameStatus is “Playing”. We hide the frog from its
current position. Next, we find which arrow key is pressed (variable KD).
The hop sound is played and the proper frog graphic is assigned. For vertical
motion, FrogLocation is adjusted accordingly (keeping it between 0 and 8).
For horizontal motion, the FrogX value is adjusted (either +40 pixels or -40
pixels, the value of FrogW), making sure the frog stays within screen
bounds. Then in DrawFrog, the frog is drawn (using Move) at its new
location. In particular, notice how FrogLocation is used to determine the
proper lane in the road panel and proper row in the river panel (using
FrogY).
One more change is needed. We want to make sure the frog is cleared from
the game screen when the game is stopped. Make the shaded change to the
StopGame subroutine: Sub StopGame
Timer.Pause() GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Shapes.HideShape(Snake) SnakeIsVisible = "false"
Shapes.HideShape(Frog)
EndSub
Save and Run the program. Click Start Game. Try out the arrow control
keys. Move the frog up and down the screen. Make sure it doesn’t go past
home or below the start panel. Try left and right motion. Make sure the frog
doesn’t leave the screen. Listen for the hop sound. Here’s my frog just sitting
in the river:
It’s pretty easy for the frog to make it home since there’s no danger from the
vehicles or snake and it can go right across the river to any location on the
home panel. We need logic to see if the frog collides with a vehicle or snake,
jumps on a log and makes it home safely. Each of these steps involves the
concept of collision detection.
Collision Detection
As the frog moves upward from one level to the next, we need some way to
see if it collides or overlaps with other objects. For example, in the road
panel, we need to see if a vehicle hits the frog. In the grass panel, we need to
check if the snake and frog collide. In the river, we want to see if the frog
overlaps with a log, so it can float down the river. And, once home (still to
be defined), we need to make sure the frog fits in the specific region. Each
shape is defined by a rectangle (known position, width and height). Hence,
we want to know if two rectangles overlap.
For the Leap Frog game, we can simplify the overlap decision. We know
what level (or panel) the frog is on, hence we know there is overlap with
objects in that panel in the vertical direction. Hence, we only need to look
for overlap in the horizontal direction. There are two possibilities – let’s look
at each. The first is when the frog overlaps a shape from the left:
In this case, we see the Frog overlaps the Shape (could be a car, a snake, a
log or a home position) if this condition holds: FrogX + FrogW > ShapeX
And FrogX + FrogW < ShapeX + ShapeW
where FrogW and ShapeW are widths of the frog and shape, respectively.
In the Leap Frog game, just because the frog overlaps a shape, we may not
want to declare a collision. Instead, we will compute the amount of overlap
(as a percentage of frog width). If this overlap is small, we won’t say there is
a collision. This will allow us to adjust how close a vehicle needs to be to the
frog before it disappears. Or, we can adjust how close to the edge of a log
the frog can get and still sit on it. Using the above previous two diagrams,
we see for the “left overlapping” case, the amount of overlap is: Overlap =
100 * (FrogX + FrogW ‐ ShapeX) / FrogW
And, for the “right overlapping” case, the amount of overlap is: Overlap =
100 * (ShapeX + ShapeW ‐ FrogX) / FrogW
If the frog collides with a vehicle while crossing the road, its journey ends
(the frog is cleared and a new frog is placed in the home panel). We will
assume a collision when 10 percent of the frog intersects with a vehicle. This
will let the frog escape any close calls.
Collisions in Leap Frog will be monitored by the Timer object. We’ll play a
‘beep’ sound if the frog collides with a vehicle. The sound file Beep.wav is
included in the KidGamesSB\KidGamesSB Programs\LeapFrog folder.
Copy this file to your program’s folder.
In this code, in the road panel (FrogLocation = 1, 2, 3), we see if frog has
collided with any visible vehicle (10 percent of the frog overlaps a vehicle).
If so, the subroutine NoMoreFrog is called to eliminate the frog. If there is
no overlap, nothing happens. Look at how IFrog is used to identify vehicles
in a particular FrogLocation.
The subroutine NoMoreFrog plays a beep, clears the frog in its current
location and gets a new frog: Sub NoMoreFrog
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
Sound.Stop(Program.Directory + "\Beep.wav")
Sound.Play(Program.Directory + "\Beep.wav") EndIf
Shapes.HideShape(Frog) GetNewFrog()
EndSub
Save and Run the program. Start the game. Try moving across the road. If
your frog is hit by a vehicle, you will hear a beep and a new frog will appear.
Code Design – Snake Collisions
If the frog successfully crosses the three lanes of vehicles, it must get past
the snake (if it’s there). If the frog collides with the snake, its journey ends.
We will assume a collision when the frog just touches the snake sprite. No
close calls allowed here!
We’ll play a ‘snake’ sound if the frog collides with the snake. The sound file
Snake.wav is included in the KidGamesSB\KidGamesSB
Programs\LeapFrog folder. Copy this file to your program’s folder.
In this new code, if any part of the frog (greater than 1 percent) overlaps
with the snake, the frog is cleared.
Following a snake collision, the snake sound is played, the frog is cleared
and a new frog appears.
Save and Run the program. Start the game. Successfully cross the road, then
sit in the grass panel until a snake appears. Make sure the snake collision
logic works (you’ll hear a sound and a new frog will appear).
Code Design - Log Collisions
Once the frog crosses the road and avoids the snake, it’s time to cross the
river. To do this, the frog must jump onto the floating logs as they go by. The
collision logic is different here. For the vehicles and the snake, if there is a
collision, the frog’s journey ends. Here, if there is a collision, we want the
frog to float with the log. If there is no collision, the frog’s journey ends with
a splash!
Before discussing the logic of floating on a log, let’s add the sound. We’ll
play a ‘splash’ sound if the frog misses a log. The sound file Splash.wav is
included in the KidGamesSB\KidGamesSB Programs\LeapFrog folder.
Copy this file to your program’s folder.
Once the frog enters the river, we need to see if it’s sitting on a log. If so,
with each timer update, the position of the frog will change with the position
of the log. To see if a frog is on a log, we use the FindOverlap subroutine. If
80 percent of the frog intersects with a log, we will say the frog is on the log
(this allows a little ‘hangover’ room). We will use a variable (OnLog) to
identify the ‘occupied’ log.
With each new frog, OnLog is initialized to zero. Add the shaded line to the
GetNewFrog subroutine to do this initialization: Sub GetNewFrog
OnLog = 0
FrogLocation = 0
FrogX = 320
FrogY = StartTop Frog = FrogUp Shapes.Move(Frog, FrogX, FrogY)
Shapes.ShowShape(Frog) EndSub
Each time the frog moves, we reset OnLog to zero to see if it stays on a log.
This is done with the shaded changes to the KeyDownSub subroutine: Sub
KeyDownSub
KD = GraphicsWindow.LastKey If (GameStatus = "Playing") Then
'Clear from current location
Shapes.HideShape(Frog) If (KD = "Up") Then
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogUp
FrogLocation = FrogLocation + 1
If (FrogLocation > 8) Then FrogLocation = 8
EndIf
ElseIf (KD = "Left") Then
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogLeft
If FrogX > 0 Then FrogX = FrogX ‐ FrogW
EndIf
ElseIf (KD = "Down") Then
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogDown FrogLocation = FrogLocation ‐ 1
If FrogLocation < 0 Then FrogLocation = 0
EndIf
ElseIf (KD = "Right") Then
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog =
FrogRight If (FrogX < GraphicsWindow.Width ‐ FrogW)
Then FrogX = FrogX + FrogW
EndIf
EndIf
'put in new location
DrawFrog()
EndIf
EndSub
If OnLog is non-zero, we need to update the frog’s horizontal position as the
corresponding log moves. This is done in the TimerTickSub subroutine.
Make the shaded changes: Sub TimerTickSub
'Road Update
.
.
'River Update
For I = 1 To NumberOfLogs If (LogIsVisible[I]) Then LogX[I] =
LogX[I] + LogSpeed[I]
Shapes.Move(Log[I], LogX[I], LogY[I]) If OnLog = I Then
FrogX = FrogX + LogSpeed[I]
If (FrogX < 0 Or FrogX > GraphicsWindow.Width ‐
FrogW) Then NoMoreFrog()
Goto ExitTickSub
EndIf
Shapes.Move(Frog, FrogX, FrogY) EndIf
If (LogX[I] > GraphicsWindow.Width And LogSpeed[I] > 0)
Then LogX[I] = ‐120
EndIf
If (LogX[I] < ‐LogW[I] And LogSpeed[I] < 0) Then LogX[I]
= GraphicsWindow.Width + (120 ‐ LogW[I]) EndIf
EndIf
EndFor
'snake update
.
.
'general status
'check for collisions
.
.
ExitTickSub:
EndSub
In this code, the frog is moved in the same direction and the same amount as
the log it is on (Log array index is OnLog). If the frog goes off either end of
the river, it’s journey ends. Now, let’s see how to give a value to OnLog.
The shaded steps are straightforward. If the frog is not on a log, it checks for
an ’80 percent’ overlap with any log in the current FrogLocation. If such an
overlap exists, OnLog is set. If no collision exists, the frog splashes away!
Notice if there is already a frog on a log (OnLog <> 0), no overlap checks
are made.
When a frog misses a log (no collision), the splash sound is played, the frog
is cleared and a new frog appears.
Save and Run the program. Start the game. Successfully cross the road, then
get past the snake. Now try jumping onto a log. Here’s my screen after my
second jump:
Notice how the frog moves with the log. Check the logic that stops the frog’s
journey if it floats off the side of the window. Make sure you hear a splash.
Try to get a frog onto the home panel – not a real difficult task and you
won’t get a new frog! Right now, you can jump anywhere on the home
panel. Next, we’ll construct a home panel that only has five specific places
the frog can call home.
Code Design – Home Collisions
Currently, the frog can jump off at any location on the home panel. We’ll
make that task a little more difficult by specifying five rectangular ‘home’
regions. If the frog leaves a log and enters one of these regions (there is a
‘total overlap’) the frog is home safe. If he misses home, a splash is heard
and his journey ends. In either case, a new frog appears.
The home panel is 640 pixels wide (just like the other panels) and 80 pixels
high. We will define each home to be a yellow bordered rectangle, 60 pixels
wide by 60 pixels high. By making the homes 60 pixels wide, we give the
frog (40 pixels wide) a little leeway when jumping off a log. These homes
will be uniformly spread across the panel:
Each home is 60 pixels wide and separated by gaps of 50 pixels. The left and
right borders are 70 pixels wide. We make the borders wider to make it a
little easier for the frog to reach these homes. If you’d like, add the width of
five homes, four gaps and two borders to see you indeed get a total width of
640 pixels.
We’d like the home to show up when the game first starts, so add this single
line in InitializeProgram after the variables HomeTop and HomeHeight
are defined: DrawHome()
The home area should also be cleared and redrawn when a new game begins.
Add the shaded line to the StartPauseButtonClick subroutine: Sub
StartPauseButtonClick If (GameStatus = "Stopped") Then GameStatus =
"Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game") .
.
PositionLogs()
For I = 1 To NumberOfLogs Shapes.ShowShape(Log[I])
LogIsVisible[I] = "true"
EndFor
GetNewFrog()
DrawHome()
Timer.Resume() ElseIf (GameStatus = "Playing") Then .
.
Else
'game restarted
.
.
EndIf
EndSub
Save and Run the program. The home area will be drawn:
When a frog jumps to the home panel, he is safe if there is not already a frog
in that home location and if he completely overlaps (we actually use 95
percent) with the home rectangle. In that case, we will play a ‘safe’ sound
and draw a ‘at home’ frog. That frog is represented by the FrogHome.gif
graphic (40 pixels by 40 pixels) found in the KidGamesSB\KidGamesSB
Program\LeapFrog folder:
The home sound is the Home.wav file found in that same folder. Copy these
two files (FrogHome.gif and Home.wav) to your program’s folder.
Add this line to InitializeProgram (with other frog graphics) to load the
FrogHome image: FrogHome = ImageList.LoadImage(Program.Directory +
"\FrogHome.gif") Add the shaded line to the DrawHome subroutine to
initialize the FrogIsHome array (used to show which home locations have a
frog in them) each time the home panel is redrawn: Sub DrawHome
PadX[1] = 70
PadX[2] = 180
PadX[3] = 290
PadX[4] = 400
PadX[5] = 510
PadY = HomeTop + 15
PadW = 60
PadH = 60
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
For I = 1 To 5
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(PadX[I], PadY, PadW, PadH)
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
GraphicsWindow.DrawRectangle(PadX[I], PadY, PadW, PadH)
FrogIsHome[I] = "false"
EndFor
EndSub
We can now add code to the TimerTickSub subroutine to check for
collisions in the home panel. Before doing this, add the two shaded lines to
the DrawFrog subroutine: Sub DrawFrog
If (FrogLocation = 0) Then FrogY = StartTop ElseIf (FrogLocation =
1 Or FrogLocation = 2 Or FrogLocation = 3) Then FrogY = RoadTop
+ 140 ‐ 45 * FrogLocation ElseIf (FrogLocation = 4) Then FrogY =
GrassTop ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or
FrogLocation = 7) Then FrogY = RiverTop + 120 ‐ 40 *
(FrogLocation ‐ 4) ElseIf (FrogLocation = 8) Then FrogY =
HomeTop + 40
EndIf
If (FrogLocation <> 8) Then
Shapes.Move(Frog, FrogX, FrogY) Shapes.ShowShape(Frog)
EndIf
EndSub
We will only draw the frog on the home panel if it reaches home
successfully. That code is added next.
You should see how this code works. If the frog successfully maneuvers to
an empty home, it is drawn there and a sound played. If no overlaps are
found or the selected location is already filled, the frog’s journey ends. If all
homes are filled, they are cleared.
When a frog misses home, the splash sound is played, the frog is cleared and
a new frog appears.
Save and Run the program. Start a game. You now have a completely
functional game. You can traverse the road, elude the snake, cross the river
and get home. Make sure when you get five frogs home (it may be tricky the
first few times you try it) that the home clears and the game continues.
Here’s my screen as I’m trying to get my last frog home:
As programmed, you can play Leap Frog forever. You have unlimited frogs
and the game stays at the same difficulty no matter how long you play. We’ll
change that now. First, we will limit the number of frogs available during a
game. Once your frogs are gone, the game will be over. Second, each time
all the frogs have reached home, we will increase the difficulty of the game
by speeding things up a bit, adding more vehicles and removing logs. This
idea of having increasing levels of difficulty is a fun feature of video games.
And, you may be wondering why we have no scoring? We’ll take care of
that soon.
Code Design – Game Levels
We start Leap Frog at Level 1 (indicated in the title area of the window).
This is the level we have been using (with 7 vehicles and all 12 logs). At this
initial level, you will begin with five available frogs. We will show the
number of frogs (using the FrogUp image) remaining in the upper right of
the window.
Modify the existing line of code in InitializeProgram that sets the window
title to indicate the level and add the line initializing the Level variable:
Level = 1
GraphicsWindow.Title = "Leap Frog ‐ Level 1"
This code resets the level (Level) and the number of frogs remaining
(FrogsRemaining). Why did we initialize FrogsRemaining at 4 if we said
there are five initial frogs? The first frog is on the window when we start, so
that frog plus the four remaining gives us five frogs.
Save and Run the program. Click Start Game. Notice the four little frogs in
the upper corner:
Each time a frog’s journey ends (hitting a vehicle or snake, or falling off a
log), we want to eliminate one of the remaining frogs and check to see if the
game has ended (no more frogs). When a game ends, we’ll play a game over
sound. The sound file GameOver.wav is included in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder. Copy this file to
your program’s folder.
Save and Run the program. Play recklessly until five frogs have been lost.
Make sure the game ends and the game over sound is heard.
So, now, the game is not endless – you have a limited number of frogs. Next,
we code the logic that increases the difficulty of the game as new levels are
achieved. A new level is achieved when you get five frogs home. At that
point, we’ll play another sound. The sound file NewLevel.wav is included in
the KidGamesSB\KidGamesSB Programs\LeapFrog folder. Copy this file
to your program’s folder.
Here, we play the new level sound and increment the Level.
Save and Run the program. Get five frogs home and make sure you move to
the next level. When testing the game, you’ll probably get a little tired of
trying to get all five frogs home. Here’s a trick. Look at the code where you
check if all five homes are filled (in TimerTickSub subroutine): For J = 1
To 5
If (FrogIsHome[J] = "false") Then goto ExitTickSub
EndIf
EndFor
Change the first line (temporarily of course) to:
For J = 3 To 3
With this change, you only need to get a frog in the middle home to
complete a level. This makes it much easier to achieve the higher levels to
test your code. Just be sure to change it back to: For J = 1 To 5
We can now move to higher game levels with each group of frogs we get
home safely. With each level, we want the game to change (get more
difficult). Let’s establish those changes. These are just some rules I made up
– feel free to change them as you like. At higher levels, I decided game play
should get faster, vehicles should be added and logs should be removed.
And, to be nice, with every second level, you are given a new frog (up to a
maximum of five). The rules I developed for each level are:
So once we reach Level 5, all 12 vehicles are on the road and there 9 logs in
the river. By this level, speeds have increased significantly – things are really
moving. At each level, we also reposition the logs and vehicles to their
original starting positions to avoid the ‘overlap’ problem.
GraphicsWindow.DrawImage(ImageList.LoadImage(Program.Directory +
"\FrogUp.gif"), GraphicsWindow.Width ‐ FrogsRemaining * FrogW ‐ 10,
5) EndIf
EndIf
'reposition logs, vehicles
PositionLogs()
PositionVehicles()
'delete logs, add vehicles
If (Level = 2) Then Shapes.HideShape(Log[1]) LogIsVisible[1] =
"false"
ElseIf (Level = 3) Then Shapes.HideShape(Log[7]) LogIsVisible[7] =
"false"
Shapes.ShowShape(Vehicle[1]) Shapes.ShowShape(Vehicle[5])
VehicleIsVisible[1] = "true"
VehicleIsVisible[5] = "true"
ElseIf (Level = 4) Then Shapes.HideShape(Log[12])
LogIsVisible[12] = "false"
Shapes.ShowShape(Vehicle[7]) Shapes.ShowShape(Vehicle[11])
VehicleIsVisible[7] = "true"
VehicleIsVisible[11] = "true"
ElseIf (Level = 5) Then Shapes.ShowShape(Vehicle[4])
VehicleIsVisible[4] = "true"
EndIf
EndSub
Any time anyone plays a game, they like to know their score. And, they like
to see if they do better than others. Let’s add that capability to the Leap
Frog game. Like other rules used in this game, the scoring rules are
somewhat arbitrary – feel free to change them as you want.
We will use Score to track the current game score and HighScore to track
the highest score achieved. These values will be displayed at the top of the
game window.
We also want to insure the Score is reset to zero when starting a new game.
Add the shaded lines to the StartPauseButtonClick event subroutine to
reset the score with each new game: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Score = 0
UpdateScore()
Level = 1
GraphicsWindow.Title = "Leap Frog ‐ Level 1"
.
.
ElseIf (GameStatus = "Playing") Then .
.
Else
.
.
EndIf
EndSub
Add the shaded line to the StopGame subroutine to update the score when a
game stops. This line is needed in case the game stops before a score update
occurs: Sub StopGame
Timer.Pause() Sound.PlayAndWait(Program.Directory +
"\GameOver.wav") GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Shapes.HideShape(Snake) SnakeIsVisible = "false"
Shapes.HideShape(Frog)
UpdateScore()
EndSub
Save and Run the program. The initialized scores will appear at the top of
the window.
The scores for getting a frog home safely and completing a level, as well as
updating the scores, is done in the TimerTickSub subroutine. Make the
shaded changes: Sub TimerTickSub
UpdateScore()
.
.
ElseIf (FrogLocation = 8) Then 'moved to home level ‐ see if home
For I = 1 To 5
ShapeX = PadX[I]
ShapeW = PadW
FindOverlap()
If (FrogIsHome[I] = "false" And Overlap > 95) Then
Score = Score + 200
FrogIsHome[I] = "true"
GraphicsWindow.DrawImage(FrogHome, PadX[I] + 10,
PadY + 10) ' Sound.Stop(Program.Directory +
"\home.wav")
'Sound.Play(Program.Directory + "\home.wav")
GetNewFrog()
'check if all found
For J = 3 To 3
If (FrogIsHome[J] = "false") Then goto ExitTickSub
EndIf
EndFor
DrawHome()
Score = Score + 1000
GoToNextLevel()
Goto ExitTickSub
EndIf
EndFor
NoMoreFrog()
EndIf
ExitTickSub:
EndSub
Save and Run the program. You now have scoring. Here’s a game I played
into the third level (without using my cheat):
I have the highest score, since this the only game I’ve played.
We’re nearly finished with Leap Frog. Have you noticed the High Scores
button at the bottom of the window? We’ve kind of ignored that button.
We’ll use it now. One last thing players like to see is how well they compare
to those who have played the game before. As programmed, only one high
score is saved – the highest score since the program was started. It would be
nice to be able to save high scores for future players to see. We do that next,
saving and displaying the 10 highest scores ever achieved. If a player
reaches the Top 10, he/she can add his/her name to this illustrious list. We
will add a text window to our program that displays the high scores. Then,
we will discuss how to write and read text files using Small Basic. This will
let us save and recall the high scores.
Window Design – High Scores
We will use a text window to display the sales results. Like the graphics
window, it helps to first make a sketch of the desired layout. Here is the
sketch for the High Scores window:
We will have room for the top ten scores. For each, we list a player’s name
and the corresponding score. For new high scores, we will allow the user to
type his/her name so it can be added to the list.
Code Design – Displaying High Scores
We want to write code for the High Scores button. First, make the shaded
changes to the StartPauseButtonClick and StopGame subroutines to
show/hide this button at proper times: Sub StartPauseButtonClick If
(GameStatus = "Stopped") Then GameStatus = "Playing"
Controls.SetButtonCaption(StartPauseButton, "Pause Game")
Controls.SetButtonCaption(ExitStopButton, "Stop Game")
Controls.HideControl(HighScoresButton)
.
.
ElseIf (GameStatus = "Playing") Then .
.
Else
.
.
EndIf
EndSub
Sub StopGame
Timer.Pause() Sound.PlayAndWait(Program.Directory +
"\GameOver.wav") GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.Showcontrol(HighScoresButton)
Shapes.HideShape(Snake) SnakeIsVisible = "false"
Shapes.HideShape(Frog) UpdateScore()
EndSub
When a player clicks the High Scores button, we want that window to
display. Add this code to the HighScoresButtonClick event: Sub
HighScoresButtonClick GraphicsWindow.Hide() TextWindow.Show()
TextWindow.BackgroundColor = "White"
TextWindow.ForegroundColor = "Black"
TextWindow.Title = "Leap Frog High Scores"
TextWindow.Clear() TextWindow.Pause() TextWindow.Hide()
GraphicsWindow.Show() EndSub
Save and run the program. Click High Scores and you will see the almost
blank window:
There are no scores yet. Let’s develop the code to add scores, save them and
re-display them. First, we look at saving information displayed on the High
Scores window.
Code Design – Saving High Scores
When we close the High Scores window, we want to save player names and
their high scores in a file. To do this, we look at how to write values of
variables to files. We use the Small Basic File object. To write a variable
named Variable to line N in a file MyFile.txt (in your program’s folder), use
the WriteLine method: File.WriteLine(Program.Directory + "\MyFile.txt",
Variable, N) This statement will write the variable on a single line in the file.
In the Leap Frog game, the file we use will have 20 lines. The first two lines
will be the name and score for the highest score, the next two lines the name
and score for the second highest score, and so on for all 10 pairs of names
and scores.
We will use two arrays to store player names and scores: PlayerName will
hold the names, while PlayerScore will hold the score. Initialize these
arrays near the end of InitializeProgram using: For I = 1 To 10
PlayerName[I] = ""
PlayerScore[I] = 0
EndFor
Notice how we position the player names and scores at known locations
(using CursorTop and CursorLeft). This will allow easier editing later.
And, note how the 20 lines in the HighScores.txt file are generated in the
file (odd numbered lines have names, even numbered lines have scores.
Save and Run the program. Click High Scores. The window will appear
with the initial high scores information:
As directed, press any key to close the window. Make sure control returns to
the Leap Frog game. Stop the game. Go to your program’s folder. Open the
file named HighScores.txt. It should have blank lines for each name and
zeroes for each score:
In this code, we read each player/score combination from the data file.
Save and Run the program. Click High Scores. If you copied the sample
HighScores.txt file into your program’s folder, you will see something like
this (some of the entries may have changed since these notes were written):
So, we can save and display the high scores file. But, how do we get entries
into the file? We need logic to see if an achieved score in the Leap Frog
game is high enough to be displayed in the Top 10 list. If it is, we need logic
to add it to the list. Let’s write that code.
Code Design – Adding to High Scores
When a Leap Frog game ends, we need to look at the achieved score and
see if it fits into the Top 10 scores list. To do this, we check if the score is
higher than the lowest score in the list. If so, it needs to be added to the list.
So a first task is to determine the minimum score (LowScore) a player
would have to achieve to enter the Top 10. This score is found by opening
HighScores.txt and finding the lowest value. We do this when first starting
the program.
Add the shaded code in InitializeProgram with other scoring code. Make
sure you put these lines (as shown) before the code displaying the scores.
This code opens HighScores.txt and finds the highest score (HighScore)
and lowest score (LowScore). The high score is displayed in the High Score
area:
Run and Save the program. The high score (again, you may see a different
value) in the sample file will appear:
Finally, we need logic to check the score at the end of a game and see if it
belongs in the Top 10. We will use a variable (NewScore) to indicate if a
new Top 10 score has been achieved. When a new Top 10 score is achieved,
we will play a ‘tada’ sound. The sound file tada.wav is included in the
KidGamesSB\KidGamesSB Programs\LeapFrog folder. Copy this file to
your program’s folder.
Add the shaded code to the StopGame subroutine to check the score against
LowScore: Sub StopGame
Timer.Pause() Sound.PlayAndWait(Program.Directory +
"\GameOver.wav") GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.Showcontrol(HighScoresButton) Shapes.HideShape(Snake)
SnakeIsVisible = "false"
Shapes.HideShape(Frog) UpdateScore()
'check if in top 10 scores
If (Score > LowScore) Then Sound.Stop(Program.Directory +
"\tada.wav") Sound.Play(Program.Directory + "\tada.wav") NewScore
= "true"
HighScoresButtonClick() EndIf
EndSub
Save and Run the program. Play until you achieve a fairly high score. Stop
the game. You should hear a ‘tada’ and the high scores window will appear.
You know you achieved a high score, but there is no way to enter your name
and score. Let’s fix that.
When the high scores window is opened, if NewScore is “true”, the current
score is to be entered into the Top 10 list. Once we know this, our coding job
is to determine where it fits in the list, enter the score in the appropriate
position and clear the area next for the corresponding player name to allow
the player to type his/her name.
Save and Run the program again. Get a fairly high score and stop. You
should hear a ‘tada’, see the congratulatory message and given the
opportunity to type your name. Go ahead – add your name to history:
Would you believe the Leap Frog game is at long last complete? It’s been a
long journey, but well worth it. Before concluding, one word about the high
scores file. Notice we have not given you a way to easily delete high scores.
There is no Delete button on the form. The only way to do it is to delete the
HighScores.txt file from your program’s folder. This is by design. We have
found that if high scores are easily deleted, quite often friends or siblings
will wipe out another’s hard earned scores so they can get their own scores
entered. We didn’t want this to be an easy task. So, to start fresh with a new
high scores file, you will want to delete the sample file from your directory
before playing your game of Leap Frog.
A Possible Problem
As implemented, sometimes when the program is run, you may see an error
message like this:
So, what can we do? I am assuming this is a problem that will be fixed in
later versions of Small Basic. We are currently working with Beta versions
and errors do exit. For now, the only solution I have is to comment out the
lines of code that stop/play sounds. I have found you can leave the hop
sounds in, but all others should not be played for now. You decide which
sounds you want.
Leap Frog Game Program Listing
Here is the complete listing of the Leap Frog Small Basic program: ' Leap
Frog
InitializeProgram()
Sub ButtonClickedSub
B = Controls.LastClickedButton If (B = StartPauseButton) Then ' start,
stop, pause button
StartPauseButtonClick() ElseIf (B = ExitStopButton) Then 'exit, stop
button
ExitStopButtonClick() ElseIf (B = HighScoresButton) Then 'high
scores button
HighScoresButtonClick() EndIf
EndSub
Sub StopGame
Timer.Pause() Sound.PlayAndWait(Program.Directory +
"\GameOver.wav") GameStatus = "Stopped"
Controls.SetButtonCaption(StartPauseButton, "Start Game")
Controls.SetButtonCaption(ExitStopButton, "Exit")
Controls.Showcontrol(HighScoresButton) Shapes.HideShape(Snake)
SnakeIsVisible = "false"
Shapes.HideShape(Frog) UpdateScore()
'check if in top 10 scores
If (Score > LowScore) Then Sound.Stop(Program.Directory +
"\tada.wav") Sound.Play(Program.Directory + "\tada.wav") NewScore =
"true"
HighScoresButtonClick() EndIf
EndSub
Sub DrawRoad
GraphicsWindow.BrushColor = "DimGray"
GraphicsWindow.FillRectangle(0, RoadTop, GraphicsWindow.Width,
RoadHeight) 'draw road lines
GraphicsWindow.PenColor = "White"
GraphicsWindow.PenWidth = 1
GraphicsWindow.DrawLine(0, RoadTop + 2, GraphicsWindow.Width,
RoadTop + 2) GraphicsWindow.DrawLine(0, RoadTop + RoadHeight ‐ 2,
GraphicsWindow.Width, RoadTop + RoadHeight ‐ 2)
GraphicsWindow.DrawLine(0, RoadTop + 92, GraphicsWindow.Width,
RoadTop + 92) GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.DrawLine(0, RoadTop + 47, GraphicsWindow.Width,
RoadTop + 47) GraphicsWindow.DrawLine(0, RoadTop + 49,
GraphicsWindow.Width, RoadTop + 49) EndSub
Sub TimerTickSub
UpdateScore()
'Road Update
For I = 1 To NumberOfVehicles If VehicleIsVisible[I] Then VehicleX[I]
= VehicleX[I] + VehicleSpeed[I]
Shapes.Move(Vehicle[I], VehicleX[I], VehicleY[I]) If (VehicleX[I]
> GraphicsWindow.Width And VehicleSpeed[I] > 0) Then
VehicleX[I] = ‐120
EndIf
If (VehicleX[I] < ‐VehicleW[I] And VehicleSpeed[I] < 0) Then
VehicleX[I] = GraphicsWindow.Width + (120 ‐ VehicleW[I])
EndIf
EndIf
EndFor
'River Update
For I = 1 To NumberOfLogs If (LogIsVisible[I]) Then LogX[I] =
LogX[I] + LogSpeed[I]
Shapes.Move(Log[I], LogX[I], LogY[I]) If OnLog = I Then
FrogX = FrogX + LogSpeed[I]
If (FrogX < 0 Or FrogX > GraphicsWindow.Width ‐ FrogW)
Then NoMoreFrog()
Goto ExitTickSub
EndIf
Shapes.Move(Frog, FrogX, FrogY) EndIf
If (LogX[I] > GraphicsWindow.Width And LogSpeed[I] > 0)
Then LogX[I] = ‐120
EndIf
If (LogX[I] < ‐LogW[I] And LogSpeed[I] < 0) Then LogX[I] =
GraphicsWindow.Width + (120 ‐ LogW[I]) EndIf
EndIf
EndFor
'snake update
If (SnakeIsVisible = "false") Then If (Math.GetRandomNumber(50)) = 1
Then SnakeX = ‐SnakeW
Snake = Snake1
Shapes.Move(Snake, SnakeX, SnakeY)
Shapes.ShowShape(Snake) SnakeIsVisible = "true"
EndIf
Else
Shapes.HideShape(Snake) If Snake = Snake1 Then Snake = Snake2
Else
Snake = Snake1
EndIf
SnakeX = SnakeX + SnakeSpeed Shapes.Move(Snake, SnakeX,
SnakeY) Shapes.ShowShape(Snake) If (SnakeX >
GraphicsWindow.Width) Then Shapes.HideShape(Snake)
SnakeIsVisible = "false"
EndIf
EndIf
'general status
'check for collisions
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
'vehicles in FrogLocation row
IFrog = 9 ‐ 4 * (FrogLocation ‐ 1) For I = IFrog To IFrog + 3
If (VehicleIsVisible[I]) Then ShapeX = VehicleX[I]
ShapeW = VehicleW[I]
FindOverlap()
If (Overlap > 10) Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
EndFor
ElseIf (FrogLocation = 4) Then 'snake
If (SnakeIsVisible) Then ShapeX = SnakeX
ShapeW = SnakeW
FindOverlap()
If (Overlap > 1) Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or FrogLocation = 7)
Then 'check if moved to log or already on a log
If OnLog = 0 Then If (FrogLocation = 5) Then ILog1 = 10
ILog2 = 12
ElseIf (FrogLocation = 6) Then ILog1 = 6
ILog2 = 9
ElseIf (FrogLocation = 7) Then ILog1 = 1
ILog2 = 5
EndIf
For I = ILog1 To ILog2
If (LogIsVisible[I]) Then ShapeX = LogX[I]
ShapeW = LogW[I]
FindOverlap()
If (Overlap > 80) Then OnLog = I Goto GotLog
EndIf
EndIf
EndFor
GotLog:
If OnLog = 0 Then NoMoreFrog()
Goto ExitTickSub
EndIf
EndIf
ElseIf (FrogLocation = 8) Then 'moved to home level ‐ see if home
For I = 1 To 5
ShapeX = PadX[I]
ShapeW = PadW
FindOverlap()
If (FrogIsHome[I] = "false" And Overlap > 95) Then Score =
Score + 200
FrogIsHome[I] = "true"
GraphicsWindow.DrawImage(FrogHome, PadX[I] + 10, PadY
+ 10) Sound.Stop(Program.Directory + "\home.wav")
Sound.Play(Program.Directory + "\home.wav") GetNewFrog()
'check if all found
For J = 3 To 3
If (FrogIsHome[J] = "false") Then goto ExitTickSub
EndIf
EndFor
DrawHome()
Score = Score + 1000
GoToNextLevel()
Goto ExitTickSub
EndIf
EndFor
NoMoreFrog()
EndIf
ExitTickSub:
EndSub
Sub PositionLogs
GraphicsWindow.BrushColor =
GraphicsWindow.GetColorFromRGB(128, 128, 255)
GraphicsWindow.FillRectangle(0, RiverTop, GraphicsWindow.Width,
RiverHeight) 'top row
LogX[1] = 20
LogY[1] = RiverTop LogW[1] = 80
LogH[1] = 40
LogX[2] = 140
LogY[2] = RiverTop LogW[2] = 120
LogH[2] = 40
LogX[3] = 300
LogY[3] = RiverTop LogW[3] = 40
LogH[3] = 40
LogX[4] = 400
LogY[4] = RiverTop LogW[4] = 80
LogH[4] = 40
LogX[5] = 540
LogY[5] = RiverTop LogW[5] = 80
LogH[5] = 40
'middle row
LogX[6] = 60
LogY[6] = RiverTop + 40
LogW[6] = 40
LogH[6] = 40
LogX[7] = 180
LogY[7] = RiverTop + 40
LogW[7] = 120
LogH[7] = 40
LogX[8] = 360
LogY[8] = RiverTop + 40
LogW[8] = 80
LogH[8] = 40
LogX[9] = 500
LogY[9] = RiverTop + 40
LogW[9] = 120
LogH[9] = 40
'bottom row
LogX[10] = 40
LogY[10] = RiverTop + 80
LogW[10] = 120
LogH[10] = 40
LogX[11] = 280
LogY[11] = RiverTop + 80
LogW[11] = 80
LogH[11] = 40
LogX[12] = 480
LogY[12] = RiverTop + 80
LogW[12] = 120
LogH[12] = 40
'speeds
If (Level = 1) Then LogSpeed[1] = 5
LogSpeed[2] = 5
LogSpeed[3] = 5
LogSpeed[4] = 5
LogSpeed[5] = 5
LogSpeed[6] = ‐3
LogSpeed[7] = ‐3
LogSpeed[8] = ‐3
LogSpeed[9] = ‐3
LogSpeed[10] = 2
LogSpeed[11] = 2
LogSpeed[12] = 2
EndIf
For I = 1 to NumberOfLogs Shapes.Move(Log[I], LogX[I], LogY[I])
EndFor
EndSub
Sub GetNewFrog
OnLog = 0
FrogLocation = 0
FrogX = 320
FrogY = StartTop Frog = FrogUp Shapes.Move(Frog, FrogX, FrogY)
Shapes.ShowShape(Frog) EndSub
Sub KeyDownSub
KD = GraphicsWindow.LastKey If (GameStatus = "Playing") Then
'Clear from current location
Shapes.HideShape(Frog) If (KD = "Up") Then Score = Score + 100
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogUp
FrogLocation = FrogLocation + 1
If (FrogLocation > 8) Then FrogLocation = 8
EndIf
ElseIf (KD = "Left") Then Score = Score + 1
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogLeft If
FrogX > 0 Then FrogX = FrogX ‐ FrogW
EndIf
ElseIf (KD = "Down") Then Score = Score + 50
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogDown
FrogLocation = FrogLocation ‐ 1
If FrogLocation < 0 Then FrogLocation = 0
EndIf
ElseIf (KD = "Right") Then Score = Score + 10
OnLog = 0
Sound.Stop(Program.Directory + "\Hop.wav")
Sound.Play(Program.Directory + "\Hop.wav") Frog = FrogRight If
(FrogX < GraphicsWindow.Width ‐ FrogW) Then FrogX = FrogX
+ FrogW
EndIf
EndIf
'put in new location
DrawFrog()
EndIf
EndSub
Sub DrawFrog
If (FrogLocation = 0) Then FrogY = StartTop ElseIf (FrogLocation = 1
Or FrogLocation = 2 Or FrogLocation = 3) Then FrogY = RoadTop + 140
‐ 45 * FrogLocation ElseIf (FrogLocation = 4) Then FrogY = GrassTop
ElseIf (FrogLocation = 5 Or FrogLocation = 6 Or FrogLocation = 7)
Then FrogY = RiverTop + 120 ‐ 40 * (FrogLocation ‐ 4) ElseIf
(FrogLocation = 8) Then FrogY = HomeTop + 40
EndIf
If (FrogLocation <> 8) Then Shapes.Move(Frog, FrogX, FrogY)
Shapes.ShowShape(Frog) EndIf
EndSub
Sub FindOverlap
Overlap = 0
'check to see if Frog overlaps with shape defined by ShapeX, ShapeW
If (FrogX + FrogW > ShapeX And FrogX + FrogW < ShapeX + ShapeW)
Then Overlap = 100 * (FrogX + FrogW ‐ ShapeX) / FrogW
ElseIf (FrogX > ShapeX And FrogX < ShapeX + ShapeW) Then Overlap
= 100 * (ShapeX + ShapeW ‐ FrogX) / FrogW
EndIf
EndSub
Sub NoMoreFrog
If (FrogLocation = 1 Or FrogLocation = 2 Or FrogLocation = 3) Then
Sound.Stop(Program.Directory + "\Beep.wav")
Sound.Play(Program.Directory + "\Beep.wav") ElseIf (FrogLocation = 4)
Then Sound.Stop(Program.Directory + "\Snake.wav")
Sound.Play(Program.Directory + "\Snake.wav") ElseIf (FrogLocation = 5
Or FrogLocation = 6 Or FrogLocation = 7) Then
Sound.Stop(Program.Directory + "\Splash.wav")
Sound.Play(Program.Directory + "\Splash.wav") ElseIf (FrogLocation =
8) Then Sound.Stop(Program.Directory + "\Splash.wav")
Sound.Play(Program.Directory + "\Splash.wav") EndIf
Shapes.HideShape(Frog) GraphicsWindow.BrushColor =
GraphicsWindow.BackgroundColor
GraphicsWindow.FillRectangle(GraphicsWindow.Width ‐
FrogsRemaining * FrogW ‐ 10, 5, FrogW, FrogH) FrogsRemaining =
FrogsRemaining ‐ 1
If FrogsRemaining >= 0 Then GetNewFrog()
Else
ExitStopButtonClick() EndIf
EndSub
Sub DrawHome
PadX[1] = 70
PadX[2] = 180
PadX[3] = 290
PadX[4] = 400
PadX[5] = 510
PadY = HomeTop + 15
PadW = 60
PadH = 60
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
For I = 1 To 5
GraphicsWindow.BrushColor = "Black"
GraphicsWindow.FillRectangle(PadX[I], PadY, PadW, PadH)
GraphicsWindow.PenColor = "Yellow"
GraphicsWindow.PenWidth = 3
GraphicsWindow.DrawRectangle(PadX[I], PadY, PadW, PadH)
FrogIsHome[I] = "false"
EndFor
EndSub
Sub GoToNextLevel
Sound.Stop(Program.Directory + "\NewLevel.wav")
Sound.Play(Program.Directory + "\NewLevel.wav") Level = Level + 1
GraphicsWindow.Title = "Leap Frog ‐ Level " + Level 'speed things up
For I = 1 To NumberOfVehicles If (VehicleSpeed[I] > 0) Then
VehicleSpeed[I] = VehicleSpeed[I] + 1
Else
VehicleSpeed[I] = VehicleSpeed[I] ‐ 1
EndIf
EndFor
For I = 1 To NumberOfLogs If (LogSpeed[I] > 0) Then LogSpeed[I] =
LogSpeed[I] + 1
Else
LogSpeed[I] = LogSpeed[I] ‐ 1
EndIf
EndFor
'add frog every 2nd level (maximum of 5)
If (Level ‐ 2 * Math.Floor(Level / 2) = 1) Then If FrogsRemaining < 5
Then FrogsRemaining = FrogsRemaining + 1
GraphicsWindow.DrawImage(ImageList.LoadImage(Program.Directory +
"\FrogUp.gif"), GraphicsWindow.Width ‐ FrogsRemaining * FrogW ‐ 10, 5)
EndIf
EndIf
'reposition logs, vehicles
PositionLogs()
PositionVehicles()
'delete logs, add vehicles
If (Level = 2) Then Shapes.HideShape(Log[1]) LogIsVisible[1] = "false"
ElseIf (Level = 3) Then Shapes.HideShape(Log[7]) LogIsVisible[7] =
"false"
Shapes.ShowShape(Vehicle[1]) Shapes.ShowShape(Vehicle[5])
VehicleIsVisible[1] = "true"
VehicleIsVisible[5] = "true"
ElseIf (Level = 4) Then Shapes.HideShape(Log[12]) LogIsVisible[12] =
"false"
Shapes.ShowShape(Vehicle[7]) Shapes.ShowShape(Vehicle[11])
VehicleIsVisible[7] = "true"
VehicleIsVisible[11] = "true"
ElseIf (Level = 5) Then Shapes.ShowShape(Vehicle[4])
VehicleIsVisible[4] = "true"
EndIf
EndSub
Sub UpdateScore
Shapes.SetText(DisplayScore, Score) If (Score > HighScore) Then
HighScore = Score Shapes.SetText(DisplayHighScore, HighScore) EndIf
EndSub
Leap Frog Game Program Review
The Leap Frog game program is now complete. Save and Run the program
and make sure it works as promised. Check that all options work correctly.
If there are errors in your implementation, go back over the steps of window
and code design. Go over the developed code – make sure you understand
how different parts of the program were coded. As mentioned in the
beginning of this chapter, the completed program is saved as LeapFrog in
the KidGamesSB\KidGamesSB Programs\LeapFrog folder.
While completing this program, new concepts and skills you should have
gained include:
This is the last program in these notes. By now, you should be a fairly
competent Small Basic programmer. There’s always more to learn though.
Consult the Internet and bookstores for more books about skills you might
want to gain.
Leap Frog Game Program Enhancements
There are some ways to change the Leap Frog program. Some possibilities
are:
➢ There are no time penalties in the game – you can play as long as you
like. Perhaps add a clock timer that rewards faster motion and causes
you to lose points or lose frogs if you dally.
➢ Add more features to the game. Perhaps, logs that randomly break or
alligators swimming in the river. Put random potholes in the road at
higher levels. Use your imagination.
➢ To make things a bit harder at higher levels, you might narrow down
the home rectangles a bit.
Appendix II. Sharing a Small Basic Program I bet
you’re ready to show your friends and colleagues some of the programs you
have built using Small Basic. Just give them a copy of your code, ask them
to install Small Basic and learn how to open and run a program. Then, have
them open your program and run it. I think you’ll agree this might be asking
a lot of your friends, colleagues, and, ultimately, your user base. We need to
know how to run a program without Small Basic.
For example, if I open the program folder for the Leap Frog program we
just built:
Voila! The Leap Frog program is running outside of the Small Basic
development environment! Go ahead and play the game if you like.
The next question is: how do you know if your user has the .NET
Framework installed on his or her computer? And, if they don’t, how can
you get it installed? These are difficult questions. So, in addition to our
program’s executable file, we also need to give a potential user the
Microsoft .NET Framework files and inform them how to install and
register these files on their computer. Things are getting complicated. Let’s
look at an easier and very flashy solution – letting users access and run your
programs over the Internet!
Start Small Basic and take a look at the toolbar. There are two buttons there
we haven’t talked about yet. Between the buttons to open and save files and
the ones for editing are buttons marked Import and Publish:
These are remarkable buttons. Clicking Import will take you to a Microsoft
website where you can import and open a program stored on the Internet by
you or other users. Publish allows you to store your programs on the
Internet for others to use.
To import a program, you require a Program ID. How do you get such
an ID? It is assigned when you Publish a program, so let’s try that. Click
the Cancel button for now.
When you publish a program, it will be available for all to see and use.
And, for now, there is no way to “unpublish” a program. So, be careful
what you publish. You may be leary about just giving your hard work
away. For the example here, I will use a very simple two line program
just to show how things work. You can decide what you want to publish.
Here, you can describe what your program is and what it does. You can
provide a category. This will help users find your program Also listed in
this window is this very interesting piece of information: You can view
your program at: http://smallbasic.com/program/?BGF564
If you click this link (or give the link to others and let them click it),
“magic” occurs.
When I click the link, I am taken to this website hosted by Microsoft:
I think you’ll agree this pretty neat. To share your programs with other
users, Publish them, then give them the program link given to you. If they
click the link, they can run the program. Well, almost. To use this feature, a
user’s computer must have a Microsoft product called Silverlight installed
on their computer. It can be downloaded from this website:
http://www.silverlight.net/
If a user attempts to access your Small Basic program via a provided link
and they do not have the required Silverlight product, they will be taken
through the installation steps.
Return to the website with your running program. In the upper right corner
is a box marked Embed this in your website. In this box is some code that
allows you to put your running application on your own website, if you
have one. The steps to do this are beyond this discussion, but I wanted you
to know such a step was possible.
Before leaving, lets return to the Import button in Small Basic. Click it
again and enter the program ID for your program (I used BGF564):
So, you have access to any code published to the Microsoft Small Basic
library. I’m guessing this library will be growing very quickly.
More Self-Study or Instructor-Led Computer
Programming Tutorials by Kidware Software
Small Basic For Kids is an illustrated introduction to computer programming that provides an
interactive, self-paced tutorial to the new Small Basic programming environment. The book consists
of 30 short lessons that explain how to create and run a Small Basic program. Elementary students
learn about program design and many elements of the Small Basic language. Numerous examples are
used to demonstrate every step in the building process. The tutorial also includes two complete
games (Hangman and Pizza Zapper) for students to build and try. Designed for kids ages 8+.
Programming Games with Microsoft Small Basic is a self-paced second semester “intermediate"
level programming tutorial consisting of 10 chapters explaining (in simple, easy-to-follow terms)
how to write video games in Microsoft Small Basic. The games built are non-violent, family-friendly,
and teach logical thinking skills. Students will learn how to program the following Small Basic video
games: Safecracker, Tic Tac Toe, Match Game, Pizza Delivery, Moon Landing, and Leap Frog. This
intermediate level self-paced tutorial can be used at home or school.
The Developer’s Reference Guide to Microsoft Small Basic While developing all the different
Microsoft Small Basic tutorials we found it necessary to write The Developer's Reference Guide to
Microsoft Small Basic. The Developer's Reference Guide to Microsoft Small Basic is over 500 pages
long and includes over 100 Small Basic programming examples for you to learn from and include in
your own Microsoft Small Basic programs. It is a detailed reference guide for new developers.
Basic Computer Games - Small Basic Edition is a re-make of the classic BASIC COMPUTER
GAMES book originally edited by David H. Ahl. It contains 100 of the original text based BASIC
games that inspired a whole generation of programmers. Now these classic BASIC games have been
re-written in Microsoft Small Basic for a new generation to enjoy! The new Small Basic games look
and act like the original text based games. The book includes all the original spaghetti code and
GOTO commands!
The Beginning Microsoft Small Basic Programming Tutorial is a self-study first semester
"beginner" programming tutorial consisting of 11 chapters explaining (in simple, easy-to-follow
terms) how to write Microsoft Small Basic programs. Numerous examples are used to demonstrate
every step in the building process. The last chapter of this tutorial shows you how four different
Small Basic games could port to Visual Basic, Visual C# and Java. This beginning level self-paced
tutorial can be used at home or at school. The tutorial is simple enough for kids ages 10+ yet
engaging enough for adults.
Programming Home Projects with Microsoft Small Basic is a self-paced programming tutorial
explains (in simple, easy-to-follow terms) how to build Small Basic Windows applications. Students
learn about program design, Small Basic objects, many elements of the Small Basic language, and
how to debug and distribute finished programs. Sequential file input and output is also introduced.
The projects built include a Dual-Mode Stopwatch, Flash Card Math Quiz, Multiple Choice Exam,
Blackjack Card Game, Weight Monitor,Home Inventory Manager and a Snowball Toss Game.
David Ahl's Small Basic Computer Adventures is a Microsoft Small Basic re-make of the classic
Basic Computer Games programming book originally written by David H. Ahl. This new book
includes the following classic adventure simulations; Marco Polo, Westward Ho!, The Longest
Automobile Race, The Orient Express, Amelia Earhart: Around the World Flight, Tour de France,
Subway Scavenger, Hong Kong Hustle, and Voyage to Neptune. Learn how to program these classic
computer simulations in Microsoft Small Basic.
JavaTM For Kids is a beginning programming tutorial consisting of 10 chapters explaining (in
simple, easy-to-follow terms) how to build a Java application. Students learn about project design,
object-oriented programming, console applications, graphics applications and many elements of the
Java language. Numerous examples are used to demonstrate every step in the building process. The
projects include a number guessing game, a card game, an allowance calculator, a state capitals
game, Tic-Tac-Toe, a simple drawing program, and even a basic video game. Designed for kids ages
12 and up.
Learn JavaTM GUI Applications is a 9 lesson Tutorial covering object-oriented programming
concepts, using an integrated development environment to create and test Java projects, building and
distributing GUI applications, understanding and using the Swing control library, exception handling,
sequential file access, graphics, multimedia, advanced topics such as printing, and help system
authoring. Our Beginning Java or Java For Kids tutorial is a pre-requisite for this tutorial
JavaTM Homework Projects is a Java GUI Swing tutorial covering object-oriented programming
concepts. It explains (in simple, easy-to-follow terms) how to build Java GUI project to use around
the home. Students learn about project design, the Java Swing controls, many elements of the Java
language, and how to distribute finished projects. The projects built include a Dual-Mode Stopwatch,
Flash Card Math Quiz, Multiple Choice Exam, Blackjack Card Game, Weight Monitor, Home
Inventory Manager and a Snowball Toss Game. Our Learn Java GUI Applications tutorial is a pre-
Programming Games with Visual Basic® is a semester long "intermediate" programming tutorial
consisting of 10 chapters explaining (in simple, easy-to-follow terms) how to build Visual Basic
Video Games. The games built are non-violent, family-friendly, and teach logical thinking skills.
Students will learn how to program the following Visual Basic video games: Safecracker, Tic Tac
Toe, Match Game, Pizza Delivery, Moon Landing, and Leap Frog. This intermediate level self-paced
tutorial can be used at home or school. The tutorial is simple enough for kids yet engaging enough
for beginning adults.
LEARN VISUAL BASIC is acomprehensive college prep programming tutorial covering object-
oriented programming, the Visual Basic integrated development environment, building and
distributing Windows applications using the Windows Installer, exception handling, sequential file
access, graphics, multimedia, advanced topics such as web access, printing, and HTML help system
authoring. The tutorial also introduces database applications (using ADO .NET) and web applications
(using ASP.NET).
Beginning Visual Basic® is a semester long self-paced "beginner" programming tutorial consisting
of 10 chapters explaining (in simple, easy-to-follow terms) how to build a Visual Basic Windows
application. The tutorial includes several detailed computer projects for students to build and try.
These projects include a number guessing game, card game, allowance calculator, drawing program,
state capitals game, and a couple of video games like Pong. We also include several college prep
bonus projects including a loan calculator, portfolio manager, and checkbook balancer. Designed for
students age 15 and up.
Visual Basic® Homework Projects is a semester long self-paced programming tutorial explains (in
simple, easy-to-follow terms) how to build a Visual Basic Windows project. Students learn about
project design, the Visual Basic toolbox, many elements of the Visual Basic language, and how to
debug and distribute finished projects. The projects built include a Dual-Mode Stopwatch, Flash Card
Math Quiz, Multiple Choice Exam, Blackjack Card Game, Weight Monitor,Home Inventory Manager
and a Snowball Toss Game.
VISUAL BASIC AND DATABASES is a tutorial that provides a detailed introduction to using
Visual Basic for accessing and maintaining databases for desktop applications. Topics covered
include: database structure, database design, Visual Basic project building, ADO .NET data objects
(connection, data adapter, command, data table), data bound controls, proper interface design,
structured query language (SQL), creating databases using Access, SQL Server and ADOX, and
database reports. Actual projects developed include a book tracking system, a sales invoicing
program, a home inventory system and a daily weather monitor.
Visual C#® For Kids is a beginning programming tutorial consisting of 10 chapters explaining (in
simple, easy-to-follow terms) how to build a Visual C# Windows application. Students learn about
project design, the Visual C# toolbox, and many elements of the C# language. Numerous examples
are used to demonstrate every step in the building process. The projects include a number guessing
game, a card game, an allowance calculator, a drawing program, a state capitals game, Tic-Tac-Toe
and even a simple video game. Designed for kids ages 12+.
Programming Games with Visual C#® is a semester long "intermediate" programming tutorial
consisting of 10 chapters explaining (in simple, easy-to-follow terms) how to build a Visual C# Video
Games. The games built are non-violent, family-friendly and teach logical thinking skills. Students
will learn how to program the following Visual C# video games: Safecracker, Tic Tac Toe, Match
Game, Pizza Delivery, Moon Landing, and Leap Frog. This intermediate level self-paced tutorial can
be used at home or school. The tutorial is simple enough for kids yet engaging enough for beginning
adults
LEARN VISUAL C# is a comprehensive college prep computer programming tutorial covering
object-oriented programming, the Visual C# integrated development environment and toolbox,
building and distributing Windows applications (using the Windows Installer), exception handling,
sequential file input and output, graphics, multimedia effects (animation and sounds), advanced
topics such as web access, printing, and HTML help system authoring. The tutorial also introduces
database applications (using ADO .NET) and web applications (using ASP.NET).
VISUAL C# AND DATABASES is a tutorial that provides a detailed introduction to using Visual
C# for accessing and maintaining databases for desktop applications. Topics covered include:
database structure, database design, Visual C# project building, ADO .NET data objects (connection,
data adapter, command, data table), data bound controls, proper interface design, structured query
language (SQL), creating databases using Access, SQL Server and ADOX, and database reports.
Actual projects developed include a book tracking system, a sales invoicing program, a home
inventory system and a daily weather monitor.