- PVSM.RU - https://www.pvsm.ru -
От переводчика: данная статья является девятой в цикле переводов официального руководства по библиотеке SFML. Прошлую статью можно найти тут. [1] Данный цикл статей ставит своей целью предоставить людям, не знающим язык оригинала, возможность ознакомится с этой библиотекой. SFML — это простая и кроссплатформенная мультимедиа библиотека. SFML обеспечивает простой интерфейс для разработки игр и прочих мультимедийных приложений. Оригинальную статью можно найти тут [2]. Посвящается Еве Вайт. С днем рождения;). Начнем.
1. Приступая к работе
2. Модуль System
3. Модуль Window
4. Модуль Graphics
5. Модуль Audio
6. Модуль Network
Эта статья объясняет, как открыть и управлять окном. Рисование в окне выходит за пределы задач, решаемых модулем sfml-window
; эту задачу решает модуль sfml-graphics
. Однако управление окном с использование модуля sfml-graphics
выполняется также, так что чтение данной статьи важно в любом случае.
В SFML окна представлены классом sf::Window [11]. Окно может быть создано напрямую из конструктора данного класса:
#include <SFML/Window.hpp>
int main()
{
sf::Window window(sf::VideoMode(800, 600), "My window");
...
return 0;
}
Первый аргумент — видео режим, определяет размер создаваемого окна (размер области окна, без заголовка окна и границ). Тут мы создали окно размером 800x600 пикселей.
Класс sf::VideoMode [12] имеет интересные статические функции, с помощью которых можно получить разрешение рабочего стола или доступные видео режимы. Советуем посмотреть документацию по этому классу.
Второй аргумент — имя создаваемого окна.
Конструктор класса sf::Window [11] может принять и третий аргумент: стиль, который позволяет вам выбрать, какие украшения и функции вы хотите использовать.
Вы можете использовать любую комбинацию следующих стилей:
sf::Style::None |
Никаких украшений (используется, например, для загрузочных экранов); этот стиль не может быть использован с другими |
sf::Style::Titlebar |
У окна есть заголовок |
sf::Style::Resize |
Можно изменить размер окна и появляется кнопка открытие на весь экран |
sf::Style::Close |
У окна появляется кнопка закрытия |
sf::Style::Fullscreen |
Окно открывается в полноэкранном режиме; этот стиль не может быть скомбинирован с другими и требует доступный видео режим |
sf::Style::Default |
Стандартный стиль, который является сокращение Titlebar | Resize | Close |
Также есть четвертый аргумент, определяющий специфичные опции OpenGL. Эта тема рассматривается более подробно в статье по OpenGL.
Если вы хотите создать окно после создания экземпляра sf::Window [11] или создать окно заново, с другим видео режимом или названием, вы можете использовать функцию create
. Она принимает те же аргументы, что и конструктор класса.
#include <SFML/Window.hpp>
int main()
{
sf::Window window;
window.create(sf::VideoMode(800, 600), "My window");
...
return 0;
}
Если вы попробуете выполнить код выше (удалив "..."), вы вряд ли что-то увидите. Во-первых, потому что программа завершается немедленно. Во-вторых, потому что программа не обрабатывает события; так что, даже если вы добавили этот код в бесконечный цикл, вы увидите мертвое окно, которое не может быть перемещено или закрыто.
Давайте добавим немного кода, что бы сделать эту программу более интересной:
#include <SFML/Window.hpp>
int main()
{
sf::Window window(sf::VideoMode(800, 600), "My window");
// программа будет запущена до тех пор, пока окно открыто
while (window.isOpen())
{
// проверка всех событий окна, произошедших с последней итерации цикла
sf::Event event;
while (window.pollEvent(event))
{
// пользователь попытался закрыть окно: мы закрываем окно
if (event.type == sf::Event::Closed)
window.close();
}
}
return 0;
}
Код выше открывает окно и уничтожает его, когда пользователь закрывает его. Давайте посмотрим более детально, как он работает:
Во-первых, мы добавили цикл, который гарантирует, что приложение будет обновляться/дополняться до закрытия окна. Большинство (если не все) SFML программы будут иметь схожую конструкцию; иногда этот цикл называется main loop или game loop.
Затем, первое, что мы хотим сделать внутри нашего цикла — проверить наличие необработанных событий. Обратите внимание, что мы используем цикл while
так, чтобы обработать все ожидающие обработки события. Функция pollEvent
возвращает true
, если есть события, ожидающие обработки, или false
, если их нет.
Всякий раз, когда происходит событие, мы должны проверить его тип (закрытие окна? нажатие клавиши? перемещение мыши? подключение джойстика? ...), и, если мы заинтересованы в этом, отреагировать соответствующим образом. Здесь мы проверяем только то, произошло ли событие Event::Closed
, которое срабатывает, если пользователь попытается закрыть окно. В этот момент окно еще открыто и мы должны закрыть его явным образом с помощью следующих функций. Это позволяет вам сделать что-то перед закрытием окна, например, сохранить текущее состояние приложения или отобразить сообщение.
Люди часто забывают о цикле обработки событий, потому что им не нужно обрабатывать события (вместо этого они используют ввод с клавиатуры). Без цикла обработки событий, окно перестанет отвечать на запросы. Важно помнить, что цикл обработки событий имеет две роли: в дополнение к обработке пользовательских событий, это еще и обработка внутренних событий окна, которые могут быть вызваны перемещением или изменением размера окна.
После того, как окно закрылось, основной цикл завершается и программа завершает свое выполнение.
В этот момент, вы, наверное, заметили, что мы не говорили о рисовании чего-то в окне. Как указывалось во введении, это не задача модуля sfml-window
. Рисование объектов (спрайтов, текста или фигур) будет обсуждаться в статьях по sfml-graphics
.
Чтобы что-то рисовать, вы также можете использовать OpenGL напрямую и игнорировать модуль sfml-graphics
. sf::Window [11] создает OpenGL контекст и готова к принятию вызовов к OpenGL. Вы можете более подробно ознакомиться с данной темой в статье по использованию OpenGL.
Не ожидайте увидеть что-то интересное в новом окне: мы можете увидеть какой-нибудь цвет (черный или белый), или содержимое прошлого приложения, использовавшего OpenGL, или… что-то еще.
Конечно, SFML позволяет вам играться с вашими окнами. Основные операции с окнами, например изменение размера, положения, названия или иконки поддерживаются, но, в отличие от специальных библиотек GUI (Qt, wxWidgets), SFML не предоставляет расширенный функционал. Окна SFML предназначены только для обеспечения среды для OpenGL или SFML.
// изменение позиции окна (относительно рабочего стола)
window.setPosition(sf::Vector2i(10, 50));
// изменение размеров окна
window.setSize(sf::Vector2u(640, 480));
// изменение названия окна
window.setTitle("SFML window");
// получение размеров окна
sf::Vector2u size = window.getSize();
unsigned int width = size.x;
unsigned int height = size.y;
...
Вы можете обратиться к документации по API для получения полного списка функций sf::Window [11].
В случае, если вам действительно нужны расширенный функционал для вашего окна, вы можете создать одно окно с помощью другой библиотекой и внедрить его в SFML. Чтобы это сделать, вы можете использовать другой конструктор или создать функцию, которая передает sf::Window [11] дескриптор существующего окна. В этом случае, SFML будет создавать контекст рисования внутри переданного окна и отлавливать все события без вмешательства в родительский менеджер окна.
sf::WindowHandle handle = /* указание на то, что вы делаете и какую библиотеку вы используете */;
sf::Window window(handle);
Если вам нужна дополнительная, очень специфичная функция, вы можете сделать иначе: создать окно SFML, получить его дескриптор и сделать то, чего не позволяет SFML.
sf::Window window(sf::VideoMode(800, 600), "SFML window");
sf::WindowHandle handle = window.getSystemHandle();
// теперь вы можете использовать функции, специфичные для данной ОС
Интеграция SFML с другими библиотеками требует работы и не будет описана здесь, но вы можете обратиться к другим статьям, примерам или постам на форумах.
Иногда, когда приложение работает быстро, вы можете заметить визуальные артефакты. Причина в том, что частота обновления вашего приложения не синхронизирована с кадровой разверткой вашего монитора, и, как результат, нижняя часть предыдущего кадра смешивается с верхом следующего.
Решением этой проблемы является активизация вертикальной синхронизации. Синхронизация производится автоматически видеокартой и может быть просто включена или выключена с помощью функции setVerticalSyncEnabled
:
window.setVerticalSyncEnabled(true); // вызовите эту функцию единожды, после создания окна
После этого вызова, приложение будет выполняться с определенной частой, равной частоте обновления монитора.
Иногда вызов setVerticalSyncEnabled
не дает никакого эффекта: скорее всего, потому что вертикальная синхронизация выключена в настройках драйвера вашей видеокарты. Вы должны включить опцию «controlled by application» в настройках видеодрайвера.
Вы можете захотеть, чтобы ваше приложение работало на заданной кадровой частоте, вместо частоты обновления монитора. Это может быть достигнуто с помощью вызова setFramerateLimit
:
window.setFramerateLimit(60); // вызовите эту функцию единожды, после создания окна
В отличие от setVerticalSyncEnabled
, эта функция реализована SFML и использует комбинация sf::Clock [13] и sf::sleep
. Важно отметить, что эта функция не является надежной на 100%, особенно для высокой кадровой частоты: возможности sf::sleep
зависят от ОС и оборудования; минимальное время приостановки составляет 10-15 миллисекунд. Не полагайтесь на эту функцию, если вы создаете приложение, сильно зависящее от времени.
Никогда не используйте setVerticalSyncEnabled
и setFramerateLimit
вместе. Это может вызвать плохие последствия.
Ниже приведен список того, что вы можете и чего не можете делать с окнами SFML.
SFML позволяет создавать множество окон, а так же обрабатывать их события и управлять ими в главном потоке или в множестве потоков (но… смотрите ниже). В этом случае, не забудьте создать цикл обработки событий для каждого из них.
SFML неявным образом управляет несколькими мониторами. По этой причине, вы не можете выбрать, на каком мониторе появится окно, и вы не можете создать более одного полноэкранного окна. Это должно быть исправлено в будущих версиях.
Это является серьезным сдерживающим фактором для большинства операционных систем: цикл обработки событий (точнее, функция pollEvent
или waitEvent
) должен вызываться в том же потоке, в котором было создано окно. Это означает, что если вы хотите создать выделенный поток для обработки событий, вы должны убедиться, что окно создается в том же потоке. Если вы действительно хотите разделить задачи между потоками, удобнее обрабатывать события в главном потоке, и производить операции с окнами (например, отрисовку графики) в отдельном потоке. Эта конфигурация также будет совместима с других ограничений, описанными ниже.
Ага, это правда. Mac OS X не позволит вам создать окно или обработать события в потоке, отличном от главного.
По какой-то причине, Windows не позволяет созвать окна, размером больше, чем рабочий стол. Это затрагивает окна, созданные с помощью VideoMode::getDesktopMode()
: если вы будете использовать оформление окон (границы и заголовок), вы получите окно, которое будет немного больше, чем рабочий стол.
Следующая статья: Обработка событий.
Автор: HighMem
Источник [10]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/115904
Ссылки в тексте:
[1] тут.: https://habrahabr.ru/post/279689/
[2] тут: http://www.sfml-dev.org/tutorials/2.3/window-window.php
[3] SFML и Visual Studio: https://habrahabr.ru/post/278977/
[4] SFML и Code::Blocks (MinGW): https://habrahabr.ru/post/279069/
[5] SFML и Linux: https://habrahabr.ru/post/279107/
[6] SFML и Xcode (Mac OS X): https://habrahabr.ru/post/279147/
[7] Компиляция SFML с помощью CMake: https://habrahabr.ru/post/279279/
[8] Обработка времени: https://habrahabr.ru/post/279347/
[9] Потоки: https://habrahabr.ru/post/279653/
[10] Открытие и управление окнами: https://habrahabr.ru/post/279957/
[11] sf::Window: http://www.sfml-dev.org/documentation/2.3/classsf_1_1Window.php
[12] sf::VideoMode: http://www.sfml-dev.org/documentation/2.3/classsf_1_1VideoMode.php
[13] sf::Clock: http://www.sfml-dev.org/documentation/2.3/classsf_1_1Clock.php
Нажмите здесь для печати.