You can now add the landing pad, another simple rectangular
shape control that
you should place towards the right side of the moon. Call it shpPad, make it just a little wider
than the lander, and make sure its top surface is in line with the lunar
surface, as shown below (this time I will show the form with BackColor = black,
as you should have).

Try
running the program, and you will find that the lander falls straight through
the lunar surface! This should not really come as a surprise, for we have
written no code to detect the actual landing. It's easy for us to see
when the lander has hit the ground, but how can we put this into code so that
the stupid computer can detect what is so obvious to us clever humans? The
lander has landed when the bottom of the picturebox reaches (or goes
lower than) the top of the lunar surface. There is no property that
directly indicates where the bottom of the picturebox is located, but we can
find out where it is by adding picLander.Top + picLander.Height, as shown in the
following picture. In this picture, we know that the lander has not landed
because picLander.Top + picLander.Height is still less than shpMoon.Top.

We
will use an IF structure to check whether the lander has landed, and if it has
we will give a messagebox message. Change the timer code as follows:
Private Sub tmr1_Timer()
If picLander.Top + picLander.Height >= shpMoon.Top Then
MsgBox ("You have landed")
End
End If
picLander.Left = picLander.Left + vx
picLander.Top = picLander.Top + vy
vy = vy + 3
End Sub
Note that a line has been included to stop the program as soon
as the landing has been detected, otherwise the messagebox will reappear
constantly (type Ctrl-pause on the keyboard if you ever find yourself in a
situation where you cannot stop your program). Try running the program.
Our
code can now detect a landing but cannot detect whether the landing occurred in
the right place. This will be rather complex code for we have to check both the
left edge of the picturebox and the right edge. What is the condition for a good
landing? Look at the picture below.

Perhaps
you can see that the condition for the left edge to be OK is
picLander.Left >= shpPad.Left
Note the inequality 'greater than or equal to' in the above
line.
The condition for the right edge is more complicated. To
make it easier, let's make two new variables to give the position of the right
edge of the picturebox and the shpPad shape:
LanderRight = picLander.Left + picLander.Width
PadRight = shpPad.Left + shpPad.Width
Note that the variables on the left are not properties,
so it would be wrong to use dot notation for them - do NOT put dots in these
variable names. The new variables do not need to be declared with DIM like vx
and vy since the new variables are used only in this subroutine.
Now
the condition for the right edge to be OK is
and the condition for BOTH edges to be right is
(picLander.Left >= shpPad.Left) AND (LanderRight <= PadRight)
Note that conditions can be connected with words like AND or OR
just as in English. I've used parentheses to make the above line more legible.
So
now we are ready to modify the timer code. We only need to check the horizontal
landing position if we have already detected a landing, so the new IF structure
should be 'nested' inside the existing one. Note how the indentation of lines
inside each IF structure helps to make the code more legible.
Private Sub tmr1_Timer()
If picLander.Top + picLander.Height >= shpMoon.Top Then
LanderRight = picLander.Left + picLander.Width
PadRight = shpPad.Left + shpPad.Width
If (picLander.Left >= shpPad.Left) And (LanderRight <= PadRight) Then
MsgBox ("The Eagle has landed")
End
Else
MsgBox ("You crashed!")
End
End If
End If
picLander.Left = picLander.Left + vx
picLander.Top = picLander.Top + vy
vy = vy + 3
End Sub
Your lander program should be working fine now - this program is
almost fun! There's just one annoying problem: it doesn't take long to land, and
once you've landed (especially if you crashed) you would probably like the
option of trying again. Our program doesn't give that option... yet... but we
can add it without too much trouble. We will, for the first time, use a
messagebox to ask a question. Look at the following line:
response = MsgBox("You crashed! Try again?", vbYesNo)
The last part of the line, vbYesNo, tells the program to display
a 'yes' button and a 'no' button in the message box, instead of the usual 'OK'
button. The user's response has to be stored somewhere, so the line begins with
the name of a variable into which the response should be stored.
The
next line should test the response with an IF structure and act accordingly:
If response = vbYes Then
Reset
Else
End
End If
This is fine, except that VB does not understand the command
'Reset', so it will do nothing when it reaches that line. Actually it does
do something - it generates a 'reset' event, but since there is no subroutine to
handle this event, nothing happens. We will add a 'reset' subroutine later - for
the time being, just modify the timer code like this:
Private Sub tmr1_Timer()
If picLander.Top + picLander.Height >= shpMoon.Top Then
LanderRight = picLander.Left + picLander.Width
PadRight = shpPad.Left + shpPad.Width
If (picLander.Left >= shpPad.Left) And (LanderRight <= PadRight) Then
MsgBox ("The Eagle has landed")
End
Else
response = MsgBox("You crashed! Try again?", vbYesNo)
If response = vbYes Then
Reset
Else
End
End If
End If
End If
picLander.Left = picLander.Left + vx
picLander.Top = picLander.Top + vy
vy = vy + 3
End Sub
Oooooo - the code is starting to look pretty complicated - show
it to your parents if you want to impress them! As previously stated, notice how
the indentation (the inclusion of spaces at the beginning of some lines) helps
to make the structure of the program easier to see. We can easily match each 'if'
with its 'else' (if it has one) and with its 'end if'. In the
above subroutine I've coloured the background of these words to emphasize this,
but VB won't do that for you. We can see that there are 'if structures' inside
'if structures' inside 'if structures' - this is called 'nesting' and is
very common in computer programs so get used it!
Now we will create a subroutine to handle the 'reset' event, so
that the program knows what to do when it reaches that line. What exactly do we
need to do in order to reset our program? We need to
Underneath ALL your existing code, type this line
When you press the Enter key to start the next line, note that
VB has automatically given you the bottom wrapper for this subroutine.
Now
add the code to reset the program:
Private Sub Reset()
picLander.Left = 300 'recall that VB uses a tiny unit called the 'twip'
' replace this comment with a line to move the lander close to the top
vx = 0
' replace this comment with a line to set the vertical velocity to zero
End Sub
The above subroutine includes 'comments' (in green) for you to
replace. Anything that follows an apostrophe in VB code becomes a 'comment' that
VB will ignore but that will help you understand the code when you come back to
work on it in the future. Professional programmers put lots of comments in their
code and you should do the same.
If you have followed all my instructions
perfectly then
a) you are a genius
b) you should have a lander program that correctly resets if you crash the
lander and then choose to try again
You may be able to see the
lander running in a web page by following this link.
Or you may not, since certain since security settings may block it. This was done by making an
ActiveX control in VB6 (not 5) and then
incorporating that into the web page. If you'd like to know how to convert
your own projects into ActiveX controls so that you can put them on your web
site you can get advice also by following the same link.
Now your program is working
very well, but I'm sure you can think of ways of making it even better. This is
your chance to earn by adding features that you will
devise your own code for. Here are some suggestions: