Важно отметить, что добавление в проект компонента Timer (Таймер) означает, что наша игра должна отключить таймер, когда игра находится в фоновом режиме, и включить таймер при активации игры. Именно поэтому в панели Properties (для данного компонента Timer) в свойстве Enabled мы оставили логическое значение False.
Кроме того, таймер не должен быть включённым, пока программа не загрузит изображение. Поэтому в приведённом выше методе Form1_Paint в самом низу следует дописать:
'Включаем таймер:
Timer1.Enabled = True
Окончательно, код в теле метода Form1_Paint должен иметь такой вид.
Листинг 4.3. Метод для рисования изображения.
Private Sub Form1_Paint(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) _
Handles MyBase.Paint
'Загружаем в объект класса System.Drawing.Image
'добавленный в проект файл изображения заданного формата
'при помощи потока встроенного ресурса (ResourceStream):
cheeseImage = _
New Bitmap(myAssembly.GetManifestResourceStream( _
myName_of_project + "." + "cheese.JPG"))
'Рисуем изображение на форме Form1:
e.Graphics.DrawImage(cheeseImage, cx, cy)
'Включаем таймер:
Timer1.Enabled = True
End Sub
Теперь всякий раз, когда вызывается метод Form1_Paint, программа рисует сыр на экране с соответствующими координатами cx и cy.
Дважды щёлкаем по значку для компонента Timer (ниже формы в режиме проектирования). Появляется шаблон метода timer1_Tick, который после записи нашего метода updatePositions и библиотечного метода Invalidate (или Refresh) для перерисовки изображения на экране принимает следующий вид.
Листинг 4.4. Метод для смены кадров на экране и перемещения фигуры.
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
'Вызываем метод:
updatePositions()
'Перерисовываем экран:
Invalidate()
End Sub
Строим и запускаем программу на выполнение обычным образом: Build, Build Selection; Debug, Start Without Debugging. В ответ VS выводит панель Deploy (с именем проекта), на которой выбираем устройство (Device) типа Windows Mobile 6 Classic (или Professional) Emulator и щёлкаем кнопку Deploy. Появляется форма в режиме выполнения, на форме Form1 которого изображение типа встроенного нами рисунка сыра cheese.jpg из верхнего левого угла перемещается по диагонали сверху вниз (в нижний правый угол) и скрывается (рис. 4.3).
Изображение объекта мерцает, что в дальнейшем будет исправлено применением двойной буферизации.
Таким образом, мы разработали методику анимации, по которой можно перемещать любые объекты на экране .
Рис. 4.3. Объект перемещается по диагонали сверху вниз.
Рис. 4.4. Отскок объекта.
4.3. Методика проектирования отскока объекта от границы
Разработаем методику решения задачи по отскоку заданного нами объекта от заданных нами границ, например, от границ экрана. В качестве предмета и замкнутого пространства могут быть, например:
резиновый мяч, металлический или пластмассовый шар, который с большой силой бросил человек в каком-то помещении; предмет летает внутри помещения и отскакивает от пола, потолка и стен этого помещения;
пуля, выпущенная из огнестрельного оружия, например, стальная дробь, выпущенная из охотничьего ружья в комнате и в полете отскакивающая от пола, потолка и стен этой комнаты.
На практике подобные очень сложные задачи решаются после ввода в постановку задачи большого числа допущений.
Мы также введём большое число допущений, после чего задачу формулируем так:
решаем плоскую задачу, т.е. предмет изображаем в виде его проекции на плоскость x, y; в качестве примера предмета выбираем кусочек сыра cheese.jpg, проекция которого на плоскость имеет вид прямоугольника;
на этой плоскости x, y замкнутое пространство изображаем в виде задаваемой нами замкнутой линии; в качестве примера замкнутой линии выбираем прямоугольник границы экрана;
предмет перемещается в этой плоскости x, y до столкновения с границей (линией), а после удара о границу должен отскочить от границы под определённым углом и перемещаться до следующего столкновения с границей, и так далее перемещаться и отражаться от линии;
принимаем обычное допущение, что до столкновения с границей предмет перемещается (летит) по прямой линии;
на основании допущения о том, что угол падения равен углу отражения, принимаем, что после столкновения с линией прямоугольника предмет отскакивает от этой линии под тем же углом; величину угла падения и угла отражения предмета от прямой линии принимаем равной 45 градусам;
перемещение предмета осуществляется поэтапно за интервал времени, который мы установим с помощью компонента Timer (Таймер);
интервал времени устанавливаем по значению свойства Interval компонента Timer; таким образом скорость перемещения объекта можно изменять за счёт изменения свойства Interval;
анимация является бесконечным (если в него не вмешиваться) нециклическим процессом; анимацию можно остановить на любом этапе и запустить вновь.
Для решения этой задачи программа должна отслеживать текущую позицию (в виде координат) объекта, и затем, когда значение одной из двух координат объекта станет равным значению одной из двух координат границы, изменить координаты объекта в противоположном от границы направлении.
Таким образом, в данном проекте приведённый выше метод updatePositions заменяем на следующий.
Листинг 4.5. Отскок объекта от границ.
'Перемещение по оси "x" вправо (Right):
Dim goingRight As Boolean = True
'Перемещение по оси "y" вниз (Down):
Dim goingDown As Boolean = True
Private Sub updatePositions()
If (goingRight) Then
cx = cx + 1
Else
cx = cx 1
End If
If ((cx + cheeseImage.Width) >= _
Me.ClientSize.Width) Then
goingRight = False
End If
If (cx <= 0) Then
goingRight = True
End If
If (goingDown) Then
cy = cy + 1
Else
cy = cy 1
End If
If ((cy + cheeseImage.Height) >= _
Me.ClientSize.Height) Then
goingDown = False
End If
If (cy <= 0) Then
goingDown = True
End If
End Sub
В этом коде видно, что координаты объекта x, y изменяются на величину +1, когда объект перемещается в положительном направлении осей x, y (вправо и вниз), и изменяются на величину -1, когда объект перемещается в отрицательном направлении осей x, y (влево и вверх).
Код использует свойства ширины и высоты объекта (cheeseImage.Width и cheeseImage.Height) и экрана Me.ClientSize.Width и Me.ClientSize.Height). Вследствие этого программа будет нормально работать для любых размеров объекта и формы или экрана.
В режиме выполнения (Build, Build Selection; Debug, Start Without Debugging) мы видим, что на форме Form1 изображение типа встроенного нами рисунка сыра cheese.jpg перемещается по диагоналям в различных направлениях, отскакивая от границ экрана (рис. 4.4).
Методика приостановки и возобновления анимации уже была приведена выше.
4.4. Методика управления скоростью перемещения объекта и добавления звукового сигнала
Предыдущая программа довольно медленно перемещает объект по экрану. Если ширина экрана, например, 100 пикселей, то с частотой 25 кадров в секунду объект пересекает этот экран по горизонтальной прямой приблизительно за 4 секунды. Для управления скоростью перемещения объекта вместо предыдущего кода, в котором изображение перемещается на 1 пиксель через каждый Interval времени срабатывания таймера, можно изменить количество пикселей xSpeed, на которое объект перемещается через каждый Interval времени срабатывания таймера, как показано в следующем коде:
If (goingRight) Then
cx += xSpeed