Обрабатывать несколько нажатий клавиш, игнорируя повторные нажатия клавиш
Я задал это в разделе комментариев другого вопроса (> Как мне обрабатывать одновременные нажатия клавиш в Java?), И мне было предложено сделать новый вопрос в целом.
Моя проблема в том, что когда я создаю ArrayList нажатий клавиш, они не удаляются достаточно быстро с помощью события keyReleased, если пользователь удерживает клавиши. Я хочу, чтобы движение было с "asdf" и севером, востоком, югом, западом, северо-востоком... и т. Д.
Вот мой код для обоих событий:
@Override
public void keyPressed(KeyEvent e) {
if(chatTextField.isFocusOwner() == true){
//do nothing - don't walk
} else {
logger.debug("Key Pressed: " + e.getKeyChar());
lastKey = keysPressed.get(keysPressed.size()-1);
for (String key : keysPressed){
if (!key.contains(String.valueOf(e.getKeyChar())) && !lastKey.contains(String.valueOf(e.getKeyChar()))){
keysPressed.add(String.valueOf(e.getKeyChar()));
System.out.println("ADDED: " + keysPressed);
}
}
String keysList = keysPressed.toString();
if (keysList.contains("w")){
if (keysList.contains("d")){
requestCharacterMove("NorthEast");
} else if(keysList.contains("a")){
requestCharacterMove("NorthWest");
} else{
requestCharacterMove("North");
}
} else if (keysList.contains("s")){
if (keysList.contains("d")){
requestCharacterMove("SouthEast");
} else if(keysList.contains("a")){
requestCharacterMove("SouthWest");
} else{
requestCharacterMove("South");
}
} else if (keysList.contains("d")){
requestCharacterMove("East");
} else if (keysList.contains("a")){
requestCharacterMove("West");
}
}
}
@Override
public void keyReleased(KeyEvent e) {
if(chatTextField.isFocusOwner() == true){
//do nothing - don't walk
} else {
logger.debug("Key Released: " + e.getKeyChar());
for (String key : keysPressed){
if (key.contains(String.valueOf(e.getKeyChar()))){
keysPressed.remove(String.valueOf(e.getKeyChar()));
System.out.println("REMOVED: " + keysPressed);
}
}
}
}
@Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
Пока я не добавил туда второй чек через переменную lastKey(String), созданная пирамида была огромной. Даже с этой второй проверкой список увеличивается и почти всегда содержит два-три дубликата. Любая помощь в этом была бы великолепна, так как мой персонаж движется неловко.:(
Кроме того, любой способ удалить повторяющиеся преобразования в char, string, arrayList был бы полезен, так как я нервничаю, я использовал слишком много типов для чего-то "простого".
3 ответа
Ваше мнение о том, что вещи обрабатываются медленно, скорее всего, вызвано множеством операторов System.out.println().
Ваша проблема в том, что вы не получаете диагонального движения, связана с вашей несколько ошибочной логикой проверки - вместо явной проверки, если (например) нажаты клавиши A и B, просто проверьте их независимо - клавиша A перемещает символ в одном направлении, B - в другом, В целом (например), перемещая WEST и NORTH, вы фактически перемещаете NORTHWEST.
Вместо списка нажатых клавиш вы можете использовать java.util.BitSet и просто установить бит для каждой нажатой клавиши. Это также должно значительно уменьшить объем кода, который нужно написать (keyPressed просто устанавливает бит, указанный кодом ключа, keyReleased очищает его). Чтобы проверить, нажата ли клавиша, вы спрашиваете BitSet, а затем установлен ли бит для кода.
РЕДАКТИРОВАТЬ: Пример использования BitSet вместо списка
public class BitKeys implements KeyListener {
private BitSet keyBits = new BitSet(256);
@Override
public void keyPressed(final KeyEvent event) {
int keyCode = event.getKeyCode();
keyBits.set(keyCode);
}
@Override
public void keyReleased(final KeyEvent event) {
int keyCode = event.getKeyCode();
keyBits.clear(keyCode);
}
@Override
public void keyTyped(final KeyEvent event) {
// don't care
}
public boolean isKeyPressed(final int keyCode) {
return keyBits.get(keyCode);
}
}
Я сделал пример реализации KeyListener, чтобы вы могли использовать его как есть. Когда вам нужно узнать, нажата ли клавиша, просто используйте isKeyPressed(). Вам нужно решить, предпочитаете ли вы использовать необработанный код ключа (как я) или использовать ключевой символ (как вы в настоящее время). В любом случае вы видите, как при использовании класса BitSet количество кода для записи ключей уменьшается до нескольких строк:)
В качестве альтернативы, эта игра использует цифровую клавиатуру для реализации каждого (полу) кардинального направления одним нажатием клавиши. Расположение по умолчанию показано в разделе " Дизайн ". Клавиши могут быть индивидуально переназначены для сопоставления аналогичной розетки в любом месте клавиатуры.
Похоже, вы неправильно обрабатываете потоки в Java. Существует три потока (минимум) для любой программы Java. Это основной поток программы, поток рассылки событий и еще один, который я не могу вспомнить сейчас.
Всякий раз, когда вы получаете событие, оно доставляется вам специальным потоком (я считаю, что это поток рассылки событий, но это не главное). Вам не разрешено делать в этом потоке что-либо (что занимает много времени), которое замораживает ваш ввод и заставляет вас пропускать события, что делает Java безразличным. Итак, что случилось, вы сломали систему событий в Java. То, что вы должны сделать, это сохранить результат в каком-то буфере, что является быстрым действием, которое вы можете ожидать от события, а затем оно будет обработано позже, как я опишу.
[В сторону: забавное приложение - сделать простой графический интерфейс, и при нажатии кнопки ждать вызова в течение 5 секунд. Весь ваш графический интерфейс будет зависать до тех пор, пока не закончится задержка!]
У вас должен быть другой поток, работающий на стороне (вероятно, ваш основной поток). Он запустит какой-то цикл, который контролирует кадры в вашей программе, выполняя один раз за игровой цикл. После каждого цикла этот поток считывает результаты, хранящиеся во входном буфере, и обрабатывает их. Теория, лежащая в основе этого, проста, но выполнение может быть немного запутанным, потому что вам нужно будет убедиться, что входные события не пропущены или прочитаны более одного раза. В любом случае, удачи в вашей игре!