SFML: разработка приложений с графическим интерфейсом#
Материалы к занятию#
SFML. Установка и настройка в VS Studio#
SFML (Simple and Fast Multimedia Library) — это библиотека, предназначенная для разработки мультимедийных приложений, таких как игры и графические интерфейсы, с использованием языка C++. Данная методика описывает процесс установки и настройки SFML в среде разработки Visual Studio.
Для загрузки файлов библиотеки необходимо перейти на официальный сайт SFML и скачать последнюю стабильную версию библиотеки (https://www.sfml-dev.org/download/sfml/2.6.1/) . На момент написания этого пособия последней версией является SFML 2.6.1. Важно выбрать версию, совместимую с Visual Studio, например, Visual C++ 17 (2022) - 64-bit.
После завершения загрузки архив с библиотекой необходимо распаковать в удобное место на вашем компьютере. Рекомендуется создать папку dependencies в корневой директории вашего проекта и организовать её на подкаталоги для 32 и 64-битных версий. Это облегчит управление библиотеками при работе с проектами различных конфигураций.
В Visual Studio создаётся новый проект типа "Пустой проект". Это позволит начать работу с нуля, без предварительных настроек.
В обозревателе решений необходимо выбрать созданный проект и при помощи нажатия ПКМ добавить новый элемент — файл main.cpp, который будет содержать основной код программы (Обозреватель решений → ПКМ → Добавить → Создать элемент).
Важно обратить внимание на разрядность решения, которая должна соответствовать разрядности скачанной версии SFML. Для 64-битных систем указывается x64, а для 32-битных — x86.
Настройка путей к заголовочным файлам и библиотекам в Visual Studio происходит в несколько этапов:
• Открывается меню Проект -> Свойства.
• В разделе C/C++ -> Общие в поле Дополнительные каталоги включаемых файлов указывается путь к папке include библиотеки SFML.
Чтобы обеспечить переносимость проекта между ЭВМ необходимо описать относительные пути. Для этого в файле проекта должна быть создана директория dependencies внутрь которой следует разархивировать файлы SFML-2.6.1. Если процесс выполнен верно, то в строке «дополнительных каталогов включаемых файлов» указывается следующий путь:
$(ProjectDir)dependencies\SFML-2.6.1\include
Чтобы компоновщик смог найти библиотеки SFML, нужно указать путь к соответствующей папке:
• В разделе Компоновщик -> Общие в поле Дополнительные каталоги библиотек прописывается путь к папке lib
Если процесс выполнен верно, то в строке «дополнительных каталогов включаемых файлов» указывается следующий путь:
$(ProjectDir)dependencies\SFML-2.6.1\lib
Для правильной линковки файлов необходимо вручную добавить библиотеки:
В разделе Компоновщик -> Ввод -> Дополнительные зависимости добавляются файлы библиотек .lib для каждой конфигурации (Debug или Release).
Для конфигурации Debug добавляются следующие файлы:
- sfml-graphics-d.lib
- sfml-window-d.lib
- sfml-audio-d.lib
- sfml-system-d.lib
- sfml-network-d.lib
После настройки Debug версии необходимо также указать файлы для Release. Для этих целей смените конфигурацию в верхнем левом углу окна и повторите процесс аналогично прошлому этапу, изменив конфигурацию следующим образом:
- sfml-graphics.lib
- sfml-window.lib
- sfml-audio.lib
- sfml-system.lib
- sfml-network.lib
Компоновщик -> Дополнительно -> Точка входа (mainCRTStartup)
Кнопка применить!
Копируем все файлы из папки bin библиотеки SFML и вставляем в наш проект.
Проверка подключения#
Если вы правильно настроли среду, то при запуске следующего кода вы увидите окно с черным экраном.
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
window.clear();
window.display();
}
return 0;
}
Создание окна#
sf::RenderWindow
— это класс, который представляет собой окно, используемое для отображения графических объектов. Окно предоставляет графический контекст для отрисовки 2D объектов, таких как спрайты, текстуры, тексты и прочие элементы.
sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
Здесь:
sf::VideoMode(200, 200)
задает размеры окна: ширина — 200 пикселей, высота — 200 пикселей.
"SFML works!"
— строка, которая будет отображаться в заголовке окна.
Примечание: sf::RenderWindow
автоматически создает контекст OpenGL для отрисовки, что делает его удобным для создания графических приложений.
Основной цикл программы#
В графических приложениях обычно используется главный цикл, который продолжает выполняться, пока окно активно. Этот цикл управляет обновлением экрана, обработкой событий и логикой приложения. Рассмотрим его структуру:
while (window.isOpen())
{
// Обработка событий
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
// Очистка окна
window.clear();
// Обновление содержимого окна
window.display();
}
Ключевым элементом графических приложений является обработка событий (нажатие клавиш, изменение размера окна, движение мыши и т.д.). В SFML это реализовано через класс sf::Event
и метод window.pollEvent(event)
.
sf::Event event
— объект, который хранит информацию о произошедшем событии.
window.pollEvent(event)
— метод, который проверяет очередь событий окна и извлекает их. Если есть новое событие, метод возвращает true, и событие обрабатывается. Если событий нет, возвращает false.
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
Если тип события sf::Event::Closed
, это значит, что пользователь нажал на кнопку закрытия окна. В ответ на это окно закрывается с помощью метода window.close()
, что завершает главный цикл программы.
Замечание: Все события, включая изменения фокуса окна, нажатия клавиш, перемещение мыши и т.д., помещаются в очередь событий. Метод pollEvent
позволяет извлекать и обрабатывать эти события по очереди.
Обновление и отображение содержимого окна#
В каждом кадре важно сначала очистить окно, затем нарисовать новый кадр и обновить содержимое экрана. Эти действия выполняются следующими методами:
window.clear()
— очищает окно, удаляя все, что было отрисовано на предыдущем шаге.
window.display()
— отображает все, что было нарисовано с момента последнего вызова clear(). Это ключевой метод для обновления изображения на экране.
Практика#
Скаченные файлы (cookie.png и arial.ttf) из начала поместите в папку с проектом
Cookie Clicker: Инициализация окна#
Первым шагом в создании игры на SFML является инициализация окна. В данном случае окно создается с размерами 800x600 пикселей и заголовком "Cookie Clicker":
sf::RenderWindow window(sf::VideoMode(800, 600), "Cookie Clicker");
Задается окно, в котором будет происходить вся отрисовка и взаимодействие с пользователем. Это основной контейнер для всех графических объектов в игре.
Cookie Clicker: Инициализация окна#
sf::RenderWindow window(sf::VideoMode(800, 600), "Cookie Clicker");
Cookie Clicker: Размещение печенья#
Чтобы взаимодействовать с игроком, необходимо отобразить графический объект — печенье. Это реализовано через загрузку текстуры и создание спрайта.
// Загрузка текстуры печеньки
sf::Texture cookieTexture;
if (!cookieTexture.loadFromFile("cookie.png")) {
return -1;
}
// Спрайт для печеньки
sf::Sprite cookieSprite;
cookieSprite.setTexture(cookieTexture);
cookieSprite.setPosition(300, 200); // Позиция печеньки
Текстура — это изображение, которое будет отображаться на экране. Спрайт — это графический объект, который визуализирует текстуру. В данном примере спрайт печеньки размещается на позиции (300, 200).
sf::Sprite
- класс, описывающий спрайт, спрайт - это некий графический объект, которым мы можем управлять, менять его текстуру и другий свойства
sf::Texture` - это класс текстуры, по сути просто картинка, которую мы загрузили и можем натянуть куда-нибудь
Cookie Clicker: Добавление текста#
Для отображения счёта нужно инициализировать текст. Это делается с помощью шрифта и объекта sf::Text
.
// Шрифт для отображения счёта
sf::Font font;
if (!font.loadFromFile("arial.ttf")) {
return -1;
}
// Текст для отображения счёта
sf::Text scoreText;
scoreText.setFont(font);
scoreText.setCharacterSize(30);
scoreText.setFillColor(sf::Color::White);
scoreText.setPosition(10, 10);
Используем шрифт для текста, задаем его размер и цвет. Текст будет отображаться в левом верхнем углу окна.
Cookie Clicker: Инициализация счета#
Игровая логика начинается с инициализации переменной счёта, которая будет увеличиваться при каждом нажатии на печенье.
int score = 0; // Начальный счёт
scoreText.setString("Score: " + std::to_string(score));
Используем текст для отображения начального значения счёта, который изначально равен 0.
Cookie Clicker: Начало цикла#
Как и в любой игре, необходим основной цикл, который будет управлять всей логикой игры. В SFML такой цикл продолжается до тех пор, пока окно открыто.
while (window.isOpen()) {
// Обработка событий
sf::Event event;
while (window.pollEvent(event)) {
...
}
// Очистка и отрисовка объектов
window.clear();
window.draw(cookieSprite);
window.draw(scoreText);
window.display();
}
Цикл выполняет следующие шаги:
- Обработка событий.
- Очистка экрана для подготовки к новому кадру.
- Отрисовка объектов (печенья и счёта).
- Отображение новых данных на экране.
Cookie Clicker: Обработка событий#
Одним из важнейших элементов любой игры является обработка событий, таких как нажатие кнопок или клики мышью. В данном примере используются следующие типы событий:
- Закрытие окна.
- Клики мышью.
if (event.type == sf::Event::Closed) {
window.close();
}
if (event.type == sf::Event::MouseButtonPressed) {
if (event.mouseButton.button == sf::Mouse::Left) {
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
// Проверка, попал ли клик на печеньку
if (cookieSprite.getGlobalBounds().contains(mousePos.x, mousePos.y)) {
score += 1; // Увеличение счёта
scoreText.setString("Score: " + std::to_string(score)); // Обновление текста
}
}
}
Если нажата кнопка закрытия окна, программа завершает выполнение.
При клике левой кнопкой мыши проверяется, находится ли курсор в пределах границ спрайта печеньки. Если да — увеличивается счёт на единицу, и текст обновляется.
Итоговый проект#
#include <SFML/Graphics.hpp>
#include <vector>
#include <cstdlib> // Для rand()
#include <ctime> // Для time()
int main() {
// Создание окна
sf::RenderWindow window(sf::VideoMode(800, 600), "Cookie Clicker");
// Загрузка текстуры печеньки
sf::Texture cookieTexture;
if (!cookieTexture.loadFromFile("cookie.png")) {
return -1;
}
// Спрайт для печеньки
sf::Sprite cookieSprite;
cookieSprite.setTexture(cookieTexture);
cookieSprite.setPosition(300, 200); // Позиция печеньки
// Шрифт для отображения счёта
sf::Font font;
if (!font.loadFromFile("arial.ttf")) {
return -1;
}
// Текст для отображения счёта
sf::Text scoreText;
scoreText.setFont(font);
scoreText.setCharacterSize(30);
scoreText.setFillColor(sf::Color::White);
scoreText.setPosition(10, 10);
int score = 0; // Начальный счёт
scoreText.setString("Score: " + std::to_string(score));
// Основной цикл игры
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
// Проверка клика мышью
if (event.type == sf::Event::MouseButtonPressed) {
if (event.mouseButton.button == sf::Mouse::Left) {
// Получение позиции клика
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
// Проверка, попал ли клик на печеньку
if (cookieSprite.getGlobalBounds().contains(mousePos.x, mousePos.y)) {
score += 1;; // Увеличение счёта
scoreText.setString("Score: " + std::to_string(score)); // Обновление текста
}
}
}
}
// Очистка экрана
window.clear();
// Отрисовка печеньки и текста счёта
window.draw(cookieSprite);
window.draw(scoreText);
// Отображение нового кадра
window.display();
}
return 0;
}