Приветствую всех игроделов и им сочуствующих. В этой статье я хочу рассказать о таком фреймворке, как SFML, и попытаться написать на нем простейшую игру (в нашем случае это будет клон легендарного Pong).
v
Скачивание и установка
Скачать фреймворк можно с официального сайта. На данный момент для скачивания доступны две версии — 1.6 и 2.0. Я использовал версию 2.0 для Visual C++ 2010. Вы же можете выбрать необходимый для вашей ОС и компилятора вариант SFML.
Так как целью статьи не является обсуждение особенности подключения библиотек в разных IDE, то руководство по установке можно прочитать на оф. сайте. Я же постараюсь вести рассказ не привязываясь к какой-либо ОС и компилятору.
Создаем основу
Из библиотек нам будут нужны только sfml-graphics, sfml-window, sfml-system (можно подключить sfml-main для кроссплатформенности функции main). Начинаем создавать скелет будущей игры.
#include <SFML/Graphics.hpp>
int main()
{
// Создаем главное окно приложения
sf::RenderWindow window(sf::VideoMode(800, 600), "Pong");
// Главный цикл приложения
while(window.isOpen())
{
// Обрабатываем события в цикле
sf::Event event;
while(window.pollEvent(event))
{
// Кроме обычного способа наше окно будет закрываться по нажатию на Escape
if(event.type == sf::Event::Closed ||
(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape))
window.close();
}
// Очистка
window.clear();
// Тут будут вызываться функции обновления и отрисовки объектов
// Отрисовка
window.display();
}
return 0;
}
Итак, что же мы тут сделали? В первой строке был подключен заголовочный файл Graphics.hpp, и далее мы создали функцию main() и окно размером 800X600 c заголовком «Pong».
SFML предлагает удобные средства для работы с событиями. Именно их мы используем для создания цикла работы приложения и обработки событий окна. C помощью цикла мы реализуем закрытие окна по нажатию Escape. Вообще, sf::Event предоставляет возможность работы не только с клавиатурой, но и, например, с мышью. Кроме этого можно работать с некоторыми системными событиями, и не переписывать код под каждую новую платформу. Так что, если вы захотите использовать в игре джойстик, то вам не придется переписывать половину кода — достаточно будет добавить пару строк в цикл обработки.
Далее мы очищаем окно и отрисовываем содержимое буфера. Всё, каркас игры готов, можно компилировать и проверить работу. Перед вами должно появиться черное окно.
Ракетка
В Pong существует всего два вида объектов — ракетка и мяч. Мячом мы займемся в следующей статье, а класс ракетки создадим сейчас. Но для начала нам нужно добавить в main() несколько строк.
// Создаем переменную таймера (нужен для плавной анимации)
sf::Clock clock;
float time;
// Включаем вертикальную синхронизацию (для плавной анимации)
window.setVerticalSyncEnabled(true);
/* Ставим эти строки после window.clear(). Здесь мы сохраняем прошедшее время в миллисекундах и перезапускаем таймер */
time = clock.getElapsedTime().asMilliseconds();
clock.restart();
Теперь начнем создавать класс Paddle. Я привел здесь только основные методы, всё остальное вы сможете увидеть в исходниках (ссылка на скачивание в конце статьи).
class Paddle {
sf::RenderWindow* window; // Указатель на окно, нужен для отрисовки
sf::RectangleShape rectangle; // Собственно, сама ракетка
int y; // Координата y ракетки (x мы задаем в коде)
int player; // Номер игрока (1 или 2)
int score; // Переменная для хранения счета
public:
// Конструктор
Paddle(sf::RenderWindow* window, int player) {
this->score = 0;
this->y = 300;
this->player = player;
this->window = window;
// Устанавливаем размер для ракетки с помощью Vector2f
this->rectangle.setSize(sf::Vector2f(10, 100));
// Для удобства перенесем основную точку из левого верхнего угла в центр
this->rectangle.setOrigin(5, 50);
// И устанавливаем ракетки в начальные позиции
if(this->player == 1) {
this->rectangle.setPosition(25, this->y);
}
else {
this->rectangle.setPosition(775, this->y);
}
}
// Метод для отрисовки ракетки
void draw() {
this->window->draw(this->rectangle);
}
/* Обработка нажатия клавиш и перемещение ракеток
Первый игрок управляет стрелками, второй -- клавишами W и S */
void update(float time) {
if(this->player == 1) {
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
// Изменяем положение ракетки в зависимости от времени таймера
this->y -= time * 0.3;
this->setY(this->y); // setY - сеттер для переменной Y
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
this->y += time * 0.3;
this->setY(this->y);
}
}
else {
if(sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
this->setY(this->y - time * 0.3);
}
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
this->setY(this->y + time * 0.3);
}
}
}
Ракеткой нам послужит прямоугольник размером 10X100. Размер мы задаем с помощью класса Vector2f — это вполне обычный вектор, в будущем он пригодится нам для задания направления движения мяча.
Кроме системы событий в SFML есть еще один способ для обработки устройств ввода. Именно его мы используем для управления ракетками с клавиатуры. Также можно перенести управление игрока на мышь — для этого, соответственно, будет использоваться sf::Mouse (или sf::Joystick).
В исходном коде рекомендую обратить внимание на метод setY — он проверяет координаты ракетки и не дает ей выйти за пределы поля.
Теперь можно создать пару объектов Paddle и вызвать методы draw и update после очистки окна. Если вы откомпилируете исходный код, то увидите две ракетки на противоположных сторонах окна, первая управляется с помощью курсорных клавиш «вверх», «вниз», вторая — клавишами W и S.
Заключение
Пока на этом мы остановимся, а в следующей статье я расскажу, как создать класс мяча и систему очков.
Исходники.
Автор: Wyorma