VB.Net - OOP Buttons Guessing Game
Overview
This is a graphical guesstimate game. Each new game a random number of yellow 'Buttons' are drawn on the game grid. The red vertical partition line is also drawn on a random vertical grid line. This partition line isn't moveable. Mouse movement over the blue selection triangles (to the right of the grid) causes a black horizontal partition line to be drawn on the selected horizontal grid line. When mouse hovering over one of the rightmost triangles, some of the yellow 'Buttons' will become black 'Buttons' and some will become red 'Buttons'. Clicking on one of the rightmost triangles selects the current amounts of red 'Buttons' and black 'Buttons'. The aim of the game is to estimate which of the triangles you must click on to select more black 'Buttons' than red 'Buttons'. The real skill in the game is not only to win, but also to win by the narrowest margin possible...
This is an application developed using standard OOP techniques, namely encapsulation and custom events. The game core is entirely encapsulated within an extended Panel, where the GDI+ graphical elements are rendered on to the panel. Standard Panel events are used to detect mouse movement and clicks. Two custom events send feedback to the Form when the game is ended, one to enable the New Game button, and the other to provide the result String which is then displayed in a Label.
The GamePanel Class
The line of code - Dim
rightTriangles ``As
New
List(Of GraphicsPath) defines a List ``Of GraphicsPath. These are the locations of the triangles to the right of the grid, which are set in the first iteration of the Paint event and used in the Panel MouseMove and Panel ``MouseDown events...
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms
Public Class GamePanel
Inherits Panel
'custom events
Public Event enableNewButton()
Public Event showScoreLine(scoreLine As String)
'graphical elements, stored as GraphicsPaths
'for use with mouse movement And clicks
Dim topTriangles As New List(Of GraphicsPath)
Dim rightTriangles As New List(Of GraphicsPath)
'game play variables
Dim topIndex As Integer = -1
Dim rightIndex As Integer = -1
Dim oldRightIndex As Integer = -1
'used for storing locations of random graphical buttons
Dim buttons As New List(Of Point)
Dim r As New Random
Dim locked As Boolean = False
Public Sub New()
Me.Size = New Size(570, 570)
Me.DoubleBuffered = True
newGame()
End Sub
''' <summary>
''' Randomly places a random amount of buttons in random positions
''' Randomly positions the vertical divider line
''' </summary>
Public Sub newGame()
rightIndex = -1
locked = False
buttons = New List(Of Point)
Dim n As Integer = r.Next(500, 1001)
For c As Integer = 1 To n
Dim x As Integer = r.Next(0, 37)
Dim y As Integer = r.Next(0, 37)
If Not buttons.Contains(New Point(x, y)) Then
buttons.Add(New Point(x, y))
Else
c -= 1
End If
Next
Dim buttonCounts() As Integer = Enumerable.Range(15, 7).Select(Function(x) buttons.Where(Function(p) p.X < x And p.Y < 17).Count + buttons.Where(Function(p) p.X > x And p.Y > 17).Count).ToArray
topIndex = 15 + Array.IndexOf(buttonCounts, buttonCounts.Max)
Me.Invalidate()
End Sub
''' <summary>
''' Detects clicking on the triangles to the right of the grid
''' Locks the game and calls the Paint event.
''' </summary>
''' <param name="e"></param>
Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
If e.Button = MouseButtons.Left Then
If rightTriangles.FindIndex(Function(gp) gp.IsVisible(e.X, e.Y)) <> -1 Then
locked = True
RaiseEvent enableNewButton()
Me.Cursor = Cursors.Default
Me.Invalidate()
End If
End If
MyBase.OnMouseDown(e)
End Sub
''' <summary>
''' Detects movement on the triangles to the right of the grid
''' causing different amounts of buttons to be rendered red and black
''' depending on their position relative to the partition lines
''' </summary>
''' <param name="e"></param>
Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
'topIndex = topTriangles.FindIndex(Function(gp) gp.IsVisible(e.X, e.Y))
If Not locked Then
rightIndex = rightTriangles.FindIndex(Function(gp) gp.IsVisible(e.X, e.Y))
If rightIndex <> -1 Then
Me.Cursor = Cursors.Hand
Else
Me.Cursor = Cursors.Default
End If
If rightIndex <> oldRightIndex Then
Me.Invalidate()
End If
End If
MyBase.OnMouseMove(e)
End Sub
''' <summary>
''' The paint event dynamically renders the panel
''' drawing both the fixed elements and the dynamic user defined parts
''' </summary>
''' <param name="e"></param>
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
'the grid is drawn in these two for, next loops
For x As Integer = 15 To 555 Step 15
e.Graphics.DrawLine(Pens.LightGray, x, 15, x, 555)
Next
For y As Integer = 15 To 555 Step 15
e.Graphics.DrawLine(Pens.LightGray, 15, y, 555, y)
Next
'the buttons are drawn on the grid in one of the three colours
'and documented as they are drawn
Dim buttonCounts(buttons.Count - 1) As String
For x As Integer = 0 To buttons.Count - 1
e.Graphics.FillEllipse(If(rightIndex = -1, Brushes.Yellow, If((buttons(x).X < (topIndex + 1) And buttons(x).Y < (rightIndex + 1)) Or (buttons(x).X > (topIndex + 1) And buttons(x).Y > (rightIndex + 1)), Brushes.Red, If((buttons(x).X > (topIndex + 1) And buttons(x).Y < (rightIndex + 1)) Or (buttons(x).X < (topIndex + 1) And buttons(x).Y > (rightIndex + 1)), Brushes.Black, Brushes.Yellow))), New Rectangle(((buttons(x).X + 1) * 15) - 5, ((buttons(x).Y + 1) * 15) - 5, 10, 10))
buttonCounts(x) = If(rightIndex = -1, "g", If((buttons(x).X < (topIndex + 1) And buttons(x).Y < (rightIndex + 1)) Or (buttons(x).X > (topIndex + 1) And buttons(x).Y > (rightIndex + 1)), "r", If((buttons(x).X > (topIndex + 1) And buttons(x).Y < (rightIndex + 1)) Or (buttons(x).X < (topIndex + 1) And buttons(x).Y > (rightIndex + 1)), "b", "g")))
Next
'these two for, next loops draws the triangles above and to the right of the grid
Dim triangle1() As Point = {New Point(0, 0), New Point(15, 0), New Point(8, 10), New Point(0, 0)}
For x As Integer = 30 To 540 Step 15
e.Graphics.FillPolygon(Brushes.SteelBlue, Array.ConvertAll(triangle1, Function(p) New Point(p.X + x - 8, p.Y + 5)))
If topTriangles.Count < 35 Then
Dim gp As New GraphicsPath
gp.AddPolygon(Array.ConvertAll(triangle1, Function(p) New Point(p.X + x - 8, p.Y + 5)))
topTriangles.Add(gp)
End If
Next
Dim triangle2() As Point = {New Point(0, 8), New Point(10, 0), New Point(10, 15), New Point(0, 8)}
For y As Integer = 30 To 540 Step 15
e.Graphics.FillPolygon(Brushes.SteelBlue, Array.ConvertAll(triangle2, Function(p) New Point(p.X + 555, p.Y + y - 8)))
If rightTriangles.Count < 35 Then
Dim gp As New GraphicsPath
gp.AddPolygon(Array.ConvertAll(triangle2, Function(p) New Point(p.X + 555, p.Y + y - 8)))
rightTriangles.Add(gp)
End If
Next
'this draws the vertical partition line
If topIndex <> -1 Then
Dim x As Integer = CInt(topTriangles(topIndex).GetLastPoint.X)
e.Graphics.DrawLine(Pens.Red, x, 15, x, 555)
End If
'this draws the changeable horizontal selecting partition line
If rightIndex <> -1 Then
Dim y As Integer = CInt(rightTriangles(rightIndex).PathPoints(0).Y)
e.Graphics.DrawLine(Pens.Black, 15, y, 555, y)
'if game over...
If locked Then
Dim red As Integer = buttonCounts.Count(Function(s) s = "r")
Dim black As Integer = buttonCounts.Count(Function(s) s = "b")
RaiseEvent showScoreLine(String.Format("Red: {0}, Black: {1}. You " & If(red > black, "lose", If(red = black, "draw", "win")), red, black))
End If
End If
MyBase.OnPaint(e)
End Sub
End Class
Conclusion
This is another example that shows VB.Net and GDI+ are a good choice of technologies when writing this sort of desktop game...
Other Resources
C# TechNet version
Download here (VB.NET and C#)
Articles related to game programming
VB.Net - WordSearch
VB.Net - Vertex
VB.Net - Perspective
VB.Net - MasterMind
VB.Net - OOP BlackJack
VB.Net - Numbers Game
VB.Net - HangMan
Console BlackJack - VB.Net | C#
TicTacToe - VB.Net | C#
OOP Sudoku - VB.Net | C#
OctoWords VB.Net | C#
OOP Tangram Shapes Game VB.Net | C#
VB.Net - Three-card Monte
VB.Net - Split Decisions
VB.Net - Pascal's Pyramid
VB.Net - Random Maze Games
(Office) Wordsearch Creator
VB.Net - Event Driven Programming - LockWords Game
C# - Crack the Lock
VB.Net - Totris