Introduction
One of my all-time favourite games has to be Hangman. It wins loose-hands… Pardon the pun. As many of you may know, I am not the biggest gamer—not like Hangman can be classified as a gamer’s game, but still, it takes a lot for me to actually sit down and play a game. I suppose time is a big factor.
Today, you will learn how to create a basic Hangman game with Visual Basic.
For the uninformed…
Hangman
Hangman is a guessing game usually played with pencil and paper by two or more players. One player thinks of a word, phrase, or sentence and the other tries to guess the correct word, phrase, or sentence by suggesting letters, within a certain number of guesses.
The word, phrase, or sentence to guess is usually represented by a row of dashes, each representing a letter of the phrase. If the guessing player suggests a letter that occurs in the word, the other player should write the letter in all its correct positions. If the suggested letter or number does not occur in the word, the other player should draw one element of a hanged man stick figure as a tally mark.
Our Project
Start Visual Studio and create a new Visual Basic Windows Forms project.
Design
Design your form so that resembles Figure 1. You can name all your objects whatever you like, but keep in mind that my object names may differ from yours.
Figure 1: Our Design
Code
Declare the following variables:
Dim arrTerms() As String = {"Mercedes", "Audi", _ "BMW", "Mazda", "Volkswagen"} Dim rndRandom As New Random Dim btnLetters() As Button Dim lstEnteredLetters As New List(Of Label) Dim blnSkip As Boolean Dim intStage As Integer = 0
arrTerms is an array that hosts the terms that will have to be guessed during the game. There could obviously be more arrays and more terms, but this article is only a quick introduction on how to create a hangman game with Visual Basic.
rndRandom is a Random object that will assist in picking an item from the preceding array. btnLetters is a dynamic button and will aid in giving the existing buttons a consolidated event handler. lstEnteredLetters is a List of label objects. Whatever letter gets chosen by the user will have to be displayed.
blnSkip allows you to skip an already selected letter. intStage indicates the game’s progress and, depending on the Stage the game is in, the hangman will be drawn at that level.
Add the Form_Load event:
Private Sub Form1_Load(sender As Object, e As EventArgs) _ Handles MyBase.Load Me.DoubleBuffered = True btnLetters = Me.Controls.OfType(Of Button).Except(New Button() _ {btnNew}).ToArray Array.ForEach(btnLetters, Sub(b) AddHandler b.Click, _ AddressOf btn_click) Reset() End Sub
Setting the DoubleBuffered property of any control reduces the flickering that gets caused by progressive redrawing of parts of a displayed surface. btnLetters contains all the alphabetic buttons, and then an event handler gets added that handles the Click events for each of the buttons. Lastly, a Sub named Reset is called, which we will add later.
Add the btn_Click event to handle all the click events from the alphabetic buttons:
Private Sub btn_click(sender As Object, e As EventArgs) If blnSkip Then Return End If Dim btnTemp As Button = DirectCast(sender, Button) btnTemp.Enabled = False Array.ForEach(lstEnteredLetters.ToArray, Sub(lbl) lbl.Text = _ If(lbl.Tag.ToString = btnTemp.Text, btnTemp.Text, lbl.Text)) For x As Integer = 1 To lstEnteredLetters.Count - 1 lstEnteredLetters(x).Left = lstEnteredLetters(x - 1).Right Next If lstEnteredLetters(lstEnteredLetters.Count - 1).Right > _ Me.ClientSize.Width - 14 Then Me.SetClientSizeCore(lstEnteredLetters(lstEnteredLetters.Count _ - 1).Right + 14, 381) End If intStage += If(Not lstEnteredLetters.Any(Function(lbl) lbl.Text = _ btnTemp.Text), 1, 0) blnSkip = lstEnteredLetters.All(Function(lbl) lbl.Text <> _ " ") OrElse intStage = 10 Me.Invalidate() End Sub
If a letter has already been selected, nothing must happen. In other words: The button must be skipped. Once a button has been pressed, the item gets added to the lstEnteredLetters list. After the selected button’s text has been added to the lstEnteredLetters list, the letter gets displayed on the dynamically created label, and the width of the Letters’ display area gets dynamically adjusted to compensate for the width of the entered letter.
Add the Reset sub:
Private Sub Reset() SetClientSizeCore(403, 486) Dim strTerm As String = arrTerms(rndRandom.Next(0, _ arrTerms.Length)).ToUpper Array.ForEach(Me.Controls.OfType(Of Label).ToArray, _ Sub(lbl) lbl.Dispose()) Array.ForEach(btnLetters, Sub(b) b.Enabled = True) lstEnteredLetters = New List(Of Label) Dim intX As Integer = 14 For Each c As Char In strTerm Dim lblTemp As New Label lblTemp.Text = " " lblTemp.Font = New Font(Me.Font.Name, 18, _ FontStyle.Underline) lblTemp.Location = New Point(intX, 250) lblTemp.Tag = c.ToString lblTemp.AutoSize = True Controls.Add(lblTemp) lstEnteredLetters.Add(lblTemp) intX = lblTemp.Right Next blnSkip = False intStage = 0 Me.Invalidate() End Sub
The Reset sub simply returns all the variables to their default values and disposes the event handlers created during execution of the program. Also, it creates and formats the labels according the text inside the Terms array.
Add the following code for the ‘New‘ button that restarts the game by calling Reset:
Private Sub Button1_Click(sender As Object, e As EventArgs) _ Handles btnNew.Click Reset() End Sub
Add the last part of code, which is the Form’s Paint event:
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As _ System.Windows.Forms.PaintEventArgs) Handles Me.Paint If intStage >= 1 Then e.Graphics.DrawLine(New Pen(Color.Black, 2), 85, 190, 210, 190) End If If intStage >= 2 Then e.Graphics.DrawLine(New Pen(Color.Black, 2), 150, 190, 150, 50) End If If intStage >= 3 Then e.Graphics.DrawLine(New Pen(Color.Black, 2), 150, 50, 198, 50) End If If intStage >= 4 Then e.Graphics.DrawLine(New Pen(Color.Black, 2), 198, 50, 198, 70) End If If intStage >= 5 Then e.Graphics.DrawEllipse(New Pen(Color.Blue, 2), _ New Rectangle(188, 70, 20, 20)) End If If intStage >= 6 Then e.Graphics.DrawLine(New Pen(Color.Blue, 2), 198, 90, 198, 130) End If If intStage >= 7 Then e.Graphics.DrawLine(New Pen(Color.Blue, 2), 198, 95, 183, 115) End If If intStage >= 8 Then e.Graphics.DrawLine(New Pen(Color.Blue, 2), 198, 95, 213, 115) End If If intStage >= 9 Then e.Graphics.DrawLine(New Pen(Color.Blue, 2), 198, 130, 183, 170) End If If intStage >= 10 Then e.Graphics.DrawLine(New Pen(Color.Blue, 2), 198, 130, 213, 170) End If End Sub
Depending on the number of guesses, the progress of the game is shown in the form of drawn objects that create the gallows and the man and his limbs. Because the Form keeps repainting itself, you have to ensure that the previously drawn stages are continuously shown.
Our game in action:
Figure 2: Game Play
Conclusion
Making games improves your logic tremendously. Although there was not much coding involved, there was still some complicated logic. I hope you have enjoyed today’s article.