Let's get started on the development of this chapter's game project, the Guess a Number game. To create this game, you will follow the same five development steps that you've used to create previous chapter projects.
The Guess a Number game is played on a single window. Unlike previous applications where data was collected from the user using the InputBox() function, this game will collect the player's input by adding radio buttons and a check box to the user interface. In addition, instead of displaying output using the MessageBox.Show method, the game will display information messages for the player to read in a TextBox control located on the user interface.
The advantage of collecting player input and displaying game output on the user interface is that it will make the game run smoother, meaning that the player won't have to constantly stop and respond to pop-up windows as the game runs. In order to create the user interface, you'll have to learn how to work with several new types of controls, including the GroupBox, RadioButton, and CheckBox controls.
The Guess a Number game is made up of one form and the 17 controls listed in Table 6.2.
Control Type | Control Name | Description |
---|---|---|
GroupBox1 | grpRange | Contains radio buttons, a check box and a button that control the game's configuration settings |
GroupBox2 | grpScore | Displays the number of games won by the player and contains a button that is used to reset the score |
RadioButton1 | rbnControl10 | Sets the range of game numbers to 1 through 10 |
RadioButton2 | rbnControl100 | Sets the range of game numbers to 1 through 100 |
RadioButton3 | rbnControl1000 | Sets the range of game numbers to 1 through 1000 |
CheckBox1 | chkVerbose | Determines the level of messaging displayed by the game |
Label1 | lblGameswon | Identifies the TextBox control where the total number of games won is displayed |
Label2 | lblInstructions | Identifies the TextBox control where the player enters guesses |
Label3 | lblFeedback | Identifies the TextBox control where game output is displayed |
Button1 | btnDefaults | Resets default RadioButton and CheckBox control settings |
Button2 | btnReset | Resets the number of games won back to zero in order to start a new game session |
Button3 | btnCheckGuess | Processes the player's guess to see if the player guessed low, high, or won the game |
Button4 | btnNewGame | Start a new game |
TextBox1 | txtGamesWon | Displays the number of games that the player has won |
TextBox2 | txtInput | Collects and displays player guesses |
TextBox3 | txtOutput | Displays output messages generated during game play |
StatusBar1 | stbControl | Displays information messages during game play |
The first step in creating the Guess a Number game is to open up Visual Basic and create a new project as outlined below.
If you have not already done so, start up Visual Basic 2005 Express and then click on File and select New Project. The New Project dialog will appear.
Select Windows Application template.
Type Guess a Number as the name of your new application in the Name field located at the bottom of the New Project window.
Click on OK to close the New Project dialog.
Visual Basic will now create a new project for you and display a new form upon which you will design the game's user interface.
The first step in laying out the user interface is adding controls to the form and moving and resizing them to the appropriate locations. The following procedure outlines the overall steps involved in creating the game's user interface. As you go through each step, make sure that you reference Figure 6.9 so that you'll know where each control should be placed.
Figure 6.9: Completing the interface design for the Guess a Number game.
Start by adding two GroupBox controls to the form. Position and resize them as shown in Figure 6.9.
Add three RadioButton controls to the form and move them into the first GroupBox control, as shown in Figure 6.9.
A RadioButton control provides the ability to collect True/False or On/Off information. RadioButton controls are used together in groups to provide users with the ability to pick between mutually exclusive choices.
A GroupBox control container that is used to organize other controls. The GroupBox control display a caption, set using its Text property, and displays a visible border.
Add a CheckBox control to the form and move it just underneath the last RadioButton control.
A CheckBox control provides the ability to collect True/False or On/Off Information. Unlike RadioButton controls, CheckBox controls can be used individually. When selected, the CheckBox control displays an x.
Add a Button control to the first GroupBox control and reduce its size as shown in Figure 6.9.
Now, add a Label, a TextBox, and a Button control to the second GroupBox and resize and position them as shown in Figure 6.9.
Add two additional Label controls and position them toward the middle of the form as shown in Figure 6.9.
Add a TextBox control to the right of the first Label control and increase its width by approximately 30 percent.
Add another TextBox control underneath the second Label control, set its Multiline property equal to True and resize it until it takes up most of the remaining space in the lower right-hand side of the form.
Add two more Button controls on the right-hand side of the form between the two Label and TextBox controls.
Lastly, add a StatusBar control to the bottom of the form.
The overall layout of your new application's form is now complete.
Now it is time for you to customize various properties belonging to the form and the controls that you have placed on it. Begin by changing the form properties listed in Table 6.3.
Property | Value |
---|---|
Name | frmMain |
Cursor | Hand |
FormBorderStyle | Fixed3D |
StartPosition | CenterScreen |
Text | Guess a Number |
Next, make changes shown in Table 6.4 to the GroupBox controls.
Control | Property | Value |
---|---|---|
GroupBox1 | Name | grpRange |
Font.Bold | True | |
Text | Select Range | |
GroupBox2 | Name | grpScore |
Font.Bold | True | |
Text | Score |
Make the changes shown in Table 6.5 to the RadioButton controls.
Control | Property | Value |
---|---|---|
RadioButton1 | Name | rbnControl10 |
Font.Bold | True | |
Text | Range: 1 to 10 | |
RadioButton2 | Name | rbnControl100 |
Checked | True | |
Font.Bold | True | |
Text | Range: 1 to 100 | |
RadioButton3 | Name | rbnControl1000 |
Font.Bold | True | |
Text | Range: 1 to 1000 |
Make the changes shown in Table 6.6 to the CheckBox control.
Property | Value |
---|---|
Name | chkVerbose |
Checked | True |
CheckState | Checked |
Font.Bold | True |
Text | Verbose Messaging |
Make the changes shown in Table 6.7 to the Button controls.
Control | Property | Value |
---|---|---|
Button1 | Name | btnDefaults |
Font.Bold | True | |
Text | Reset Defaults | |
Button2 | Name | btnReset |
Font.Bold | True | |
Text | Reset Score | |
Button3 | Name | btnCheckGuess |
Enabled | False | |
Font.Bold | True | |
Text | Check Guess | |
Button4 | Name | btnNewGame |
Font.Bold | True | |
Text | New Game |
Make the changes shown in Table 6.8 to the Label controls.
Control | Property | Value |
---|---|---|
Label1 | Name | lblGamesWon |
Font.Bold | True | |
Text | No. of Games Won: | |
Label2 | Name | lblInstructions |
Font.Bold | True | |
Font.Size | 10 | |
Text | Enter Your Guess: | |
Label3 | Name | lblFeedback |
Font.Bold | True | |
Text | Feedback and Results |
Make the changes shown in Table 6.9 to the TextBox controls.
Control | Property | Value |
---|---|---|
TextBox1 | Name | txtGamesWon |
Font.Bold | True | |
ReadOnly | True | |
TabStop | False | |
TextBox2 | Name | txtInput |
Enabled | False | |
Font.Bold | True | |
TextBox3 | Name | txtOutput |
Font.Bold | True | |
ReadOnly | True |
Make the changes shown in Table 6.10 to the StatusBar control.
Property | Value |
---|---|
Name | stbControl |
SizingGrip | False |
Text | Game Readyl |
That's it. At this point, you have configured all the form and control properties that need to be set at design time.
Let's begin by double-clicking on the form and adding the following statement just beneath the Public Class frmMain statement, as shown below.
Public Class frmMain 'Declare variable used to store the game's randomly generated number Private intRandomNumber As Integer End Class
The intRandomNumber variable will be used through the application to store the game's randomly generated secret number. Next, modify the form's Load event procedure as shown below.
'This Sub procedure executes when the game's interface is loaded Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load txtGamesWon.Text = 0 'Set number of games won to zero btnNewGame.Focus() 'Set focus to the Button labeled New Game End Sub
The first statement displays a value of 0 in the txtGamesWon control, and the second statement places focus on the btnNewGame control. Next, we need to add logic to the btnDefaults control that will reset the game's default settings, as controlled by the RadioButton and CheckBox controls located in the first GroupBox control. Do so by modifying the Click event procedure for the btnDefaults control, as shown below.
'This Sub procedure executes when the btnDefaults Button is clicked Private Sub btnDefaults_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnDefaults.Click rbnControl100.Checked = True 'Check the rbnConrol100 radio button chkVerbose.Checked = True 'Turn on verbose messaging txtInput.Focus() 'Set focus to txtInput End Sub
The first statement selects the RadioButton that represents the range of 1 to 100. The second statement selects (by placing an x inside) the chkVerbose CheckBox control, and the third statement sets the focus to the txtInput control (to save the player the trouble of having to put it there before typing in the next guess).
Next, let's add logic to the btnReset control so that the player can reset the value that tracks the number of games won to 0. Also, take note that the value used to track the number of games won is not assigned to a variable. Instead, it is stored and managed within the txtGameWon control's Text property.
'This Sub procedure executes when the player clicks the Reset Defaults Private Sub btnReset_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnReset.Click txtGamesWon.Text = 0 'Set number of games won to zero End Sub
Next, add the following statements to the TextChanged event for the txtInput control.
'This Sub procedure executes as soon as the player types in a guess Private Sub txtInput_TextChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles txtInput.TextChanged btnCheckGuess.Enabled = True 'Enable the Button labeled Check Guess btnNewGame.Enabled = False 'Disable the Button labeled New Game End Sub
The TextChanged event is automatically triggered whenever the user keys something into the TextBox control associated with the event. It is used in the Guess a Number game to control when the btnCheckGuess button is enabled and when the btnNewGame is disabled.
Now we need to add logic to the application that randomly generates the game's secret number. To do so, I have decided to create a new procedure named GetRandomNumber() and place the logic to generate the random number in it. You won't be able to automatically generate this procedure by double-clicking on an object in the form designer. Instead, you'll need to key it in entirely by hand as shown below. You'll learn more about how to work with procedures in Chapter 8, "Enhancing Code Structure and Organization," including how to create your own custom procedures. For now, just key in the procedure as shown below.
'This Sub procedure retrieves the game's random number Public Sub GetRandomNumber() 'Declare variable representing the random number's maximum value Dim intUpperLimit As Integer 'Instantiate a Random object Dim objRandom As New Random 'If the 1st radio button is selected set the maximum value to 10 If rbnControl10.Checked = True Then intUpperLimit = 10 End If 'If the 2nd radio button is selected set the maximum value to 100 If rbnControl100.Checked = True Then intUpperLimit = 100 End If 'If the 3rd radio button is selected set the maximum value to 1000 If rbnControl1000.Checked = True Then intUpperLimit = 1000 End If 'Use the Random object's Next() method to generate a random number intRandomNumber = objRandom.Next(intUpperLimit) End Sub
When called by the btnNewGame control's Click event procedure, the GetRandomNumber procedure instantiates a new Random object called objRandom and checks to see which RadioButton control is currently selected so that it will know what range to use when generating the game's secret number. It then executes Random object's Next() method, in order to generate the random number. The Next() method is passed the value stored in the intUpperLimit variable, in order to specify the maximum range from which the random number should be selected (between 0 and the value of intRandomNumber).
Trick | The Random object's Next() method is used to generate a random number. If called without passing it any parameters, the Next() method generates a nonnegative whole number. If passed a single integer value, the Next() method generates a random number between zero and the value of the integer argument. If passed two integer values, the Next() method will generate a random number within the specified range. |
Now let's add the code required for the Click event belonging to the btnCheckGuess control, as shown below.
'This Sub procedure executes when the player clicks on the button 'labeled Check Guess Private Sub btnCheckGuess_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCheckGuess.Click Dim intPlayerGuess As Integer 'Declare variable to store guess Static intNoOfGuesses As Integer 'Declare variable to keep track 'of the number of guesses made If txtInput.Text.Length > 0 Then 'Make sure player typed something If IsNumeric(txtInput.Text) = True Then 'Ensure input is numeric 'Convert String input to Integer data type intPlayerGuess = Int32.Parse(txtInput.Text) btnCheckGuess.Enabled = True 'Enable Check Guess button 'See if player's guess is correct If intPlayerGuess = intRandomNumber Then txtInput.Text = "" 'Clear the TextBox control intNoOfGuesses += 1 'Increment variable by one 'See if player enabled verbose messaging If chkVerbose.Checked = True Then txtOutPut.Text = "Congratulations!" & _ ControlChars.CrLf & ControlChars.CrLf & _ "You have won the Guess a Number Game. " & _ ControlChars.CrLf & ControlChars.CrLf & _ "Number of guesses made = " & intNoOfGuesses Else txtOutPut.Text = "Congratulations! You Win." End If intNoOfGuesses = 0 'Reset variable to zero txtInput.Enabled = False 'Disable TextBox control 'Update the display of the total number of games won txtGamesWon.Text = txtGamesWon.Text + 1 'Disable the Button labeled Check Guess btnCheckGuess.Enabled = False 'Enable the Button labeled New Game btnNewGame.Enabled = True ' 'Enable all Radio buttons rbnControl10.Enabled = True rbnControl100.Enabled = True rbnControl100.Enabled = True 'Enable the two reset buttons btnDefaults.Enabled = True btnReset.Enabled = True stbControl.Text = "Game Ready!" 'Post sta tusbar message End If 'See if the player's guess was too low If intPlayerGuess < intRandomNumber Then txtInput.Text = "" 'Clear the TextBox control intNoOfGuesses += 1 'Increment variable by one 'See if player enabled verbose messaging If chkVerbose.Checked = True Then txtOutPut.Text = "The number that you " & _ "entered was too low. Enter higher number " & _ "and try again." & _ ControlChars.CrLf & ControlChars.CrLf & _ "Number of guesses taken so far = " & _ intNoOfGuesses Else txtOutPut.Text = "Too low." End If End If 'See if the player's guess was too high If intPlayerGuess > intRandomNumber Then txtInput.Text = "" 'Clear the TextBox control intNoOfGuesses += 1 'Increment variable by one 'See if player enabled verbose messaging If chkVerbose.Checked = True Then txtOutPut.Text = "The number that you " & _ "entered was too high. Enter lower number " & _ "and try again." & _ ControlChars.CrLf & ControlChars.CrLf & _ "Number of guesses taken so far = " & _ intNoOfGuesses Else txtOutPut.Text = "Too high. Try again." End If End If Else txtInput.Text = "" 'Clear the TextBox control 'Display message if player fails to provide numeric input If chkVerbose.Checked = True Then txtOutPut.Text = "Sorry but you entered a " & _ "non-numeric guess. Please try again and be " & _ "sure to enter a number this time." Else txtOutPut.Text = "Numeric input required. Try again." End If End If Else txtInput.Text 'Clear the TextBox control 'Display error if player fails to provide input If chkVerbose.Checked = True Then txtOutPut.Text = "Sorry but to play you must enter a " & _ "number. Please enter a number and try again." Else txtOutPut.Text = "No input provided. try again." End If End If txtInput.Focus() 'Set focus to the TextBox control End Sub
As you can see, this procedure is rather long and contains the bulk of the application's programming logic. It begins by declaring two variables. The first variable is intPlayerGuess and is used to store and process the input provided by the player. A new value will be assigned to this variable each time the player clicks on the Button control labeled Check Guess. Therefore, it is declared as a local variable. However, the second variable, which is named intNoOfGuesses, is defined as a Static variable, making its lifetime last for as long as the game runs, so that it can be used to maintain a count of the number of guesses that the player makes during each game.
Next, an If…Then…Else block is set up that determines what statements in the procedure will execute based on whether or not the player entered any input. If no input was provided, an error message is displayed in the txtOutput control. Otherwise a second nested If…Then…Else block executes and checks to see if the input supplied by the player is numeric. If the input is not numeric, an error message is displayed in the txtOutput control. Otherwise, one of three nested If…Then blocks execute. The first If…Then block checks to see if the player won the game by guessing the secret number. The second If…Then block checks to see if the player's guess was too low, and the third If…Then block checks to see if the player's guess was too high.
If the player's guess was too high or too low, an error message is displayed in the txtOutput control. The message that is displayed depends on whether the chkVerbose control is checked. If the player guesses correctly, she wins the game and a congratulatory message is displayed in the txtOutput control. In addition, the following actions are taken to prepare the game for another play:
The value of intNoOfGuesses is reset to zero.
The value indicating the number of games won is incremented by adding 1 to the value stored in the txtGamesWon control's text property.
The Check Guess button is disabled and the New Game button is enabled.
The game's RadioButton controls are enabled, allowing the player to make changes to them if desired.
The game's Reset Default button is also enabled.
The message displayed in the game's StatusBar control is updated.
Last but not least, it is time to add some code to the btnNewgame control's Click event procedure, as shown below.
'This Sub procedure executes when the New Game button is clicked Private Sub btnNewGame_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnNewGame.Click GetRandomNumber() 'Call the GetRandomNumber procedure txtOutPut.Text = "" 'Clear the TextBox control txtInput.Text = "" 'Clear the TextBox control btnNewGame.Enabled = False 'Enable the New Game button btnCheckGuess.Enabled = True 'Disable the Check Guess button txtInput.Enabled = True 'Enabled the TextBox control 'Disable all Radio buttons rbnControl10.Enabled = False rbnControl100.Enabled = False rbnControl1000.Enabled = False 'Disable the two reset buttons btnDefaults.Enabled = False btnReset.Enabled = False stbControl.Text = "Enter your guess." 'Display instructions txtInput.Focus() 'Set focus to the TextBox control End Sub
When clicked, the code for the button labeled New Game clears out any text display in the txtInput and txtOutput controls. Next, the btnNewGame control is disabled, and the btnCheckGuess control is enabled. Then the txtInput control is enabled in order to allow the player to enter a guess, and the game's RadioButton control and btnReset control are all disabled, preventing the player from making configuration changes while a new game is being played. Lastly, an instructional message is displayed on the game's StatusBar control, and the cursor is placed in the txtInput control.
That's it. The Guess a Number game is ready to run. Press F5 and see how it works. If you have any errors, double-check your typing. Otherwise, pass it on to your friends and ask them to play and to report any problems back to you if they run into one.