3.2 Обработка событий

в 9:55, , рубрики: c++, game development, SFML, Локализация продуктов, обработка, перевод, Программирование, С++, события, урок

3.2 Обработка событий - 1

От переводчика: данная статья является десятой в цикле переводов официального руководства по библиотеке 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;

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

Автор: HighMem

Источник

Поделиться новостью

* - обязательные к заполнению поля