Игра OpenGL/Gtkmm - перемещение клавиатуры

Я программирую игру в "OpenGL" и использую "Gtkmm" в качестве оконного менеджера. Я хочу использовать клавиатуру для перемещения камеры (таким образом, "кнопка ВВЕРХ" для перемещения вперед, "кнопка ВНИЗ" для перемещения назад и т. Д.)

Некоторое время назад, когда я программировал на Java, я использовал эту технику для "перемещения":
Когда приложение получило, например, сигнал "UP-key-press", оно впоследствии установило флаг "shouldMoveForward" на "true", а когда оно позже получило сигнал "UP-key-release", оно установило флаг обратно на " ложный".
И "игровой цикл" постоянно проверяется на наличие этого флага, и, если это правда, он перемещает камеру вперед, в противном случае он ничего не делает.

Так что я бы хотел использовать ту же технику в "Gtkmm". Поэтому я просто переопределил эти функции моего "Gtk:: DrawingArea":

bool Gtk::Widget::on_key_press_event(GdkEventKey* event)
bool Gtk::Widget::on_key_release_event(GdkEventKey* event)

Но проблема заключается в следующем: когда я, например, нажимаю клавишу "ВВЕРХ" и удерживаю ее в течение 5 секунд, генерируется следующая последовательность сигналов:

press  ...<little time waiting>...  release  press  release  press  release  press  release   ..........   press  release  press  release

Предыдущая ситуация возникает, когда я запускаю свою игру "под Linux".

Когда я "на Windows", это так, как я хочу, таким образом:

press  ...<little time waiting>...  press  press  press  press  press  ..........  press  press  release

Так что, похоже, это "непереносимое" решение для перемещения камеры в Gtkmm.

Так есть ли другое ("ПОРТАТИВНОЕ") решение для перемещения камеры с помощью Gtkmm в качестве оконного менеджера?

2 ответа

В этой теме описана проблема (которой нет в самой GTK+) и несколько способов ее решения.

Я только что столкнулся с функцией "автоповтор" в моей Java-игре, и я исправил ее.

Поскольку вы знаете Java, у вас не должно возникнуть проблем при переносе следующего кода:

// Keyboard
private final List<Integer> keysPressed = new LinkedList<Integer>();
private final List<Integer> keysDown = new LinkedList<Integer>();
private final List<Integer> keysRemove = new LinkedList<Integer>();

public final void keyPressed(final KeyEvent e) {
    int key = e.getKeyCode();

    // Fix AutoKeyRepeat under X11
    if (keysRemove.contains(key)) {
        keysRemove.remove(Integer.valueOf(key));
    }

    if (!keysDown.contains(key)) {
        keysDown.add(key);
        keysPressed.add(key);
    }
    e.consume();
}

public final void keyReleased(final KeyEvent e) {
    int key = e.getKeyCode();
    keysRemove.add(key);
    e.consume();
}

public final void clearKeys() {
    for (Integer key : keysRemove) {
        keysDown.remove(Integer.valueOf(key));
        if (keysPressed.contains(key)) {
            keysPressed.remove(Integer.valueOf(key));
        }
    }
    keysRemove.clear();
    keysPressed.clear();
}

Метод clearKeys вызывается в основном цикле сразу после того, как состояние игры было обновлено (проверено на ввод с клавиатуры / перемещенные объекты), трюк здесь первый, если в keyPressed. Автоматически сгенерированные ключевые события происходят в одно и то же время, поэтому почти невозможно, чтобы что-то произошло между поддельными событиями keyReleased и keyPressed. Единственный способ, которым ключ может быть в списке keyRemove, когда происходит событие keyPressed, - это фальшивое событие, поэтому в этом случае мы просто удаляем ключ из списка keyRemove.

Когда вы отпускаете ключ обычно, за ним не следует немедленное событие keyPressed, поэтому он не удаляется из списка и не обрабатывается clearKeys.

Для остальной части кода (например, проверка, нажата ли клавиша или была нажата), проверьте источник: http://github.com/BonsaiDen/Bonsai-Game-Library/blob/master/src/org/bonsai/dev/GameInput.java

Другие вопросы по тегам