Memory matching games are fun projects that serve as an excellent entry point into the world of game development and user interface programming. They not only test the player's memory but also the developer's skills in handling logic, state management, and timing. In this detailed guide, we will dive deep into creating a dynamic and engaging icon-matching game from scratch using C# and Windows Forms, focusing on fundamental techniques like reference variables and Timers.
The game's objective is simple: the player is presented with a board full of hidden icons and must click on two squares at a time to reveal a pair of icons. If the icons match, they remain visible. If they are different, they will be hidden again after a short period.
Through this project, you will gain practical experience in:
To get started, you will need the Visual Studio development environment with the .NET desktop development workload installed.
The core of a memory game is its ability to "remember" the first card the player selected while they search for the second. We cannot achieve this with local variables inside the click function because they lose their value once the function ends. This is where class-level reference variables come into play.
We will define two reference variables of type Label
within our main Form1
class. These variables will hold a reference to the controls that have been clicked.
public partial class Form1 : Form { // Reference variable to store the first clicked icon Label firstClicked = null; // Reference variable to store the second clicked icon Label secondClicked = null; public Form1() { InitializeComponent(); } }
When a variable's value is null
, it signifies that no icon is currently selected. This is their initial state when the game starts.
Now, let's modify the Click Event Handler
for our icons. Instead of creating a separate event handler for each icon, you can link all icons to the same handler to promote code reuse.
private void label_Click(object sender, EventArgs e) { // If the timer is running, ignore any other clicks if (timer1.Enabled == true) return; Label clickedLabel = sender as Label; if (clickedLabel != null) { // Ignore the click if the label is already visible (black) if (clickedLabel.ForeColor == Color.Black) return; // If this is the first click if (firstClicked == null) { firstClicked = clickedLabel; firstClicked.ForeColor = Color.Black; // Show the icon return; } // If the code reaches here, this is the second click secondClicked = clickedLabel; secondClicked.ForeColor = Color.Black; // Check for a winner after a successful match CheckForWinner(); // Check if the two icons match if (firstClicked.Text == secondClicked.Text) { // Correct match, reset the variables without hiding the icons firstClicked = null; secondClicked = null; return; } // If the icons don't match, start the timer to hide them timer1.Start(); } }
In this code, we use sender as Label
to safely cast the object that raised the event (a Label
in our case) to the correct type. This method is safer than a direct cast. For more details on handling events in .NET, you can review the official Microsoft documentation on events.
The player needs a moment to see the second icon and remember its location before it disappears if it's not a match. This short delay is what makes the game possible and enjoyable. We will use the Timer
component from the Windows Forms Toolbox to achieve this.
Timer
component from the Toolbox
and drop it onto your form.Interval
property to 750
(this represents 750 milliseconds).Enabled
property is set to False
by default, as we only want the timer to run when we need it.Now, double-click timer1
to create its Tick
event handler. This event fires every time the specified interval is completed.
private void timer1_Tick(object sender, EventArgs e) { // Stop the timer immediately so it doesn't run again unexpectedly timer1.Stop(); // Hide the two icons by making their color the same as the background firstClicked.ForeColor = firstClicked.BackColor; secondClicked.ForeColor = secondClicked.BackColor; // Reset the reference variables for the next turn firstClicked = null; secondClicked = null; }
The Timer
component is a powerful tool for executing scheduled tasks in UI applications. You can explore more of its advanced properties on the System.Windows.Forms.Timer Class page on Microsoft Learn.
After every successful match, we must check if the player has uncovered all matching pairs. If so, they have won the game. We will create a separate method for this purpose to keep our code clean.
This method will loop through all controls inside the TableLayoutPanel
(or whatever container you are using) and check the foreground color of each Label
. If any Label
's color is not black, it means the game is not over yet.
private void CheckForWinner() { // Loop through all the controls on the TableLayoutPanel foreach (Control control in tableLayoutPanel1.Controls) { // Ensure the control is a Label Label iconLabel = control as Label; if (iconLabel != null) { // If we find any icon that is still hidden, exit the method if (iconLabel.ForeColor != Color.Black) return; } } // If the loop completes, all icons are matched MessageBox.Show("You matched all the icons successfully!", "Congratulations!"); Close(); // Close the form to end the game }
Notice that we call CheckForWinner()
inside the label_Click
event handler right after the player selects the second icon. This ensures a check is performed after every potential winning move.
Now that you have the basic game structure, you can add many features to make it more challenging and appealing:
Webdings
font, you can use actual pictures by setting the Image
property of each Label
.Timer
that runs for the entire duration of the game to calculate how long it takes the player to win, and display it in a status bar.TableLayoutPanel
(e.g., to 6x6) and add more icons.For information on how to use different controls like the Label
, you can refer to the Label Control guide for Windows Forms.
You have successfully built a fully functional memory matching game using C# and Windows Forms. More importantly, you have learned fundamental programming concepts like state management with reference variables, event flow control, and using timers for temporal interaction. This project is an excellent starting point for more complex projects and gives you a solid foundation to continue your journey in the world of software development with C#. Feel free to experiment and expand on this small project to turn it into a polished and complete game.