От переводчика: данная статья является десятой в цикле переводов официального руководства по библиотеке SFML. Прошлую статью можно найти тут. Данный цикл статей ставит своей целью предоставить людям, не знающим язык оригинала, возможность ознакомится с этой библиотекой. SFML — это простая и кроссплатформенная мультимедиа библиотека. SFML обеспечивает простой интерфейс для разработки игр и прочих мультимедийных приложений. Оригинальную статью можно найти тут. Начнем.
Оглавление:
0.1 Вступление
1. Приступая к работе
2. Модуль System
3. Модуль Window
4. Модуль Graphics
5. Модуль Audio
6. Модуль Network
1. Приступая к работе
- SFML и Visual Studio
- SFML и Code::Blocks (MinGW)
- SFML и Linux
- SFML и Xcode (Mac OS X)
- Компиляция SFML с помощью CMake
2. Модуль System
3. Модуль Window
- Открытие и управление окнами
- Обработка событий
- Работа с клавиатурой, мышью и джойстиками
- Использование OpenGL
4. Модуль Graphics
- Рисование 2D объектов
- Спрайты и текстуры
- Текст и шрифты
- Формы
- Проектирование ваших собственных объектов с помощью массивов вершин
- Позиция, вращение, масштаб: преобразование объектов
- Добавление специальных эффектов с шейдерами
- Контроль 2D камеры и вида
5. Модуль Audio
- Проигрывание звуков и музыки
- Запись аудио
- Пользовательские потоки аудио
- Спатиализация: звуки в 3D
6. Модуль Network
- Коммуникация с использованием сокетов
- Использование и расширение пакетов
- Веб-запросы с помощью HTTP
- Передача файлов с помощью FTP
Вступление
В этой статье приводится подробный список событий и объясняется, как эти события обрабатывать.
Тип sf::Event
До детального разбора обработки событий важно понять, что из себя представляет тип sf::Event, и как правильно использовать его. sf::Event состоит из объединения, хранящего в себе тип события, и вспомагательных функций и членов. Доступному члену объединения соответсвует один или несколько членов класса, например,
event.key
соответствует событию KeyPressed
. Попытка обработки любых других членов приведет к неопределенному поведению. Никогда не пытайтесь обработать не произошедшее событие.Экземпляр sf::Event можно инициализировать функцией
pollEvent
(или waitEvent
) класса sf::Window. Только эти две функции могут инициализировать экземпляр sf::Event. Для ясности, вот как выглядит типичный цикл обработки событий:
sf::Event event;
// пока есть события, обрабатывать их...
while (window.pollEvent(event))
{
// проверяем тип события...
switch (event.type)
{
// закрытие окна
case sf::Event::Closed:
window.close();
break;
// нажатие клавиши
case sf::Event::KeyPressed:
...
break;
// мы не обрабатываем другие типы событий
default:
break;
}
}
Перечитайте параграф выше и убедитесь, что вы все поняли. Класс sf::Event вызывает много проблем у начинающих программистов.
Ладно, теперь мы знаем, как события представлены в SFML, настало время выяснить, что каждое событие означает.
Событие Closed
Событие
sf::Event::Closed
срабатывает, когда пользователь хочет закрыть окно, используя любой из методов, предоставляемых менеджером окон (кнопка закрытия, макросы клавиатуры и так далее). Это событие предоставляет информацию о том, что пользователь попытался закрыть окно; оно еще не закрыто.Обычно, в ответ на это событие, код вызывает
window.close()
, чтобы закрыть окно. Однако, вы можете сделать еще что-то, например, сохранить текущее состояние приложения или спросить пользователя, что надо сделать. Если вы ничего не сделаете в ответ на это событие, окно будет оставаться открытым.Член класса, ассоциируемый с этим событием, не существует.
if (event.type == sf::Event::Closed)
window.close();
Событие Resized
Событие
sf::Event::Resized
срабатывает, когда происходит изменение размера окна. Либо в результате действия пользователя, либо программно, после вызова window.setSize
.Вы можете использовать это событие, чтобы отрегулировать настройки отображения: область просмотра, если вы используете OpenGL напрямую, или текущую точку обзора, если вы используете
sfml-graphics
.Член класса, ассоциируемый с этим событием, называется event.size и содержит новый размер окна.
if (event.type == sf::Event::Resized)
{
std::cout << "new width: " << event.size.width << std::endl;
std::cout << "new height: " << event.size.height << std::endl;
}
События LostFocus и GainedFocus
События
sf::Event::LostFocus
и sf::Event::GainedFocus
срабатывают, когда окно потеряло/приобрело фокус; это происходит, когда пользователь меняет текущее активное окно. Когда окно теряет фокус, оно не получает события клавиатуры.Это событие можно использовать, например, для приостановки игры, когда окно неактивно.
Член класса, ассоциируемый с этим событием, не существует.
if (event.type == sf::Event::LostFocus)
myGame.pause();
if (event.type == sf::Event::GainedFocus)
myGame.resume();
События TextEntered
Событие
sf::Event::TextEntered
срабатывает, когда происходит ввод символа. Это не событие KeyPressed
: TextEntered
срабатывает, когда пользователь вводит символ, который может быть выведен. Например, нажатие '^' и 'e' на французской клавиатуре приведет к двум событиям KeyPressed
и только к одному TextEntered
, содержащему символ 'e'. Это работает для всех методов ввода, предоставленным операционной системой.Это событие обычно используется для отлова пользовательского ввода в текстовое поле.
Член класса, ассоциируемый с этим событием, называется
event.text
и содержит номер символа Unicode введенного символа. Вы можете поместить это значение в sf::String, или привести его к типу char
после того, как убедитесь, что этот символ лежит в диапазоне ASCII символов (0 — 127).if (event.type == sf::Event::TextEntered)
{
if (event.text.unicode < 128)
std::cout << "ASCII character typed: " << static_cast<char>(event.text.unicode) << std::endl;
}
Многие программисты используют событие
KeyPressed
для обработки пользовательского ввода и применяют сумасшедшие алгоритмы для обработки пользовательского ввода, которые пытаются интерпретировать все возможные комбинации клавиш. Не делайте этого!События KeyPressed и KeyReleased
События
sf::Event::KeyPressed
и sf::Event::KeyReleased
срабативают, когда клавиша на клавиатуре нажата/отжата. Если клавиша зажата, события
KeyPressed
будут генерироваться с определенным интервалов, заданным операционной системой (т.е. та же задержка, что применяется, когда вы вводите текст в редакторе). Чтобы отменить повторение событий KeyPressed
, вы можете вызвать window.setKeyRepeatEnabled(false)
. Очевидно, что событие KeyReleased
никогда не повторяется.Эти события можно использовать, если вы хотите вызвать какое-нибудь действие ровно один раз, когда клавиша нажата или отжата, например, чтобы заставить персонажа прыгнуть.
Иногда люди пытаются использовать событие
KeyPressed
для реализации плавного движения. Это не приводит к ожидаемому эффекту, потому что это событие генерируется с определенным интервалом. Чтобы реализовать плавное движение с помощью событий, вы должны использовать логическое значение, устанавливаемое KeyPressed
и обнуляемое KeyReleased
; движение должно осуществляться, пока это логическое значение установлено.Другие (более простые) пути реализации плавного движение, с использованием вода с клавиатуры с помощью sf::Keyboard (смотрите посвященную этому статью).
Член класса, ассоциируемый с этим событием, называется
event.key
и содержит код нажатого/отжатого символа, а также текущее состояние клавиш-модификаторов (alt, control, shift, system).if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Escape)
{
std::cout << "the escape key was pressed" << std::endl;
std::cout << "control:" << event.key.control << std::endl;
std::cout << "alt:" << event.key.alt << std::endl;
std::cout << "shift:" << event.key.shift << std::endl;
std::cout << "system:" << event.key.system << std::endl;
}
}
Помните, что некторые клавиши имеют специфичное значение для операционной системы, обработка этих клавиш приводит к неопределенному поведению. Например, клавиша F10 в Windows, которая меняет фокус, или клавиша F12, которая запуска дебагер при использовании Visual Studio. Эта проблема будет решена в будущих версиях SFML.
Событие MouseWheelMoved
Событие
sf::Event::MouseWheelMoved
устарело и было упразнено в SFML 2.3. Используйте MouseWheelScrolled
. Событие MouseWheelScrolled
Событие
sf::Event::MouseWheelScrolled
вызыватеся, когда колесо мыши двигается вверх, вниз или вбок (если это поддерживается мышью). Член класса, ассоциируемый с этим событием, называется
event.mouseWheelScroll
и содержит число тиков, на которое сместилось колесо, ориентацию движения колеса и текущую позицию курсора мыши.if (event.type == sf::Event::MouseWheelScrolled)
{
if (event.mouseWheelScroll.wheel == sf::Mouse::VerticalWheel)
std::cout << "wheel type: vertical" << std::endl;
else if (event.mouseWheelScroll.wheel == sf::Mouse::HorizontalWheel)
std::cout << "wheel type: horizontal" << std::endl;
else
std::cout << "wheel type: unknown" << std::endl;
std::cout << "wheel movement: " << event.mouseWheelScroll.delta << std::endl;
std::cout << "mouse x: " << event.mouseWheelScroll.x << std::endl;
std::cout << "mouse y: " << event.mouseWheelScroll.y << std::endl;
}
События MouseButtonPressed и MouseButtonReleased
События
sf::Event::MouseButtonPressed
и sf::Event::MouseButtonReleased
срабатывают, когда кнопка мыши нажата/отпущена.SFML поддерживает 5 кнопок мыши: левую, правую, среднюю (колесо мыши), экстра #1 и экстра #2 (кнопки на боковой стороне).
Член класса, ассоциируемый с этим событием, называется
event.mouseButton
и содержит код нажатой/отжатой кнопки, а также позицию курсора мыши.if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Right)
{
std::cout << "the right button was pressed" << std::endl;
std::cout << "mouse x: " << event.mouseButton.x << std::endl;
std::cout << "mouse y: " << event.mouseButton.y << std::endl;
}
}
Событие MouseMoved
Событие
sf::Event::MouseMoved
срабатывает, когда курсор мыши движется внутри окна. Это событие срабатывает, даже если окно не в фокусе. Однако, срабатывание происходит только когда курсор мыши движется только в пределах внутренней области окна (во внутреннюю облась окна не входят заголов и границы),
Член класса, ассоциируемый с этим событием, называется
event.mouseMove
и содержит позицию курсора мыши относительно окна.if (event.type == sf::Event::MouseMoved)
{
std::cout << "new mouse x: " << event.mouseMove.x << std::endl;
std::cout << "new mouse y: " << event.mouseMove.y << std::endl;
}
События MouseEntered и MouseLeft
События
sf::Event::MouseEntered
и sf::Event::MouseLeft
срабатывают, когда курсор мыши входит в облась окна или покидает ее.Член класса, ассоциируемый с этим событием, не существует.
if (event.type == sf::Event::MouseEntered)
std::cout << "the mouse cursor has entered the window" << std::endl;
if (event.type == sf::Event::MouseLeft)
std::cout << "the mouse cursor has left the window" << std::endl;
События JoystickButtonPressed и JoystickButtonReleased
События
sf::Event::JoystickButtonPressed
и sf::Event::JoystickButtonReleased
срабатывают, когда кнопка геймпада нажата/отжата. SFML поддерживает 8 джойстиков и 32 кнопки.
Член класса, ассоциируемый с этим событием, называется
event.joystickButton
и содержит идентификатор джойстика и индекс нажатой/отжатой кнопки.if (event.type == sf::Event::JoystickButtonPressed)
{
std::cout << "joystick button pressed!" << std::endl;
std::cout << "joystick id: " << event.joystickButton.joystickId << std::endl;
std::cout << "button: " << event.joystickButton.button << std::endl;
}
Событие JoystickMoved
Событие
sf::Event::JoystickMoved
срабатывает, когда стик геймпада движется.Стики джойстика, как правило, очень чувствительны, именно поэтому SFML использует порог обнаружения, чтобы избежать постоянных срабатываний
JoystickMoved
. Это пороговое значение можно изменить с помощью вызова функции Window::setJoystickThreshold
.SFML поддерживает 8 стиков джойстика: X, Y, Z, R, U, V, POV X и POV Y. Как происходит взаимодействие с геймпадом зависит от драйвера этого геймпада.
Член класса, ассоциируемый с этим событием, называется
event.joystickMove
и содержит идентификатор джойстика, имя стика и его текущую позицию (в интервале [-100, 100]).if (event.type == sf::Event::JoystickMoved)
{
if (event.joystickMove.axis == sf::Joystick::X)
{
std::cout << "X axis moved!" << std::endl;
std::cout << "joystick id: " << event.joystickMove.joystickId << std::endl;
std::cout << "new position: " << event.joystickMove.position << std::endl;
}
}
События JoystickConnected и JoystickDisconnected
События
sf::Event::JoystickConnected
и sf::Event::JoystickDisconnected
срабатывают, когда джойстик присоединяется/отсоединяется.Член класс, ассоциируемый с этим событием, называется
event.joystickConnect
и содержит идентификатор присоединенного/отсоединенного джойстика.if (event.type == sf::Event::JoystickConnected)
std::cout << "joystick connected: " << event.joystickConnect.joystickId << std::endl;
if (event.type == sf::Event::JoystickDisconnected)
std::cout << "joystick disconnected: " << event.joystickConnect.joystickId << std::endl;
Следующая статья: Работа с клавиатурой, мышью и джойстиками.