Последний выпуск по программированию спрайтовых игр был - 115.
Практический пример
Рассмотрим изученные возможности BlitzBasic на примере создания простейшего арканоида. Для этого нам потребуются: основная игровая панель, спрайты шарика, биты и кирпичиков. В демонстрационной версии воспользуемся готовыми рисунками из примера арканоида, входящего в поставку BlitzBasic, однако весь код напишем сами с нуля.
Изображения хранятся в каталоге BlitzBasic Samples/2D Samples/blitzanoid/gfx/. Панель - файл field.bmp, шарик - ball.bmp, бита - bat.bmp, кирпичики - все в одном файле blocks.bmp.
Создадим заготовку программы с главным циклом отображения. В таком виде она только будет отображать на экране число кадров в секунду:
Graphics 640,480,16
SetBuffer BackBuffer()
fps = 1
fpsc = 0
tim = MilliSecs() while not KeyHit(1)
Cls
Text 100,100,fps
Flip
fpsc = fpsc+1 if MilliSecs()-tim > 1000 then
tim = MilliSecs()
fps = fpsc
fpsc = 0 end if
Wend end
Следующий шаг - отображение на экране игровой панели. Можно делать это сразу командой DrawImage, однако не исключено, что в будущем отображение панели потребует дополнительно вывод набранных очков, бонусов и других сведений. Поэтому выделим для этой цели отдельную функцию DrawBoard, пока пустую:
function DrawBoard()
end function
а вызывать ее будем в главном цикле:
while not KeyHit(1)
Cls
DrawBoard()
Text 100,100,fps
Flip
...
В начало программы добавим команду загрузки спрайта игрового поля:
Graphics 640,480,16
SetBuffer BackBuffer()
Global sprBoard = LoadImage("field.bmp")
...
а в функцию его отображения - команду вывода спрайта:
; function DrawBoard()
DrawImage sprBoard,0,0 end function
Проверьте, как работает программа, и переметите вывод значения FPS в более подходящее место.
Кирпичи, шарик и бита
Теперь подумаем над способом представления движущихся объектов в программе. Для каждого игрового объекта (шар, кирпич, бонус) можно в принципе выделить свой собственный тип данных, но это бывает полезно, если структура каждого такого типа сильно отличается от других. Например, объект "робот" по внутреннему строению будет сильно разниться от объекта "снаряд".
В нашем же случае все игровые объекты характеризуются, в сущности, схожими параметрами - для их обработки требуется фактически лишь знание местоположения на экране, скорость и идентификатор спрайта. Поэтому будем для простоты использовать один общий тип данных TBrick, который сейчас опишем, а вот внутри него уже выделим отдельное поле для различия между шаром, битой, кирпичом и т. д.
type TBrick
Field Id
Field n
Field obj
Field x#, y#
Field sx#,sy# end type
Id - это наш, внутренний номер, обозначающий класс объекта. Пусть значение 1 будет соответствовать кирпичику, значение 2 - мячу, значение 3 - бите (ракетке).
n - некий уникальный номер объекта в игре.
obj - идентификатор спрайта.
x#,y# - координаты на экране.
xs#, sy# - скорость движения.
Пусть первоначально у нас в игре будет 25 кирпичей и по одному шарику и бите. Тогда их инициализация в начале программы может выглядеть так:
for i = 1 to 25
b.TBrick = New TBrick
b\x# = i*20-3
b\y# = 30
b\Id = 1
b\n = i
b\obj = LoadAnimImage("blocks.bmp",32,16,0,14)
Next
Обратите внимание, что хотя мы считаем каждый кирпич статичным спрайтом, загружаем мы не одну картинку, а серию, как в анимированный. Это позволит в дальнейшем менять, например, цвет кирпичика в зависимости от различных условий, просто указывая номер спрайта в группе.
Дополним функцию DrawBoard() отображением всех кирпичиков. Для этого воспользуемся известным вариантом оператора цикла, перебирающим все значения некоторого пользовательского типа.
Так как все наши объекты должны всегда отображаться на экране, можно сразу, без проверки внутреннего типа, показать текущий объект (ведь нам все равно, кирпичик это, шар или бита - все они должны быть отображены).
; function DrawBoard()
DrawImage sprBoard,0,0
; for b.TBrick = Each TBrick
DrawImage b\obj, b\x#, b\y# Next
end function
Запустите программу - на экране появится уже достаточно красивое, но пока неподвижное изображение.
Оживляем биту
Внутри цикла перебора элементов нам теперь надо проверить, является ли текущий объект битой (значение его поля Id должно равняться 3).
if b\Id = 3 then
end if
В этом случае x-координату биты просто надо привязать к текущей x-координате мыши:
for b.TBrick = Each TBrick
DrawImage b\obj, b\x#, b\y#
if b\Id = 3 then ; бита
b\x# = MouseX() end if
Next
Запустите программу и проверьте, как двигается бита.
Запускаем шарик
Следующий шаг - оживление шарика. Сделаем это уже знакомым нам способом - просто будем изменять его координату на значение скорости. Выполним это внутри соответствующей проверки на принадлежность текущего объекта типу "шарики":
if b\Id = 2 then ; шарик!
b\x# = b\x# + b\sx#
b\y# = b\y# + b\sy# end if
При соприкосновении шарика со стенкой его скорость должна меняться на противоположную. Но надо учесть направление его движения, чтобы при отражении от вертикальной стены менялась лишь x-составляющая, и наоборот.
Задание. Дополните программу контролем за шариком - он не должен улетать за пределы экрана, а отражаться от стен, правильно (естественно) изменяя направление движения и с учетом толщины стен. Шарик может исчезать, только если он уходит вниз.
Во второй части данного занятия мы рассмотрим, как правильно выполнять анализ столкновения шарика с кирпичиками, чтобы это давало наглядный эффект.