我正在用Java编写游戏,现在是Swing + JOGL-一个带有GLCanvas的JFrame。
我使用keyPressed
etc.事件(jframe.addKeyListener(...)
)处理输入,但似乎无法正常工作:
我究竟做错了什么?
有没有更好的方法来处理Java中的键盘输入?
(除非我别无选择,否则我不希望切换到另一个库,例如LWJGL …)。
为了降低依赖性,我将使用“内置”键盘处理。如果您知道自己在做什么,它就可以正常工作。我将从游戏中粘贴一些代码:
它使用自定义的重复延迟/速率来处理键重复,并且组件键盘焦点位于哪个位置都没有问题。
public class GameKeyController implements KeyEventDispatcher {
private final int MAX_REPEAT_RATE = 100; // Hz
private final LocalGame game;
private final GamingContext context;
private final Account account;
Timer keyRepeatTimer;
Map<Move, TimerTask> repeatingTasks = new EnumMap<Move, TimerTask>(Move.class);
public GameKeyController(LocalGame game, GamingContext context,
Account account) {
this.game = game;
this.context = context;
this.account = account;
}
public boolean dispatchKeyEvent(KeyEvent e) {
assert EventQueue.isDispatchThread();
int kc = e.getKeyCode();
if (e.getID() == KeyEvent.KEY_PRESSED) {
// If repeat is activated, ignore KEY_PRESSED events.
// Should actually not occur, since KEY_RELEASED *should* have been
// intercepted since last KEY_PRESSED.
if (kc == account.getInt(KC_MOVE_LEFT) && !isRepeating(LEFT)) move(LEFT);
if (kc == account.getInt(KC_MOVE_RIGHT) && !isRepeating(RIGHT)) move(RIGHT);
if (kc == account.getInt(KC_SOFT_DROP) && !isRepeating(SOFT_DROP)) move(SOFT_DROP);
// Regular moves
if (kc == account.getInt(KC_ROT_CW)) move(ROT_CW);
if (kc == account.getInt(KC_ROT_CW2)) move(ROT_CW);
if (kc == account.getInt(KC_ROT_CCW)) move(ROT_CCW);
if (kc == account.getInt(KC_ROT_CCW2)) move(ROT_CCW);
if (kc == account.getInt(KC_HARD_DROP)) move(HARD_DROP);
if (kc == account.getInt(KC_SLIDE_DROP)) move(SLIDE_DROP);
if (kc == account.getInt(KC_FULL_LEFT)) move(FULL_LEFT);
if (kc == account.getInt(KC_FULL_RIGHT)) move(FULL_RIGHT);
if (kc == account.getInt(KC_HOLD)) move(HOLD);
if (kc == account.getInt(KC_SEND_TO_ME)) useSpecial(0);
if (kc == account.getInt(KC_SEND_TO_1)) useSpecial(1);
if (kc == account.getInt(KC_SEND_TO_2)) useSpecial(2);
if (kc == account.getInt(KC_SEND_TO_3)) useSpecial(3);
if (kc == account.getInt(KC_SEND_TO_4)) useSpecial(4);
if (kc == account.getInt(KC_SEND_TO_5)) useSpecial(5);
if (kc == account.getInt(KC_SEND_TO_6)) useSpecial(6);
if (kc == account.getInt(KC_SEND_TO_7)) useSpecial(7);
if (kc == account.getInt(KC_SEND_TO_8)) useSpecial(8);
if (kc == account.getInt(KC_SEND_TO_9)) useSpecial(9);
// Reported bug: Key repeat "lags on releases", that is, the key
// continues to repeat a few ms after it has been released.
// The following two lines gives one "upper" approximation of
// when someone really wants to release the key.
if (kc == account.getInt(KC_MOVE_RIGHT)) stopRepeating(LEFT);
if (kc == account.getInt(KC_MOVE_LEFT)) stopRepeating(RIGHT);
}
if (e.getID() == KeyEvent.KEY_RELEASED) {
if (kc == account.getInt(KC_MOVE_LEFT)) stopRepeating(LEFT);
if (kc == account.getInt(KC_MOVE_RIGHT)) stopRepeating(RIGHT);
if (kc == account.getInt(KC_SOFT_DROP)) stopRepeating(SOFT_DROP);
}
return false;
}
private synchronized void stopRepeating(Move m) {
if (!isRepeating(m))
return;
repeatingTasks.get(m).cancel();
repeatingTasks.remove(m);
}
private synchronized boolean isRepeating(Move m) {
return repeatingTasks.get(m) != null;
}
private synchronized void move(Move move) {
assert EventQueue.isDispatchThread();
context.notIdleSinceStart();
PlayfieldEvent pfe = game.move(move);
// Fake wall kicks
if ((move == ROT_CW || move == ROT_CCW) &&
account.getBool(USE_FAKE_WALL_KICKS) && !pfe.pfChanged) {
// Try RIGHT and ROT, then LEFT and ROT.
Playfield pf = game.getPlayfield();
if (pf.isFakeRotPossible(true, move == ROT_CW)) {
game.move(RIGHT);
game.move(move);
} else if (pf.isFakeRotPossible(false, move == ROT_CW)) {
game.move(LEFT);
game.move(move);
}
}
// Initiate key repeats
int delay = account.getInt(KEY_REPEAT_DELAY);
int rate = account.getInt(KEY_REPEAT_RATE);
if (delay > 0 && rate > 0 && isRepeatable(move))
startRepeating(move);
}
private boolean isRepeatable(Move m) {
return m == LEFT || m == RIGHT || m == SOFT_DROP;
}
private synchronized void startRepeating(Move move) {
assert EventQueue.isDispatchThread();
if (isRepeating(move))
return;
long delay = account.getInt(KEY_REPEAT_DELAY);
int rate = account.getInt(KEY_REPEAT_RATE);
Move repeatMove = move;
if (rate >= MAX_REPEAT_RATE) {
rate = MAX_REPEAT_RATE;
repeatMove = move == LEFT ? FULL_LEFT
: move == RIGHT ? FULL_RIGHT
: move == SOFT_DROP ? SLIDE_DROP
: null; // not a repeatable move!
}
long period = (long) (1000.0 / rate);
if (move == SOFT_DROP)
delay = period;
final Move m = repeatMove;
TimerTask tt = new TimerTask() {
// Should only be executed by keyRepeatTimer thread.
public void run() {
// Remove the if-branch below and you get old school GB behavior
// With the if-branch it's more TDS-ish.
// TODO: Make this depend on an account-setting
if (m == SOFT_DROP && game.getPlayfield().isTetOnSurface()) {
stopRepeating(SOFT_DROP);
return;
}
game.move(m);
// Attempt to make it more responsive to key-releases.
// Even if there are multiple this-tasks piled up (due to
// "scheduleAtFixedRate") we don't want this thread to take
// precedence over AWT thread.
Thread.yield();
}
};
repeatingTasks.put(move, tt);
keyRepeatTimer.scheduleAtFixedRate(tt, delay, period);
}
public synchronized void init() {
if (!isInited()) {
keyRepeatTimer = new Timer("Key Repeat Timer");
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
}
}
public synchronized boolean isInited() {
return keyRepeatTimer != null;
}
public synchronized void uninit() {
if (isInited()) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
keyRepeatTimer.cancel();
keyRepeatTimer = null;
}
}
private void useSpecial(int target) {
context.notIdleSinceStart();
context.useSpecial(target);
}
}
问题内容: 我正在使用Java swing使用计算器,并且希望能够通过键盘输入数字和操作。我似乎无法正常工作。 问题答案: 我认为这是问题所在: 从JComponent.getInputMap() javadoc: 返回组件具有焦点时使用的。这是的便捷方法。 因此,按钮必须具有焦点才能正常工作。由于您正在使用计算器,因此建议您改用以下方法: JComponent.getInputMap(int c
我对java完全陌生,我想在Java中创建一个单人棋盘游戏。 我已经有很多定义游戏的类,但是对于我的问题,我将把问题限制在为我的棋盘游戏创建GUI板 我非常具体的问题是,基于以下代码: 如何在棋盘游戏中移动玩家?(类播放器存在) 提前感谢您的得体回答。因为我对java非常陌生,请清楚地解释您的答案。 这是以下代码的输出:
问题内容: 我已经用Java设计了自己的合成器,现在我想将其与Midi键盘连接。我在下面的课程搜索所有带有发射器的Midi设备。它成功找到了我的Midi键盘。我将自己的接收器添加到每个设备的每个发送器中,以便它可以接收所有可能的信息。通过阅读所有帮助文档和Java文档,我知道Transmitter将MidiEvents发送给Receiver,然后由Receiver使用send方法处理它们。因此,我
我正在使用LibGdx的java游戏,我需要你的帮助。 说明:箭头键有一个问题。让我先解释一下我的代码是如何工作的。所以在我的更新方法中,我检查是否按下了键。如果是的话,我来处理。问题是我的代码一个接一个地检查。因此,它检查的第一个箭头键优先于所有其他箭头键,因为如果按下它,它将首先被调用。前任: 顺便说一下,我的游戏是瓷砖基地。当玩家移动完1个图块后,它会再次检查箭头键输入,看看下一步需要朝哪个
包含在程序启动时启动的线程。这个线程包含一个循环,每40毫秒更新一次游戏并重新绘制()board。 备选办法B: 板创建一个摆动计时器。这个计时器的动作监听器是板本身。actionPerformed()方法每40毫秒运行一次,并更新game+repaints Board()。 谢谢