От переводчика: данная статья является десятой в цикле переводов официального руководства по библиотеке SFML. Прошлую статью можно найти тут. Данный цикл статей ставит своей целью предоставить людям, не знающим язык оригинала, возможность ознакомится с этой библиотекой. SFML — это простая и кроссплатформенная мультимедиа библиотека. SFML обеспечивает простой интерфейс для разработки игр и прочих мультимедийных приложений. Оригинальную статью можно найти тут. Начнем.

Оглавление:
0.1 Вступление

1. Приступая к работе

  1. SFML и Visual Studio
  2. SFML и Code::Blocks (MinGW)
  3. SFML и Linux
  4. SFML и Xcode (Mac OS X)
  5. Компиляция SFML с помощью CMake

2. Модуль System

  1. Обработка времени
  2. Потоки
  3. Работа с пользовательскими потоками данных

3. Модуль Window

  1. Открытие и управление окнами
  2. Обработка событий
  3. Работа с клавиатурой, мышью и джойстиками
  4. Использование OpenGL

4. Модуль Graphics

  1. Рисование 2D объектов
  2. Спрайты и текстуры
  3. Текст и шрифты
  4. Формы
  5. Проектирование ваших собственных объектов с помощью массивов вершин
  6. Позиция, вращение, масштаб: преобразование объектов
  7. Добавление специальных эффектов с шейдерами
  8. Контроль 2D камеры и вида

5. Модуль Audio

  1. Проигрывание звуков и музыки
  2. Запись аудио
  3. Пользовательские потоки аудио
  4. Спатиализация: звуки в 3D

6. Модуль Network

  1. Коммуникация с использованием сокетов
  2. Использование и расширение пакетов
  3. Веб-запросы с помощью HTTP
  4. Передача файлов с помощью 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, содержащему символ 'ê'. Это работает для всех методов ввода, предоставленным операционной системой.

Это событие обычно используется для отлова пользовательского ввода в текстовое поле.

Член класса, ассоциируемый с этим событием, называется 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;

Следующая статья: Работа с клавиатурой, мышью и джойстиками.