Creating a Maze Game in .NET, Part 2: Adding Gameplay | CodeGuru

Creating a Maze Game in .NET, Part 2: Adding Gameplay

Continuing with our game, all that is left to do is to add the physical Maze object and enable it to work with the existing Grid and Game classes and add it to the form. In this part, you will create the maze object. If you haven’t completed “Creating a Maze Game in .NET, Part […]

Written By
Hannes DuPreez
Hannes DuPreez
Aug 28, 2019
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Continuing with our game, all that is left to do is to add the physical Maze object and enable it to work with the existing Grid and Game classes and add it to the form. In this part, you will create the maze object. If you haven’t completed “Creating a Maze Game in .NET, Part 1: Structure” yet, please do so before beginning this article.

Let’s jump right in.

Add a new class and name it Maze, for example.

Add the following code for this class:

C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using System.Windows.Forms;
using System.Drawing;

namespace HTG_Maze_VB
{
   class Maze : DataGridView
   {
      private int WM_LBUTTONDOWN = 0x201;
      private int WM_LBUTTONDBLCLK = 0x203;
      private int WM_KEYDOWN = 0x100;

      public Maze()
      {
         this.DoubleBuffered = true;
      }

      private bool blnSolution;

      public bool ShowSolution
      {
         get
         {
            return blnSolution;
         }

         set
         {
            blnSolution = value;
         }

      }


      protected override void OnRowPrePaint(System.Windows.
         .DataGridViewRowPrePaintEventArgs e)
      {
         e.PaintParts = e.PaintParts &
            ~DataGridViewPaintParts.Focus;
         base.OnRowPrePaint(e);
      }

      protected override void OnPaint(System.Windows.Forms
         .PaintEventArgs e)
      {
         base.OnPaint(e);

         if (clsGrid.Cells == null)
            return;

         for (int row = 0; row <= base.Rows.Count - 1; row++)
         {
            for (int col = 0; col <= base.Columns.Count - 1;
               col++)
            {
               int intWidth = 2;
               Pen pRed = new Pen(Color.Red, intWidth);
               Pen pGreen = new Pen(Color.Green, intWidth);
               int intSize = base.Rows[0].Cells[0].Size.Width;

               if (ShowSolution ? Convert.ToBoolean
                     (clsGrid.Solution[col][row]) :
                     Convert.ToBoolean(clsGrid.Cells[col][row]
                    .intNorth > 0))
                  e.Graphics.DrawLine(ShowSolution ? pGreen :
                     pRed, System.Convert.ToInt32(intSize * col +
                     ((intSize - intWidth) / (double)2) + 1),
                     System.Convert.ToInt32(intSize * row),
                     System.Convert.ToInt32(intSize * col +
                     ((intSize - intWidth) / (double)2) + 1),
                     System.Convert.ToInt32(intSize * row +
                    ((intSize - intWidth) / (double)2) + 1));

               if (ShowSolution ? Convert.ToBoolean(clsGrid
                     .Solution[col][row]) : Convert.ToBoolean
                     (clsGrid.Cells[col][row].intSouth > 0))
                  e.Graphics.DrawLine(ShowSolution ? pGreen : pRed,
                     System.Convert.ToInt32(intSize * col +
                     ((intSize - intWidth) / (double)2) + 1),
                     System.Convert.ToInt32(intSize * row +
                     ((intSize - intWidth) / (double)2) + 1),
                     System.Convert.ToInt32(intSize * col +
                     ((intSize - intWidth) / (double)2) + 1),
                     System.Convert.ToInt32(intSize * (row + 1)));

               if (ShowSolution ? Convert.ToBoolean(clsGrid
                     .Solution[col][row]) : Convert.ToBoolean
                     (clsGrid.Cells[col][row].intWest > 0))
                  e.Graphics.DrawLine(ShowSolution ? pGreen : pRed,
                     System.Convert.ToInt32(intSize * col),
                     System.Convert.ToInt32(intSize * row +
                     ((intSize - intWidth) / (double)2) + 1),
                     System.Convert.ToInt32(intSize * col +
                     ((intSize - intWidth) / (double)2) + 1),
                     System.Convert.ToInt32(intSize * row +
                     ((intSize - intWidth) / (double)2) + 1));

               if (ShowSolution ? Convert.ToBoolean(clsGrid
                     .Solution[col][row]) : Convert.ToBoolean
                     (clsGrid.Cells[col][row].intEast > 0))
                  e.Graphics.DrawLine(ShowSolution ? pGreen : pRed,
                     System.Convert.ToInt32(intSize * col +
                     ((intSize - intWidth) / (double)2) - 1),
                     System.Convert.ToInt32(intSize * row +
                     ((intSize - intWidth) / (double)2) + 1),
                     System.Convert.ToInt32(intSize * (col + 1)),
                     System.Convert.ToInt32(intSize * row +
                     ((intSize - intWidth) / (double)2) + 1));
            }
         }
      }

      protected override void WndProc(ref
         System.Windows.Forms.Message m)
      {
         if (m.Msg == WM_KEYDOWN)
         {
            if (ShowSolution)
               return;

            int row = base.CurrentCell.RowIndex;
            int col = base.CurrentCell.ColumnIndex;

            int msgVal = m.WParam.ToInt32();

            switch ((Keys)msgVal)
            {
               case Keys.Up:
                  if (row > 0)
                  {
                     if (clsGrid.Cells[col][row].blnNorth == false)
                     {
                        clsGrid.Cells[col][row].intNorth += 1;
                        clsGrid.Cells[col][row - 1].intSouth += 1;
                        base.CurrentCell =
                           base.Rows[row - 1].Cells[col];
                     }
                  }
                  break;
               case Keys.Down:
                  if (row < base.Rows.Count - 1)
                  {
                     if (clsGrid.Cells[col][row].blnSouth == false)
                     {
                        clsGrid.Cells[col][row].intSouth += 1;
                        clsGrid.Cells[col][row + 1].intNorth += 1;
                        base.CurrentCell =
                           base.Rows[row + 1].Cells[col];
                     }
                  }
                  break;
               case Keys.Left:
                  if (col > 0)
                  {
                     if (clsGrid.Cells[col][row].blnWest == false)
                     {
                        clsGrid.Cells[col][row].intWest += 1;
                        clsGrid.Cells[col - 1][row].intEast += 1;
                        base.CurrentCell =
                           base.Rows[row].Cells[col - 1];
                     }
                  }
                  break;
               case Keys.Right:
                  if (col < base.Columns.Count - 1)
                  {
                     if (clsGrid.Cells[col][row].blnEast == false)
                     {
                        clsGrid.Cells[col][row].intEast += 1;
                        clsGrid.Cells[col + 1][row].intWest += 1;
                        base.CurrentCell =
                           base.Rows[row].Cells[col + 1];
                     }
                  }
                  break;
            }

            base.Refresh();

            return;
         }
         else if (m.Msg == WM_LBUTTONDBLCLK || m.Msg ==
               WM_LBUTTONDOWN)
            return;

         base.WndProc( ref m);
      }
   }
}

VB.NET

Public Class Maze
   Inherits DataGridView

   Dim WM_LBUTTONDOWN As Integer = &H201
   Dim WM_LBUTTONDBLCLK As Integer = &H203
   Dim WM_KEYDOWN As Integer = &H100

   Public Sub New()

      Me.DoubleBuffered = True

   End Sub

   Private blnSolution As Boolean

   Public Property ShowSolution() As Boolean

      Get
         Return blnSolution
      End Get

      Set(ByVal value As Boolean)
         blnSolution = value
      End Set

   End Property


   Protected Overrides Sub OnRowPrePaint(ByVal e As _
         System.Windows.Forms.DataGridViewRowPrePaintEventArgs)

      e.PaintParts = e.PaintParts And Not _
         DataGridViewPaintParts.Focus
      MyBase.OnRowPrePaint(e)

   End Sub

   Protected Overrides Sub OnPaint(ByVal e As _
         System.Windows.Forms.PaintEventArgs)
      MyBase.OnPaint(e)

      If clsGrid.Cells Is Nothing Then Return

      For row As Integer = 0 To MyBase.Rows.Count - 1

         For col As Integer = 0 To MyBase.Columns.Count - 1

            Dim intWidth As Integer = 2
            Dim pRed As New Pen(Color.Red, intWidth)
            Dim pGreen As New Pen(Color.Green, intWidth)
            Dim intSize As Integer = _
               MyBase.Rows(0).Cells(0).Size.Width

            If If(ShowSolution(), clsGrid.Solution(col)(row), _
                  clsGrid.Cells(col)(row)).intNorth > 0 Then
               e.Graphics.DrawLine(If(ShowSolution(), pGreen, _
                  pRed), CInt(intSize * col + ((intSize - _
                  intWidth) / 2) + 1), CInt(intSize * row), _
                  CInt(intSize * col + ((intSize - intWidth) / 2) _
                  + 1), CInt(intSize * row + ((intSize - _
                  intWidth) / 2) + 1))
            End If

            If If(ShowSolution(), clsGrid.Solution(col)(row), _
                  clsGrid.Cells(col)(row)).intSouth > 0 Then
               e.Graphics.DrawLine(If(ShowSolution(), pGreen, _
                  pRed), CInt(intSize * col + ((intSize - _
                  intWidth) / 2) + 1), CInt(intSize * row + _
                  ((intSize - intWidth) / 2) + 1), CInt(intSize * _
                  col + ((intSize - intWidth) / 2) + 1), _
                  CInt(intSize * (row + 1)))
            End If

            If If(ShowSolution(), clsGrid.Solution(col)(row), _
                  clsGrid.Cells(col)(row)).intWest > 0 Then
               e.Graphics.DrawLine(If(ShowSolution(), pGreen, _
                  pRed), CInt(intSize * col), CInt(intSize * row _
                  + ((intSize - intWidth) / 2) + 1), CInt(intSize _
                  * col + ((intSize - intWidth) / 2) + 1), _
                  CInt(intSize * row + ((intSize - intWidth) / 2) _
                  + 1))

            End If

            If If(ShowSolution(), clsGrid.Solution(col)(row), _
                  clsGrid.Cells(col)(row)).intEast > 0 Then
               e.Graphics.DrawLine(If(ShowSolution(), pGreen, _
                  pRed), CInt(intSize * col + ((intSize - _
                  intWidth) / 2) - 1), CInt(intSize * row + _
                  ((intSize - intWidth) / 2) + 1), CInt(intSize * _
                  (col + 1)), CInt(intSize * row + ((intSize - _
                  intWidth) / 2) + 1))
            End If

         Next

      Next

   End Sub

   Protected Overrides Sub WndProc(ByRef m As _
         System.Windows.Forms.Message)

      If m.Msg = WM_KEYDOWN Then

         If ShowSolution Then Return

         Dim row As Integer = MyBase.CurrentCell.RowIndex
         Dim col As Integer = MyBase.CurrentCell.ColumnIndex

         If m.WParam.ToInt32 = Keys.Up Then

            If row > 0 Then
               If clsGrid.Cells(col)(row).blnNorth = False Then
                  clsGrid.Cells(col)(row).intNorth += 1
                  clsGrid.Cells(col)(row - 1).intSouth += 1
                  MyBase.CurrentCell = MyBase.Rows(row - _
                     1).Cells(col)
               End If

            End If

         ElseIf m.WParam.ToInt32 = Keys.Down Then

            If row < MyBase.Rows.Count - 1 Then
               If clsGrid.Cells(col)(row).blnSouth = False Then
                  clsGrid.Cells(col)(row).intSouth += 1
                  clsGrid.Cells(col)(row + 1).intNorth += 1
                  MyBase.CurrentCell = _
                     MyBase.Rows(row + 1).Cells(col)
               End If

            End If
         ElseIf m.WParam.ToInt32 = Keys.Left Then

            If col > 0 Then
               If clsGrid.Cells(col)(row).blnWest = False Then
                  clsGrid.Cells(col)(row).intWest += 1
                  clsGrid.Cells(col - 1)(row).intEast += 1
                  MyBase.CurrentCell = _
                     MyBase.Rows(row).Cells(col - 1)
               End If

            End If

         ElseIf m.WParam.ToInt32 = Keys.Right Then

            If col < MyBase.Columns.Count - 1 Then
               If clsGrid.Cells(col)(row).blnEast = False Then
                  clsGrid.Cells(col)(row).intEast += 1
                  clsGrid.Cells(col + 1)(row).intWest += 1
                  MyBase.CurrentCell = _
                     MyBase.Rows(row).Cells(col + 1)
               End If

            End If

         End If

         MyBase.Refresh()

         Return

      ElseIf m.Msg = WM_LBUTTONDBLCLK OrElse m.Msg = _
            WM_LBUTTONDOWN Then

         Return

      End If

      MyBase.WndProc(m)

   End Sub

End Class

Let’s see what happens here.

You specify the DoubleBuffered property in the class constructor. This prevents flickering when redrawing pictures. You created the ShowSolution property, which will allow you to see the Solution when clicked or play the game when it is not clicked.

You then override the RowPrePaint event which occurs before the DataGridView’s rows are painted, to identify which parts have the focus. The Paint event of the DataGridView is overridden, and this is where the fun happens. We loop through each cell and draw random connecting lines to form a maze.

Lastly, you override WndProc, which is the normal input for a window to intercept the keys that are pressed. This allows us to navigate through the maze in any cardinal direction and keep track of it by drawing a line as we try to navigate through the maze.

Conclusion

We are almost done. We must now add this to a form, and this is what we will do in Part 3. Until then, happy coding!

Hannes DuPreez

Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.