Открываем файл Form1.vb (например, по схеме: File, Open, File) и в самом верху импортируем пространства имён для управления соответствующими классами:
Imports System.Reflection 'Для класса Assembly.
В классе Form1 нашего проекта записываем следующие переменные и методы.
Листинг 22.1. Переменные и методы.
'–
'Offsets on form where we should draw the playfield
'–
Const GAME_SCREEN_DX = 2
Const GAME_SCREEN_DY = 1
'Current playfield
Private m_playfieldManager As PlayFieldManager
'Gfx object of the form that we will render the playfield to
Dim m_myFormsGraphics As Graphics
'–
'Does the things we need to get get a round running
'–
Sub InitializeNewLevel()
'Add a game event handler to get updates on the game
AddHandler m_playfieldManager.GameStateChanged, _
AddressOf GameEventOccured
'Start the game
timerGame.Enabled = True
ButtonNextLevel.Visible = False
'–
'Give the text-box focus so we can get keyboard events
'–
TextBox1.Focus()
End Sub
'–
'Starts a new game
'–
Sub StartGame()
'Мелодия начала игры с ожиданием окончания мелодии:
'My.Computer.Audio.Play("..\..\Sounds\drumpad-crash.wav", _
' AudioPlayMode.WaitToComplete)
'Мелодия начала игры без ожидания её окончания:
My.Computer.Audio.Play("..\..\Sounds\drumpad-crash.wav")
'–
'Create Graphics object and cache it
'–
If (m_myFormsGraphics Is Nothing) Then
m_myFormsGraphics = Me.CreateGraphics
End If
'–
'Create the playfield level we want to start on
'–
m_playfieldManager = New Playfield_Level2()
'–
'Start the level running
'–
InitializeNewLevel()
End Sub
Sub PictureBoxPlayField_MouseDown( _
ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.MouseEventArgs)
'If Hank's around, give him a new destination
'If Not (m_HankTheWonderCaveMan Is Nothing) Then
If Not (m_playfieldManager Is Nothing) Then
m_playfieldManager.HankTheWonderCaveman. _
setHanksDestination(e.X, e.Y)
End If
End Sub
'–
'This event-sink is to get called when a game event occurs
'–
Sub GameEventOccured(ByVal gameUpdateMessage As _
PlayFieldManager.GameUpdate)
'The level was completed succesfully
If (gameUpdateMessage = PlayFieldManager.GameUpdate. _
levelSuccesfullyCompleted) Then
ButtonNextLevel.Visible = True
End If
End Sub
'Загружаем в проект файлы изображений по такой схеме:
'Создаём объект myAssembly класса Assembly и присваиваем ему
'ссылку на исполняемую сборку нашего приложения:
Public myAssembly As Assembly = Assembly.GetExecutingAssembly()
'Создаём объект myAssemblyName
'класса System.Reflection.AssemblyName и присваиваем ему
'имя сборки, которое состоит из имени проекта,
'Version, Culture, PublicKeyToken:
Public myAssemblyName As AssemblyName = myAssembly.GetName()
'Из имени сборки при помощи свойства Name
'выделяем имя проекта типа string:
Public myName_of_project As String = myAssemblyName.Name
В панели Properties (для Form1) на вкладке Events дважды щёлкаем по имени события Load. Появившийся шаблон метода после записи нашего кода принимает следующий вид.
Листинг 22.2. Метод для загрузки изображений.
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Me.Visible = False
'–
'Load and cache the global object we need
'–
g_InitializeGlobals()
Me.Visible = True
'–
'Place the textbox off the screen
'–
TextBox1.Width = 4
TextBox1.Multiline = True
TextBox1.Left = -20
'Start the game
StartGame()
End Sub
В панели Properties (для Form1) на вкладке Events дважды щёлкаем по имени события FormClosing. Появившийся шаблон после записи нашего кода принимает следующий вид.
Листинг 22.3. Метод для закрытия формы.
Private Sub Form1_FormClosing(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.FormClosingEventArgs) _
Handles MyBase.FormClosing
' '–
' 'Cleanup
' '–
'–
'Free up the form based objects
'–
m_playfieldManager = Nothing
If Not (m_myFormsGraphics Is Nothing) Then
m_myFormsGraphics.Dispose()
m_myFormsGraphics = Nothing
End If
'–
'Free up all the global objects
'–
g_DisposeAndFreeGlobals()
End Sub
На форме дважды щёлкаем по кнопке Button с номером 1 и текстом “Новая игра” (или в панели Properties, для этого элемента, на вкладке Events дважды щёлкаем по имени соответствующего события). Появившийся шаблон после записи нашего кода принимает следующий вид.
Листинг 22.4. Метод-обработчик щелчка кнопки.
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
StartGame()
End Sub
На форме дважды щёлкаем по кнопке Button с текстом Уровень (или в панели Properties, для этого элемента, на вкладке Events дважды щёлкаем по имени соответствующего события). Появившийся шаблон метода после записи нашего кода принимает следующий вид.
Листинг 22.5. Метод-обработчик щелчка кнопки.
Private Sub ButtonNextLevel_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles ButtonNextLevel.Click
'–
'Starts a new level of play
'–
'Ask the current level what it's next level is
m_playfieldManager = m_playfieldManager.GetNextLevel()
'Start the level running
InitializeNewLevel()
End Sub
На форме дважды щёлкаем по кнопке Button с текстом Помощь (или в панели Properties, для этого элемента, на вкладке Events дважды щёлкаем по имени соответствующего события). Появившийся шаблон метода после записи нашего кода принимает следующий вид.
Листинг 22.6. Метод-обработчик щелчка кнопки.
Private Sub buttonInstructions_Click( _
ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles buttonInstructions.Click
MsgBox("Правила игры: Соберите все факелы и " + _
"принесите их Еве. Очки засчитываются " + _
"за каждый факел данного уровня, " + _
"за оставшееся время бонуса и за энергию игрока, " _
+ "оставшуюся в конце каждого уровня.")
MsgBox("Адам потеряет энергию, если он будет поражён " + _
"валуном или птицей. Адам будет подскакивать, " + _
"чтобы не быть поражённым этими объектами. " + _
"Адам также потеряет энергию, " + _
"если он упадёт с большой высоты.")
MsgBox("Управление Адамом состоит в том, " + _
"чтобы щёлкать по экрану. После каждого щелчка " + _
"появляется пунктирная линия, показывающая, " + _
"куда пойдёт Адам. Чтобы Адам подпрыгнул " + _
"от валуна или птицы, " + _
"следует нажать клавишу пробела.")
'Bring the focus back to the textbox
'so it gets the keyboard input
TextBox1.Focus()
End Sub
В панели Properties, для элемента TextBox, на вкладке Events дважды щёлкаем по имени события KeyDown. Появившийся шаблон после записи нашего кода принимает следующий вид.
Листинг 22.7. Метод-обработчик события.
Private Sub TextBox1_KeyDown(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.KeyEventArgs) _
Handles TextBox1.KeyDown
'–
'This textbox is a way to get the keyboard input
'for the game becuase:
' 1. When you hit the "START" button, it get's the focus
'(so the form no longer gets keydown events)
' 2. The Start Button does not get key-down events
'–
If (m_playfieldManager Is Nothing) Then
Return
End If
Dim i As Integer
i = e.KeyValue
Const PocketPC_BUTTON_PUSHED = 134
Const Keyboard_SPACE_PUSHED = 32
Const PocketPC_UP = 38
Const PocketPC_DOWN = 40
Const PocketPC_LEFT = 37
Const PocketPC_RIGHT = 39
Dim hank As HankTheWonderCaveman = _
m_playfieldManager.HankTheWonderCaveman
Const D_MOVEMENT = 14
Const D_MOVEMENT_UP = 70
If (i = PocketPC_BUTTON_PUSHED) Or _
(i = Keyboard_SPACE_PUSHED) Then
hank.MakeHankJump()
e.Handled = True
ElseIf (i = PocketPC_RIGHT) Then
hank.NudgeHanksDirection(D_MOVEMENT, 0)
ElseIf (i = PocketPC_LEFT) Then
hank.NudgeHanksDirection(-D_MOVEMENT, 0)
ElseIf (i = PocketPC_UP) Then
hank.NudgeHanksDirection(0, -D_MOVEMENT_UP)
ElseIf (i = PocketPC_DOWN) Then
hank.NudgeHanksDirection(0, D_MOVEMENT)
End If
TextBox1.Text = ""
End Sub
Дважды щёлкаем по значку для таймера Timer (или в панели Properties, для этого компонента, на вкладке Events дважды щёлкаем по имени соответствующего события). Появившийся шаблон метода после записи нашего кода принимает следующий вид.
Листинг 22.8. Метод, вызываемый таймером через каждый интервал Interval времени.
Private Sub timerGame_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles timerGame.Tick
' '–
' 'This timer is the heartbeat if the game.
' 'Every time it gets called we
' 'allow all of the game characters to move,
' 'we check for collisions beween objects,
' 'and we render the board to the screen.
' '–
'–
'If we are not running, exit the sub
'–
If (m_playfieldManager Is Nothing) Then Exit Sub
'–
'Give all the characters a chance to move
'–
m_playfieldManager.MoveCharactersOnPlayfield()
'–
'Render the playfield and all of the objects onto the form
'–
m_myFormsGraphics.DrawImage(m_playfieldManager. _
RenderPlayField(), GAME_SCREEN_DX, GAME_SCREEN_DY)
End Sub
В панели Properties, для формы Form1, на вкладке Events дважды щёлкаем по имени события MouseDown. Появившийся шаблон после записи нашего кода принимает следующий вид.
Листинг 22.9. Метод-обработчик события.
Private Sub Form1_MouseDown(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles MyBase.MouseDown
'Make sure there is a game we are playing
If Not (m_playfieldManager Is Nothing) Then
If e.Button = MouseButtons.Right Then
m_playfieldManager.HankTheWonderCaveman. _
MakeHankJump()
Else
'–
'Figure out where on the game playfield we clicked
'–
Dim x_GAME As Integer
Dim y_GAME As Integer
x_GAME = e.X – GAME_SCREEN_DX
y_GAME = e.Y – GAME_SCREEN_DY
'Let Hank figure out what to do
m_playfieldManager.HankTheWonderCaveman. _
setHanksDestination(x_GAME, y_GAME)
End If
End If
End Sub
Мы закончили написание программы в главный класс Form1 (для формы Form1 с пользовательским интерфейсом игры).
Теперь в наш проект добавляем новые файлы (для программирования соответствующих игровых действий). Добавить в проект файл можно по двум вариантам.
По первому варианту, добавляем в проект нужный файл по обычной схеме: в панели Solution Explorer выполняем правый щелчок по имени проекта, в контекстном меню выбираем Add, Existing Item (или Project, Add Existing Item), в панели Add Existing Item в окне “Files of type” выбираем “All Files”, в центральном окне находим (в папке компьютера с загруженными, например, из Интернета, файлами) и с нажатой клавишей Ctrl выделяем все файлы формата (.vb) и щёлкаем кнопку Add, чтобы после этого добавления в панели Solution Explorer были файлы, показанные на рис. 22.11.
По второму варианту, в панели Solution Explorer выполняем правый щелчок по имени проекта и в контекстном меню выбираем Add, New Item, в панели Add New Item выделяем шаблон Code File, в окне Name записываем имя BorisTheMenacingBird.vb и щёлкаем кнопку Add. В проект (и в панель Solution Explorer) добавляется этот файл, открывается пустое окно редактирования кода, в которое записываем код со следующего листинга.
Листинг 22.10. Новый файл.
'–
'This class represents one of the characters in the game,
' "BorisTheMenacingBird"
'
'It contains logic for the rendering and movement of the character
'–
Public Class BorisTheMenacingBird
Inherits DrawablePlayfieldMultiFrameBitmap
Private m_yVelocityBoris As Integer 'How fast are _
'we traveling vertically?
Private m_xVelocityBoris As Integer 'How fast are we
'traveling vertically?
Const MAX_DY_BORIS_FLYING = 4
Private m_y_accelerationBorris As Integer
Private m_world_I_Inhabit As PlayFieldManager
Private m_myModeOfMovement As ModeOfMovement
Public Enum ModeOfMovement As Integer
Flying = 1
End Enum
'When did we last update a flipped image
Private m_lastTickCountWhenImageFlipped As Integer
Const DTIME_TO_FLAP_WINGS = 400 'Every 600 ms we should
'flap our wings
'–
'These are the current image states for Hank
'–
Private Enum BorisImagesIndexes
flyLeft1 = 1
flyLeft2 = 2
End Enum
'–
'[in] X,Y : Position to start Hank at
'[in] worldHankInhabits : Playfield in which Hank lives
'–
Sub New(ByVal x As Integer, ByVal y As Integer, _
ByVal world_I_Inhabit As PlayFieldManager)
'–
'Get the bitmaps for our character
'–
Dim col As Collection
col = g_FlyingBirdPictureCollection()
m_world_I_Inhabit = world_I_Inhabit
ChangeMyMovementState(ModeOfMovement.Flying)
'Start him off as falling.
'Initialize our base class with these…
MyBase.Initialize_DrawableMultiPlayfiedBitmapObject( _
x, y, col, True)
'Set the image index
Me.CurrentFrameIndex = BorisImagesIndexes.flyLeft1
'Set Boris' speed
m_xVelocityBoris = -4
m_y_accelerationBorris = 1
'–
'Set the collision rectangle for Hank
'–
Const BORIS_COLLISION_STARTX = 11
Const BORIS_COLLISION_DX = 31
Const BORIS_COLLISION_STARTY = 6
Const BORIS_COLLISION_DY = 7
Me.CollisionRectangle = New Rectangle( _
BORIS_COLLISION_STARTX, BORIS_COLLISION_STARTY, _
BORIS_COLLISION_DX, BORIS_COLLISION_DY)
End Sub
'–
'This function should be called to bring about any change
'of state
'It sets/resets any other variables we need to when we deal
'with state transitions
'–
Private Sub ChangeMyMovementState(ByVal newState As _
ModeOfMovement)
m_myModeOfMovement = newState
End Sub
'–
'MOVE Boris
'
'This function is called to move the character on the screen