dcsimg

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

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


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!



About the Author

Hannes DuPreez

Hannes du Preez is a self-taught developer who started learning to program in the days of QBasic. He has written several articles over the years detailing his programming quests and adventures. .NET is his second love, just after his wife and kid. He has always been an avid supporter of .NET since the beginning and is an expert in VB and C#. He was given the Microsoft Most Valuable Professional Award for .NET (2008–2017). He has worked as a moderator and an article reviewer on online forums and currently works as a C# developer and writes articles for CodeGuru.com, Developer.com, DevX.com, and the Database journal.
His first book Visual Studio 2019 In Depth is currently on sale on Amazon and Bpb Publications.

You could reach him at: ojdupreez1978[at]gmail[dot]com

Related Articles

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date