События

Введение

Этот урок представляет подробный перечень событий окна. Он описывает их и показывает как можно и нельзя использовать события.

Тип sf::Event

Прежде чем перейти к событиям, важно понять что из себя представляет тип sf::Event и как правильно им пользоваться. sf::Event — это объединение, а значит, что только один из членов этого объединения допустим (т.е. существует) в данный момент времени (все элементы объединения хранятся в одной области памяти; за подробностями — в любой учебник по с++). Допустимым членом является тот, который соответствует типу события, например event.key для события KeyPressed. Попытка считывания другого члена приведёт к неопределённому поведению (скорее всего вы получите недопустимые или случайные значения). Поэтому никогда не пытайтесь использовать член события, который не соответствуют типу этого события.

Экземпляры sf::Event в качестве аргументов принимаются методом pollEvent() (или waitEvent()) класса sf::Window. Только две эти функции могут предоставить допустимые события, любая попытка использовать sf::Event без предварительного успешного вызова pollEvent() (или waitEvent()) приведёт к такому же неопределённому поведению, о котором говорилось выше.

Для большей ясности, вот так выглядит типичный цикл с использованием событий:

sf::Event event;

// пока имеются события в очереди...
while (window.pollEvent(event))
{
    // проверка типа события...
    switch (event.type)
    {
        // закрытие окна
        case sf::Event::Closed:
            window.close();
            break;

        // нажатие клавиш
        case sf::Event::KeyPressed:
            ...
            break;

        // мы не обрабатываем другие типы событий
        default:
            break;
    }
}

Перечитайте ещё разок то, что написано выше, важно что бы это хорошо отложилось у вас в недопонимание объединения http://www.sfml-dev.org/documentation/2.1/classsf_1_1Event.php часто вызывает проблемы у программистов.

Хорошо, теперь мы можем рассмотреть какие события поддерживает SFML, что они из себя представляют и как использовать их должным образом.

Событие закрытия (Closed)

Событие sf::Event::Closed срабатывает, когда пользователь хочет закрыть окно любым из способов, предоставляемых ОС (кнопкой «закрыть», сочетанием клавиш и т.д.). Это событие только представляет запрос на закрытие окна, физически оно не закрывается.

Самым распространённым ответом на этот запрос будет вызов window.close(), который как раз и выполнит фактическое закрытие окна. Но в то же время, вы можете сделать ещё что-нибудь, например сохранить текущее состояние приложения или задать вопрос пользователю («Вы уверены что хотите выйти?»). Если вы ничего не сделаете, окно останется открытым.

И ещё, нет объектов связанных с этим событием в объединении sf::Event.

if (event.type == sf::Event::Closed)
    window.close();

Событие изменения размера (Resized)

Событие sf::Event::Resized срабатывает, когда окно меняет свои размеры в результате действий пользователя или программно, вызовом window.setSize().

Вы можете использовать это событие для настройки параметров визуализации: точки просмотра (viewport) при использовании 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 срабатывают когда окно выходит из фокуса или его получает (имеется ввиду переключение между окнами, когда окно то активно, то неактивно). Когда окно не в фокусе, оно не получает события клавиатуры.

Это событие можно использовать, если вы хотите приостанавливать игру, когда окно делается неактивным.

Объектов связанных с этим событием в объединении sf::Event нет.

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, он содержит введённый символ в формате Юникод. Вы можете поместить его непосредственно в sf:String или же в char, но только убедившись предварительно, что символ находится в диапазоне ASCII (0 — 127).

if (event.type == sf::Event::TextEntered)
{
    if (event.text.unicode < 128)
        std::cout << "ASCII character typed: " << static_cast(event.text.unicode) << std::endl;
}

Заметьте, что так как некоторые непечатаемые  символы (например backspace) являются частью стандарта Юникод, то они генерируют вызов этого события. В большинстве случаев, вам следует фильтровать эти символы.

Многие программисты используют событие KeyPressed для получения пользовательского ввода и начинают реализовывать сумасшедшие алгоритмы, которые пытаются интерпретировать все возможные комбинации клавиш для выдачи правильных символов. Не делайте так!

События нажатия и отпускания клавиши (KeyPressed и KeyReleased)

События sf::Event::KeyPressed и sf::Event::KeyReleased вызываются, когда нажимается или отпускается клавиша на клавиатуре.

Если клавиша удерживается, будет генерироваться несколько событий KeyPressed, с учётом задержки по умолчанию в ОС (это такая же задержка как и при наборе текста в текстовом редакторе). Для отключения повторного вызова событий можно вызвать функцию window.setKeyRepeatEnabled(false). Очевидно, что события KeyReleased не могут генерироваться повторно.

Это событие используется, если вы хотите вызвать действие только один раз, когда клавиша нажата или отпущена, например прыжок персонажа клавишей «пробел» или выход при нажатии клавиши «escape».

Иногда, люди пытаются реализовать плавное движение реагируя непосредственно на 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 срабатывает, когда колесо мышки перемещается вверх или вниз.

Объект связанный с этим событием — event.mouseWheel, он содержит количество отсчётов перемещения  колеса, а так же текущее положение курсора мышки.

if (event.type == sf::Event::MouseWheelMoved)
{
    std::cout << "wheel movement: " << event.mouseWheel.delta << std::endl;
    std::cout << "mouse x: " << event.mouseWheel.x << std::endl;
    std::cout << "mouse y: " << event.mouseWheel.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 срабатывают при введении курсора мыши в пределы окна и выведении его из этих пределов.

Объектов связанных с этим событием в объединении sf::Event нет.

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 срабатывает, когда двигается мини-джойстик (stick).

Мини-джойстики, как правило, очень чувствительны, поэтому SFML использует порог обнаружения что бы избежать спама в виде кучи событий JoystickMoved. Этот порог может быть изменён с помощью функции Window::setJoystickThreshold(), если хотите получать больше или меньше событий мини-джойстика.

SFML поддерживает 8 джойстиковых осей: X, Y, Z, R, U, V, POV X and 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;

 

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Капча * Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.