End Sub
Дважды щёлкаем по команде New Game для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.3. Метод-обработчик выбора команды.
Private Sub NewGameToolStripMenuItem_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles NewGameToolStripMenuItem.Click
StartNewGame()
End Sub
Дважды щёлкаем по команде Pause для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.4. Метод-обработчик выбора команды.
Private Sub PauseToolStripMenuItem_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles PauseToolStripMenuItem.Click
Me.Pause()
End Sub
Дважды щёлкаем по команде Restart для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.5. Метод-обработчик выбора команды.
Private Sub RestartToolStripMenuItem_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles RestartToolStripMenuItem.Click
Restart()
End Sub
Дважды щёлкаем по команде Options для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.6. Метод-обработчик выбора команды.
Private Sub OptionsToolStripMenuItem_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles OptionsToolStripMenuItem.Click
Dim optionsForm As New Form2
optionsForm.ShowDialog()
End Sub
Дважды щёлкаем по команде Exit для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.7. Метод-обработчик выбора команды.
Private Sub ExitToolStripMenuItem_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles ExitToolStripMenuItem.Click
Me.EndGame()
End Sub
Дважды щёлкаем по элементу управления PictureBox с рисунком new.bmp (или в панели Properties для этого элемента на вкладке Events дважды щёлкаем по имени события Click). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.8. Метод-обработчик щелчка по элементу.
Private Sub newGame_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles newGame.Click
StartNewGame()
End Sub
Дважды щёлкаем по элементу управления PictureBox с рисунком exit.bmp (или в панели Properties для этого элемента на вкладке Events дважды щёлкаем по имени события Click). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.9. Метод-обработчик щелчка по элементу.
Private Sub exitGame_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles exitGame.Click
EndGame()
End Sub
Дважды щёлкаем по элементу управления PictureBox с рисунком options.bmp (или в панели Properties для этого элемента на вкладке Events дважды щёлкаем по имени события Click). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.10. Метод-обработчик щелчка по элементу.
Private Sub options_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles options.Click
ShowOptions()
End Sub
Для управления игрой мышью, в панели Properties (для формы Form1) на вкладке Events дважды щёлкаем по имени события MouseDown. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.11. Метод-обработчик нажатия кнопки мыши.
Private Sub Form1_MouseDown(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles MyBase.MouseDown
mouseOffset = New Point(-e.X, -e.Y)
End Sub
Для управления игрой мышью, в панели Properties (для формы Form1) на вкладке Events дважды щёлкаем по имени события MouseMove. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.12. Метод-обработчик перемещения мыши.
Private Sub Form1_MouseMove(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles MyBase.MouseMove
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mousePos As Point = Control.MousePosition
mousePos.Offset(mouseOffset.X, mouseOffset.Y)
Location = mousePos
End If
End Sub
Для управления игрой клавишами клавиатуры, в панели Properties (для формы Form1) на вкладке Events дважды щёлкаем по имени события KeyPress. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.13. Метод-обработчик нажатия клавиши.
Private Sub Form1_KeyPress(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles MyBase.KeyPress
Select Case e.KeyChar
Case "p"c, "P"c
If paused Then
Restart()
Else
Pause()
End If
Case "m"c, "M"c
If Me.FormBorderStyle = _
Windows.Forms.FormBorderStyle.Fixed3D Then
Me.FormBorderStyle = _
Windows.Forms.FormBorderStyle.None
Me.Menu = Nothing
Else
Me.FormBorderStyle = _
Windows.Forms.FormBorderStyle.Fixed3D
'Me.Menu = Me.MainMenu1
End If
Case Else
' Do nothing.
End Select
End Sub
Чтобы программа периодически через Interval времени дополняла поле игры новыми разноцветными кругами (взамен выбитых игроком кругов), ниже формы дважды щёлкаем по значку для первого таймера Timer1 (или в панели Properties для этого компонента на вкладке Events дважды щёлкаем по имени события Tick). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.14. Метод, вызываемый через Interval времени.
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
' Add another row to the grid and update the screen.
matrix.AddRow()
matrix.Draw(Me.PictureBox1.CreateGraphics(), _
Me.PictureBox1.BackColor)
End Sub
Чтобы в верхней части формы (на синей полоске для свойства Text) после начала игры шел отсчёт времени (Time), ниже формы дважды щёлкаем по значку для второго таймера Timer2 (или в панели Properties для этого компонента на вкладке Events дважды щёлкаем по имени события Tick). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.
Листинг 20.15. Метод, вызываемый через Interval времени.
'Счётчик секунд, который обнуляем в начале каждой игры
'в методе StartNewGame:
Dim secondCounter As Integer
'Время окончания игры:
Dim EndGameTime As Integer = 60
Private Sub Timer2_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer2.Tick
secondCounter = secondCounter + 1
Me.Text = "Time : " & secondCounter.ToString()
'Мелодия окончания игры:
If secondCounter = EndGameTime Then
My.Computer.Audio.Play( _
"..\..\Resources\win.wav", _
AudioPlayMode.Background)
End If
End Sub
Схема записи и вывода справочной информации, например, с правилами игры после выбора команды Contents (для элемента управления MenuStrip) и после выбора других команд уже приводилась в наших предыдущих работах.
Мы закончили написание программы в главный класс Form1 (для формы Form1 с пользовательским интерфейсом игры).
Теперь в наш проект добавляем новые файлы (для программирования соответствующих игровых действий). Добавить в проект файл можно по двум вариантам.
По первому варианту, добавляем в проект нужный файл по обычной схеме: в панели Solution Explorer выполняем правый щелчок по имени проекта, в контекстном меню выбираем Add, Existing Item, в панели Add Existing Item в окне Files of type выбираем All Files, в центральном окне находим (например, в папке компьютера файл, скопированный из Интернета), выделяем имя этого файла и щёлкаем кнопку Add (или дважды щёлкаем по имени этого файла).
По второму варианту, в панели Solution Explorer выполняем правый щелчок по имени проекта и в контекстном меню выбираем Add, New Item, в панели Add New Item выделяем шаблон Code File, в окне Name записываем имя Block.vb и щёлкаем кнопку Add. В проект (и в панель Solution Explorer) добавляется этот файл, открывается пустое окно редактирования кода, в которое записываем код со следующего листинга.
Листинг 20.16. Новый файл.
Imports System.Drawing.Drawing2D
'''
''' This class represents one of the balls in the game grid.
'''
'''
Public Class Block
Public Const BlockSize As Integer = 25
Private colorValue As Color
Private deletionValue As Boolean = False
Private Shared rand As New Random
Public Property Color() As Color
Get
Return colorValue
End Get
Set(ByVal Value As Color)
colorValue = Value
End Set
End Property
Public Property MarkedForDeletion() As Boolean
Get
Return deletionValue
End Get
Set(ByVal Value As Boolean)
deletionValue = Value
End Set
End Property
Public Sub New(ByVal newColor As Color)
colorValue = newColor
End Sub
Public Sub New(ByVal colors() As Color)
Dim ncolors As Integer = colors.Length
Dim pickedColor As Integer
pickedColor = rand.Next(0, ncolors)
colorValue = colors(pickedColor)
End Sub
Public Sub Draw(ByVal graphics As Graphics, ByVal point As Point)
Dim brush As System.Drawing.Drawing2D.LinearGradientBrush = _
CreateTheBrush(point)
DrawTheCircle(graphics, brush, point)
End Sub
Private Sub DrawTheCircle(ByVal graphics As Graphics, _
ByVal brush As LinearGradientBrush, ByVal location As Point)
Dim topleft As Point = location
Dim bottomright As Point = New Point(location.X + _
BlockSize, location.Y + BlockSize)
Dim transTopLeft As Point = PointTranslator.TranslateToBL( _
topleft)
Dim transBottomRight As Point = _
PointTranslator.TranslateToBL(bottomright)
Dim transwidth As Integer = transBottomRight.X transTopLeft.X
Dim transheight As Integer = _
transBottomRight.Y transTopLeft.Y
graphics.FillEllipse(brush, New Rectangle(transTopLeft, _
New Size(transwidth, transheight)))
End Sub
Private Function CreateTheBrush(ByVal location As Point) As _
LinearGradientBrush
Dim transLocation As Point = _
PointTranslator.TranslateToBL(location)
Dim brushpt1 As Point = transLocation
Dim brushpt2 As New Point(transLocation.X + Block.BlockSize _
+ 4, transLocation.Y BlockSize 4)
Dim brush As New LinearGradientBrush(brushpt1, _
brushpt2, Me.Color, System.Drawing.Color.White)
Return brush
End Function
End Class
По второму варианту, в панели Solution Explorer выполняем правый щелчок по имени проекта и в контекстном меню выбираем Add, New Item, в панели Add New Item выделяем шаблон Code File, в окне Name записываем имя Grid.vb и щёлкаем кнопку Add. В проект (и в панель Solution Explorer) добавляется этот файл, открывается пустое окно редактирования кода, в которое записываем код со следующего листинга.
Листинг 20.17. Новый файл.
'''
''' This class represents the grid of blocks. It handles most of
''' the game play.
'''
'''
Public Class Grid
' The grids is 12 columns and 15 rows of Block objects.
Dim matrix(11, 14) As Block
'''
''' Creates a few rows of blocks to start the game.
''' Game starts with Red, Blue, and Green blocks.
'''
''' Number of rows of blocks to create
''' to start the game.
'''
Public Sub New(ByVal nrows As Integer)
If nrows > matrix.GetLength(0) Then
Throw New Exception("Must start with " & _
matrix.GetLength(0) & " or fewer rows.")
End If
Dim row As Integer
Dim column As Integer
For row = 0 To nrows 1
For column = 0 To matrix.GetLength(1) 1
matrix(row, column) = New Block( _
New Color() {Color.Red, Color.Blue, Color.Green})
Next
Next
For row = nrows To matrix.GetLength(0) 1
For column = 0 To matrix.GetLength(1) 1
matrix(row, column) = Nothing
Next
Next
End Sub
'''
''' A new row may be added at any time. New rows have Gray
''' blocks in addition
''' to Red, Blue, and Green. This makes the game more difficult.
'''
'''
Public Sub AddRow()
Dim column As Integer
' Add a new block to each column.
For column = 0 To matrix.GetLength(1) 1
Dim newBlock As New Block(New Color() _
{Color.Red, Color.Blue, Color.Green, Color.Gray})
' Add the new block at the botttom of the column,
' and push the rest of the
' blocks up one column.
For row As Integer = matrix.GetLength(0) 1 To 1 Step -1
matrix(row, column) = matrix(row 1, column)
Next
matrix(0, column) = newBlock
Next
End Sub
'''
''' Draw the grid of blocks
'''
'''
'''
'''
Public Sub Draw(ByVal graphics As Graphics, _
ByVal backColor As Color)
graphics.Clear(backColor)
Dim row As Integer
Dim column As Integer
Dim theBlock As Block
For row = 0 To matrix.GetLength(0) 1
For column = 0 To matrix.GetLength(1) 1
theBlock = matrix(row, column)
If Not theBlock Is Nothing Then
Dim pointA As New Point( _
column * Block.BlockSize, _
row * Block.BlockSize)
matrix(row, column).Draw(graphics, pointA)
End If
Next
Next
End Sub
'''
''' This method responds to a click event in the UI.
'''
'''
'''
'''
Public Function Click(ByVal point As Point) As Integer
' Figure out row and column.
Dim total As Integer
Dim transPt As Point = PointTranslator.TranslateToTL(point)
Dim selectedRow As Integer = transPt.Y \ Block.BlockSize
Dim selectedColumn As Integer = transPt.X \ Block.BlockSize
Dim selectedBlock As Block = matrix(selectedRow, _
selectedColumn)
If Not selectedBlock Is Nothing Then
selectedBlock.MarkedForDeletion = True
' Determine if any of the neighboring blocks are
' the same color.
FindSameColorNeighbors(selectedRow, selectedColumn)
' Determine how many blocks would be eliminated.
total = Me.CalculateScore()
If total > 1 Then
Me.CollapseBlocks()
Else
Me.ClearMarkedForDeletion()
End If
End If
Return total
End Function
Private Sub ClearMarkedForDeletion()
Dim row As Integer
Dim column As Integer
For column = matrix.GetLength(1) 1 To 0 Step -1
' If column is completely empty, then move everthing
' down one.
For row = 0 To matrix.GetLength(0) 1
If Not matrix(row, column) Is Nothing Then
matrix(row, column).MarkedForDeletion = False
End If
Next
Next
End Sub
'''
''' Find out how many blocks will be eliminated.
'''
'''
'''
Private Function CalculateScore() As Integer
Dim row As Integer
Dim column As Integer
Dim total As Integer = 0
For column = matrix.GetLength(1) 1 To 0 Step -1
' If column is completely empty, then move everthing
' down one.
For row = 0 To matrix.GetLength(0) 1
If Not matrix(row, column) Is Nothing Then
If matrix(row, column).MarkedForDeletion Then
total += 1
End If
End If
Next
Next
Return total
End Function
'''
''' After the blocks are removed from the columns, there may be
''' columns that are empty. Move columns from right to left to
''' fill in the empty columns.
'''
'''
Public Sub CollapseColumns()
Dim row As Integer
Dim column As Integer
For column = matrix.GetLength(1) 1 To 0 Step -1
' If column is completely empty, then all the columns
' over one.
Dim noBlocks As Boolean = True
For row = 0 To matrix.GetLength(0) 1
If Not matrix(row, column) Is Nothing Then
noBlocks = False
End If
Next
If noBlocks Then
Dim newcol As Integer
For newcol = column To matrix.GetLength(1) 2
For row = 0 To matrix.GetLength(0) 1
matrix(row, newcol) = matrix(row, newcol + 1)
Next
Next
newcol = matrix.GetLength(1) 1
For row = 0 To matrix.GetLength(0) 1
matrix(row, newcol) = Nothing
Next
End If
Next
End Sub
'''
''' Remove all the blocks from the grid.
'''
'''
Public Sub CollapseBlocks()
Dim theBlock As Block
Dim column As Integer
Dim row As Integer
Dim aRow As Integer
' First remove the blocks from each column.
For column = 0 To matrix.GetLength(1) 1
For row = matrix.GetLength(0) 1 To 0 Step -1
theBlock = matrix(row, column)
If (Not theBlock Is Nothing) Then
If theBlock.MarkedForDeletion Then
For aRow = row To matrix.GetLength(0) 2
matrix(aRow, column) = _
matrix(aRow + 1, column)
Next
matrix(matrix.GetLength(0) 1, _
column) = Nothing
End If
End If
Next
Next
' Reset the MarkedForDeletion flags.