Controls on the fly (Matt Gertz)

So last week, I posted up a simple “Maze” game, in which you navigate through a virtual environment similar to the old “Myst” game.  The way I’d coded it, though, it didn’t actually have any “game” to it – you just walked around.  In this post I’ll add some state to it (which, after all, is pretty much all that defines a game, beyond being fun) -- things to interact with.

There are a number of ways I could implement environmental objects in the game, but I think I’ll take this opportunity to discuss how to add controls on the fly.  I could add a bunch of controls to my form and just make them visible or enable them as needed, but that could be a lot of controls on the form that generally aren’t being used  -- creating controls as needed makes better sense.  Creating a control on the fly is incredibly simple in Visual Basic, and it’s also very easy to handle events on those controls. 

First, let’s check to see if we need to add a control.  In the previous code, I had an empty method called “AddExceptionalInfo,” called on each transition, which we’ll fill up now.  Let’s say that, when the user gets to square (1,1) and looks down (regardless of his/her compass orientation), they’ll see a gerbil.  (Please note that I don’t have a gerbil fixation; it’s just that the GIF was handy from my post two weeks ago.)  So, we start out with:

        If x = 1 AndAlso y = 1 AndAlso z = 0 AndAlso att = Attitude.Down Then

 

Now we’ll add the gerbil:

                Dim gerbilPictBox As New PictureBox

                gerbilPictBox.Image = My.Resources.walter1

                gerbilPictBox.Left = 400

                gerbilPictBox.Top = 400

 

The control exists, but is not on the form yet.  To do that, we just execute the following lines of code:

                Me.Controls.Add(gerbilPictBox)

                gerbilPictBox.BringToFront()

        End If

 

which adds the gerbil to the form and makes sure that it’s on top of the navigation labels.

So far, so good.  If you navigate to (1,1) and look down, you’ll see a gerbil.  However, when you look up again, the gerbil is still in front of you, floating in mid-air!  Clearly, we need to get rid of the gerbil when we’re looking in a different direction.  Fortunately, I can navigate through my list on controls and get rid of the inappropriate one.  I’ll add the following code to the top of the same method:

        ' First, clean up any controls left behind:

        Dim oldControls() As Control

        oldControls = Me.Controls.Find("TempGerbil", True)

        If oldControls.GetLength(0) > 0 Then

            Me.Controls.Remove(oldControls(0))

        End If

 

which will look through the form’s controls, return an array of any that have the key “TempGerbil,”  and then remove the first element from that array (which should only have one element anyway if I’ve done my job properly – in shipping code, I’d add a check here to make sure).  Then, in the code where I create the gerbil, I just add the line:

                gerbilPictBox.Name = "TempGerbil"

 

so that the previous code will find it when entering the function.

So, now the gerbil will only appear when you look down in (1,1), and will go away when you look up.  But, let’s say that it’s important to the game to collect the gerbil.  (This is starting to sound a lot like “Zork,” I realize…)  To support that, we’ll need to handle events on the gerbil.  First, let’s create a state variable as a member of the form:

    Dim hasGerbil As Boolean = False

 

And we’ll add an event handler which changes the state when the gerbil is acquired (i.e., double-clicked):

    Private Sub Gerbil_DoubleClick(ByVal sender As Object, _

ByVal e As System.EventArgs)

        Me.hasGerbil = True

        Me.Controls.Remove(sender)

    End Sub

 

Note that I don’t have to search for the control to remove, since the value of “sender” is the control that fired the event, which will be the gerbil control.

Now, we’ll update our gerbil creation code so that we don’t see a gerbil if we’ve already picked it up:

        If x = 1 AndAlso y = 1 AndAlso z = 0 AndAlso att = Attitude.Down Then

            If hasGerbil = False Then ' Have we already picked it up?

 

And finally, to connect the double-click event handler to the gerbil control, we just need one line of code in the gerbil creation code, right before we add it to the form:

 

                AddHandler gerbilPictBox.DoubleClick, AddressOf Gerbil_DoubleClick

 

And that’s it!  The player can pick up the gerbil by double-clicking on it, and carry it off to wherever having a gerbil would make game sense. 

This was a quick-n-dirty code-up to demonstrate adding controls; I’ve appended the full code to this post.  Obviously, you could clean it up to support multiple controls appearing in squares, dropping things you’ve picked up, using one control with another via dragging controls (as in my post two weeks ago), and so on.  In a “professional” program I’d actually create an array of all of the interesting objects (such as gerbils) which would include their location & name, and which would be scanned in the “AddExceptionalInfo” so that I didn’t have to special-case individual instances as I’ve done here -- this would also help me support dropping inventory in new locations, etc, since the coordinates wouldn't be hard coded.  However, all of the complicated bits are already coded here, and as you can see, they’re really not that complicated at all when using Visual Basic.

I’m going to try to think of a non-gaming topic for next time – talk to you then!

--Matt--*