Создаем игру на SFML

в 11:45, , рубрики: c++, game development, Gamedev, OpenGL, SFML, разработка игр, метки: , , , ,

Приветствую всех игроделов и им сочуствующих. В этой статье я хочу рассказать о таком фреймворке, как SFML, и попытаться написать на нем простейшую игру (в нашем случае это будет клон легендарного Pong).

Создаем игру на SFMLv

Скачивание и установка

Скачать фреймворк можно с официального сайта. На данный момент для скачивания доступны две версии — 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

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js