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

В libGDX игре или приложении обработка событий позволяет получить более детальную и прежде всего хронологическую информацию о входных данных от пользователя. Обработка событий обеспечивает способ реализации взаимодействия с пользовательским интерфейсом, где важны конкретные последовательности ввода, например зажатие кнопки и затем отпускание означает, что пользователь нажал кнопку. Такое взаимодействие трудно реализовать с помощью опроса состояния клавиши.

Процессор ввода

Обработка событий осуществляется с помощью общего шаблона наблюдателя. Сначала мы должны реализовать интерфейс обработчик, называемый InputProcessor:

public class MyInputProcessor implements InputProcessor {
    @Override
    public boolean keyDown (int keycode) {
        return false;
    }

    @Override
    public boolean keyUp (int keycode) {
        return false;
    }

    @Override
    public boolean keyTyped (char character) {
        return false;
    }

    @Override
    public boolean touchDown (int x, int y, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchUp (int x, int y, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchDragged (int x, int y, int pointer) {
        return false;
    }

    @Override
    public boolean touchMoved (int x, int y) {
        return false;
    }

    @Override
    public boolean scrolled (int amount) {
        return false;
    }
}

Первые три метода позволяют перехватывать события клавиатуры:

  • keyDown(): метод вызывается, когда была нажата клавиша. Сообщает код клавиши, который можно найти в Keys классе.
  • keyUp(): метод вызывается, когда была отпущена клавиша. Сообщает код клавиши, как указано выше.
  • keyTyped(): метод вызывается, когда был сгенерирован Unicode символ при вводе с клавиатуры. keyTyped() метод может быть использован для реализации текстовых полей и аналогичных элементов пользовательского интерфейса.

Следующие три метода сообщают о событиях мыши и сенсорного экрана:

  • touchDown(): метод вызывается, когда палец коснулся экрана или была нажата кнопка мыши. Сообщает последние известные координаты, а также индекс указателя и кнопку мыши (для сенсорных экранов всегда Buttons.LEFT).
  • touchUp(): метод вызывается, когда палец был убран с экрана или была отпущена кнопка мыши. Сообщает последние известные координаты, а также индекс указателя и кнопку мыши (для сенсорных экранов всегда Buttons.LEFT).
  • touchDragged(): метод вызывается, когда палец перемещается по экрану или перемещается мышь с нажатой кнопкой. Какая была нажата кнопка – не сообщается, так как во время движения могло быть нажато несколько кнопок. В libGDX вы можете использовать Gdx.input.isButtonPressed() метод для проверки определенной кнопки.
  • touchMoved(): метод вызывается, когда мышь перемещается по экрану без нажатой кнопки. Это событие имеет значение только для персонального компьютера, и никогда не будет вызываться на устройствах с сенсорным экраном, где вы можете получить только touchDragged() событие.
  • scrolled(): метод вызывается, когда совершается прокрутка колеса мыши. Сообщает значение -1 или 1, в зависимости от направления вращения. Этот метод никогда не вызывается для устройств с сенсорным экраном.

Каждый из методов возвращает boolean значение. Почему это так, мы изучим в разделе о классе InputMultiplexer.

После реализации InputProcessor нужно сказать об этом libGDX, чтобы фреймворк мог вызвать ее, когда придет новое событие.

MyInputProcessor inputProcessor = new MyInputProcessor();
Gdx.input.setInputProcessor(inputProcessor);

С этого момента все новые события ввода будет сообщаться MyInputProcessor экземпляру.

InputAdapter

В libGDX существует InputAdapter класс, который реализует полностью интерфейс InputProcessor, возвращая false в каждом методе. Вы можете наследоваться от InputAdapter класса и переопределить необходимые методы. Также можно использовать анонимные внутренние классы.

Gdx.input.setInputProcessor(new InputAdapter(){
    public boolean touchDown(int x,int y,int pointer,int button){
        // код при нажатии
        return true; // возвращает true, сообщая, что событие было обработано
    }

    public boolean touchUp(int x,int y,int pointer,int button){
        // код при отпускании
        return true; // возвращает true, сообщая, что событие было обработано
    }
});

InputMultiplexer

Иногда хочется иметь несколько InputProcessor, например один процессор для пользовательского интерфейса, который лучше вызывать первым, а второй процессор для событий ввода, который управляет игровым миром. Для достижения этой цели можно воспользоваться InputMultiplexer классом libGDX фреймворка.

InputMultiplexer multiplexer = new InputMultiplexer();
multiplexer.addProcessor(new MyUiInputProcessor());
multiplexer.addProcessor(new MyGameInputProcessor());
Gdx.input.setInputProcessor(multiplexer);

Класс InputMultiplexer будет перенаправлять новые события первому InputProcessor. Если этот процессор вернет false из вызванного метода обработки события, это указывает на то, что событие не было обработано и мультиплексор передаст событие другому процессору. Благодаря этому механизму в libGDX, MyUiInputProcessor может обрабатывать любые события, которые исходят от элементов управления и передавать любые другие события в MyGameInputProcessor.

Пример непрерывной обработки ввода

Если вы хотите перемещать в игре персонажа, используя процессор ввода, то вы заметите, что персонаж будет двигаться только тогда, когда нажата клавиша. Для непрерывной обработки событий ввода или перемещения спрайта, вы можете добавить boolean флаг в класс персонажа.

public class Bob
{
    boolean leftMove;
    boolean rightMove;
    ...
    updateMotion()
    {
        if (leftMove)
        {
            x -= 5 * Gdx.graphics.getDeltaTime();
        }
        if (rightMove)
        {
            x += 5 * Gdx.graphics.getDeltaTime();
        }
    }
    ...
    public void setLeftMove(boolean t)
    {
        if(rightMove && t) rightMove = false;
        leftMove = t;
    }
    public void setRightMove(boolean t)
    {
        if(leftMove && t) leftMove = false;
        rightMove = t;
    }

Процессор ввода

...
    @Override
    public boolean keyDown(int keycode)
    {
        switch (keycode)
        {
        case Keys.LEFT:
            bob.setLeftMove(true);
            break;
        case Keys.RIGHT:
            bob.setRightMove(true);
            break;
        }
        return true;
    }
    @Override
    public boolean keyUp(int keycode)
    {
        switch (keycode)
        {
        case Keys.LEFT:
            bob.setLeftMove(false);
            break;
        case Keys.RIGHT:
            bob.setRightMove(false);
            break;
        }
        return true;
    }