Игра 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