Arkanoid и SDL. Управление спрайтами

Arkanoid sdl source code

Продолжаем создавать игры с использованием библиотеки SDL. На этот раз обсудим вариант управления спрайтами на примере игры Arkanoid.

При реализации более-менее сложного проекта, очень помогает разбиение общей задачи на подзадачи. Следовательно, код удобно разбить на серию модулей по назначению, что и было сделано.

Все необходимые графические файлы можно позаимствовать на общедоступных ресурсах: https://opengameart.org/content/starfield-background — фон; https://opengameart.org/sites/default/files/breakout_pieces_2.png — остальные детали.

Структура и описание

Итак, в процессе определения разных задач игры, у меня получился такой список модулей:

  • main.cpp — основной модуль
  • Ball.cpp — расчет и отрисовка мяча
  • Block.cpp — отрисовка отдельного блока
  • Collision.cpp — алгоритмы определения столкновений разных объектов сцены
  • Player.cpp — все, что связано с игроком (двигающейся платформой). Обработка событий клавиатуры, отрисовка платформы и т.д.
  • Scene.cpp — алгоритмы обработки игрового процесса в целом
  • SpriteBank.cpp — модуль для формирования базы спрайтов из набора графических изображений
  • SpriteString.cpp — модуль для вывода текстовых сообщений

Для каждого исходника существует соответствующий заголовочный файл с необходимым описанием типов и структур данных.

Для внесения ясности скажу, что старался отделить работу с графикой от игровой логики и «физики». Ничего особенного в этом нет, так как это общий принцип. Подробно следует рассказать только о SpriteBank.

SpriteBank

Для себя я решил, что хорошо было бы сгруппировать спрайты в наборы по смыслу. Допустим, в нулевом наборе будут фоны уровней, а номер фона будет соответствовать номеру уровня. В первом наборе сосредоточены спрайты анимации персонажа в естественном порядке их следования. Во втором объединены все статичные объекты сцены и т.д. Это удобно, так как программист не задумывается о том как и из каких источников будет сформирован контент. Есть только номер набора картинок и назначение этого набора.

Желательно иметь возможность формировать такие множества любым способом (брать спрайты из разных графических файлов, использовать один и тот же спрайт в разных наборах, менять порядок следования и т.д.).

Набор спрайтов

Как решить такую задачу? Можно загрузить нужные изображения в память, пронумеровав их. Затем описать ряд прямоугольных областей из загруженных картинок. Для описания такой области достаточно указать номер области, номер изображения, координаты и размеры прямоугольника.

Подмножества (наборы)

Когда набор всех нужных спрайтов (прямоугольных частей исходных изображений) описан, можно приступить к описанию групп этих спрайтов. Для каждой группы понадобиться следующая информация: номер группы, количество спрайтов в ней, упорядоченный набор пар <номер спрайта>-<номер изображения>.

test.set

Всё вышеописанное храниться в файле test.set, который есть в архиве с исходниками. Но для понимания мы рассмотрим наиболее простой пример такого файла:

0

3
0 crypt.png
1 ../Tilesets/breakout_pieces.png
2 bg_1_1.png

5
0 0 0 0 64 64 
1 0 64 0 64 64
2 1 48 8 32 16
3 1 84 8 32 16
4 2 0 0 640 480

3

0
2
0 0 1 0

1
2
2 1 3 1

2
1
4 2

Как следует воспринимать написанное? Первое число (0) — это идентификатор базы спрайтов. На тот случай, если баз будет несколько. Затем указано количество файлов-изображений (их 3). Первый файл имеет идентификатор 0 и название «crypt.png«, а последний — 2 и название «bg_1_1.png«. Затем указано общее количество спрайтов в базе (5) и соответствующее описание каждого спрайта. Например, строка «2 1 48 8 32 16» говорит нам, что спрайт под номером 2 взят как прямоугольная область картинки «../Tilesets/breakout_pieces.png» с координатами x:48, y:8, шириной 32 пикселя, высотой 16 пикселей.

А теперь из этих пяти спрайтов сформируем наборы. Тут всего три набора. Первый имеет номер 0, содержит 2 спрайта (0 и 1 из crypt.png, на что указывает строка «0 0 1 0»). Остальные два записаны в аналогичном формате.

В данном случае может показаться избыточным номер источника спрайта. Но такой шаг оправдан, если номера спрайтов уникальны только в рамках одного источника.

Таким образом, программисту для отображения игрового мира достаточно определиться с назначением подмножеств (наборов) и смыслом порядкового номера элемента в каждом подмножестве. К тому же, замена каких-либо спрайтов может осуществляться простым редактированием файла test.set.

SpriteString

Практически во всех играх присутствует хоть какой-то текст. Кроме того, выдавать сообщения игроку хотелось бы с помощью красивого, стилистически подходящего шрифта. Такой шрифт можно легко приспособить к проекту, если он существует в виде графического файла с изображением символов. В таком случае делаем каждый символ отдельным спрайтом, формируем соответствующий набор, сопоставляем его со строкой-алфавитом и создаем функцию отображения текста. Всё это реализовано в модуле SpriteString.

В общем и целом

Чем ценен данный проект? А тем, что SpriteBank можно использовать в своих целях, как и всё остальное в нём. На полноценную игру эта версия Arkanoid не претендует, так как весь игровой процесс сводится к уничтожению случайным образом созданного поля из кирпичей. У игрока есть три попытки пройти уровень. За каждый уничтоженный кирпич начисляются очки. Вот, собственно, и всё.

Исходники довольно легко доработать, если есть желание.

Добавить комментарий

Ваш e-mail не будет опубликован.