One of the first projects that someone new to programming often wants to do is a game. Often times they want to do something they have seen on their consoles or mega computer games without realizing how much work actually goes into designing and implementing a game of that scope. After reading a book about programming they realize how tough those games are and that games of that scope usually involve dozens of programmers as well as designers, writers, production and marketing people as well. But does that mean you have to learn boring “Hello World” programs for the rest of your career? Certainly not. We will show you how to get started with learning how to build a simple game that can also be fun and teach you a few programming principles along the way. We will create a small instance of the game “Memory” in VB.NET. It is visual and not too complicated, but fun and can be expanded to include even more features.
The game of Memory (also known as Concentration), for those who have not heard of it before, is a game where the player is presented with several playing cards all face down and randomly mixed up. The player must then choose 2 cards (traditionally) and flip them over to see if they match. If they match, they are left face up and the player chooses another set to make a match. If the cards do not match, the player attempts to remember what they look like before flipping them face down again. The game is over when all the cards have been matched and thus are face up. How fast can you make all the matches?
To start off building this game we are going to identify some major components of the game mechanics. These include:
First we will need to setup our lists of pictureboxes and other private variables to keep track of cards, matches, selected cards etc.
Private Choices As New List(Of PictureBox) Private Cards As New List(Of PictureBox) Private Matches As New List(Of Integer) Private CopiesOfCard As Integer
The second part is setting up the new game. Again we are going to clear any of our lists, setup a new list of card images and randomize them using a shuffle algorithm. We then display them to screen. The key part of this code to focus on is the loop. Each card we are going to represent as a picturebox. We create a list of pictureboxes, set their image to the face down image, tag them with the type of card they are (so we can easily compare cards later to see if they match) and lastly attach an event to them for when the user clicks the picturebox to flip it over.
Private Sub SetupCards(howManyCardTypes As Integer, numberOfCopiesPerCard As Integer) ' Start by calculating the number of cards that will be displayed. This is number of card variations times copies per card. ' Resize our cards array to fit all these cards. CopiesOfCard = numberOfCopiesPerCard ' Clear any existing game data ClearGame() ' Image list index keeps track of which card we are working with from the image list control Dim imageListIndex As Integer = 0 ' Fill our cards picturebox list making sure to put in the appropriate copies of each card ' We then step that many copies on each iteration of outer loop. e.g. If we have three copies, we start at zero index and skip to 3 index on next iteration. Dim length As Integer = numberOfCopiesPerCard * howManyCardTypes For i As Integer = 0 To length - 1 Step numberOfCopiesPerCard ' Makes copies of each card and tag each card with the index from the image list For j As Integer = 1 To numberOfCopiesPerCard Dim picCard As PictureBox = New PictureBox() picCard.Image = imgListCards.Images(imgListCards.Images.Count - 1) picCard.Tag = imageListIndex AddHandler picCard.Click, AddressOf Me.cardflip_click Cards.Add(picCard) Next imageListIndex += 1 Next ' We call to shuffle the cards Shuffle(Cards) ' Then display the cards with 5 per line DisplayCards(5) End Sub
We built in some functionality to this method so that we can customize the game. We can specify how many copies of each card are going to be on the board (and thus the number of cards the player will need to click to make a match) and how many card types we will use. So calling SetupGame(5,3) is going to say we have 5 card types and each will have 3 copies on the board. The player then has to click 3 cards to make a match.
The third step will be the event for when someone clicks a card. We have to evaluate if a match has occurred, if that card has already been found as a match and set the image of the picturebox based on the stored “tag”. The tag itself is an integer that represents the card type like 0 = Ace and 1 = King etc. We use this integer to then find the number as an index for the image list control and set the image of the picturebox. Then we clean up our lists (or add to lists) as needed depending on if a match was made or not.
''' <summary> ''' Event for showing a card and evaluating it for matches. ''' </summary> ''' <param name="sender">Presumably the picturebox card that was clicked.</param> ''' <param name="e">Eventargs</param> Private Sub cardflip_click(sender As Object, e As EventArgs) Dim picture As PictureBox = CType(sender, PictureBox) Dim idTag As Integer = CType(picture.Tag, Integer) If Not Choices.Contains(picture) And Not Matches.Contains(idTag) Then Choices.Add(picture) ShowCard(picture) If Choices.Count = CopiesOfCard Then If ChoicesMatch() Then statusLabel.Text = "You found a match!" Matches.Add(idTag) Else statusLabel.Text = "No match, sorry!" Threading.Thread.Sleep(1000) ' Hide the choices the user made For i As Integer = 0 To Choices.Count - 1 HideCard(Choices(i)) Next End If ' Clear the choices (match or no match) Choices.Clear() End If End If End Sub
In the code above you might be wondering what the thread sleep is all about. Well, to prevent the game from hiding the cards immediately after determining no match was made, we pause the game for a second and then proceed with flipping them back over. If you wanted to make this more or less challenging, you could reduce/increase the time the player has to look at the card. Once the time expires we go about covering up all the chosen cards.
Next comes our small support helper functions. Ones to hide or show a card, to clear the game lists (used during a new game setup), shuffle the cards and determine if a match happens. For shuffling we will use the Fisher-Yates algorithm and determining a match is just looping through the chosen cards and seeing if all the tags match. If they don’t match at any point we know they don’t have all matches.
''' <summary> ''' ClearGame handles clearing the cards, choices and board. ''' </summary> Private Sub ClearGame() If Cards.Count > 0 Then For i As Integer = 0 To Cards.Count - 1 Me.Controls.Remove(Cards(i)) Next End If ' Clear the cards if they were already setup from a previous game. Cards.Clear() Choices.Clear() Matches.Clear() End Sub ''' <summary> ''' Checks to make sure that all chosen items match successfully ''' </summary> ''' <returns>True or False</returns> Private Function ChoicesMatch() As Boolean For i As Integer = 1 To Choices.Count - 1 Dim c1 As Integer = CType(Choices(i - 1).Tag, Integer) Dim c2 As Integer = CType(Choices(i).Tag, Integer) If c1 <> c2 Then Return False End If Next Return True End Function Private Sub ShowCard(card As PictureBox) card.Image = imgListCards.Images(Convert.ToInt32(card.Tag)) Me.Refresh() End Sub Private Sub HideCard(card As PictureBox) card.Image = imgListCards.Images(imgListCards.Images.Count - 1) End Sub ''' <summary> ''' Shuffles picturebox controls around randomly using the Fisher-Yates algorithm ''' </summary> ''' <param name="cards">Array of PictureBox Controls to shuffle</param> Private Sub Shuffle(ByRef cards As List(Of PictureBox)) Dim r As Random = New Random() For i = 0 To cards.Count - 1 Dim index As Integer = r.Next(i, cards.Count) ' Do a simple swap here If i <> index Then Dim temp As PictureBox = cards(i) cards(i) = cards(index) cards(index) = temp End If Next End Sub ''' <summary> ''' Display the cards to the screen, broken into number of cards per line. ''' </summary> ''' <param name="cardsPerLine">The number of cards to have per line</param> ''' <remarks>Cards per line should be greater than zero.</remarks> Private Sub DisplayCards(cardsPerLine As Integer) Dim startX As Integer = 15 Dim startY As Integer = 50 For i As Integer = 0 To Cards.Count - 1 Cards(i).Top = startY Cards(i).Left = startX Cards(i).Size = New System.Drawing.Size(100, 146) Me.Controls.Add(Cards(i)) Cards(i).Visible = True startX = startX + 120 If (i + 1) Mod cardsPerLine = 0 Then startX = 15 startY = startY + 166 End If Next End Sub
Another major piece here is the displaying of the cards. We need to loop through the cards and place them onto the form at a specified width/height and at a specified X/Y coordinate. For a bit of extra added functionality, we take in a parameter that determines how many cards we should display on a given row. By default above we give it 5 so there are 5 cards on each row but you can really specify any number given that it is greater than 1 and less than the number of cards we have in this run of the game.
''' <summary> ''' Event for showing a card and evaluating it for matches. ''' </summary> ''' <param name="sender">Presumably the picturebox card that was clicked.</param> ''' <param name="e">Eventargs</param> Private Sub cardflip_click(sender As Object, e As EventArgs) Dim picture As PictureBox = CType(sender, PictureBox) Dim idTag As Integer = CType(picture.Tag, Integer) If Not Choices.Contains(picture) And Not Matches.Contains(idTag) Then Choices.Add(picture) ShowCard(picture) If Choices.Count = CopiesOfCard Then If ChoicesMatch() Then statusLabel.Text = "You found a match!" Matches.Add(idTag) Else statusLabel.Text = "No match, sorry!" Threading.Thread.Sleep(1000) ' Hide the choices the user made For i As Integer = 0 To Choices.Count - 1 HideCard(Choices(i)) Next End If ' Clear the choices (match or no match) Choices.Clear() End If End If End Sub
The last thing we need to do is have a mechanism to select a game setup. We did this using a few menu choices in a menustrip. In the menu we provided two game types. One game requires 2 matches and the other requires 3 game matches.
' Menu toolstrip items for configuring the game in different ways and for exiting Private Sub TwoMatchesToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles TwoMatchesToolStripMenuItem.Click SetupCards(5, 2) End Sub Private Sub ThreeMatchesToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles ThreeMatchesToolStripMenuItem.Click SetupCards(5, 3) End Sub
To give you some screenshots of how this game looks (along with some assets you can use for your game) see the images and links below.
Click here to download the images I used for the demo above.
You don’t have to have a ton of knowledge to create games or even a whole team working for years to develop a game that people would like. With a little ingenuity, and time, you can create classic games that can turn into something that thousands of people will love. Some ideas you could use to expand this game would be to play someone online where the winner is the one with the most matches, you could add in some card flipping animation or even allow the player to select their own card themes.
All the code in this blog is in the public domain and feel free to steal what you want and implement it in your own game projects. Thanks for reading! 🙂