键侦听器在单击画布后停止工作



我有一个简单的KeyHandler

public class KeyHandler implements KeyListener {
private final Set<Integer> keyEvents = new LinkedHashSet<>();
public Set<Integer> pressedKeys() {
return keyEvents;
}
@Override
public void keyPressed(KeyEvent e) {
keyEvents.add(e.getKeyCode());
}
@Override
public void keyReleased(KeyEvent e) {
keyEvents.remove(e.getKeyCode());
}
@Override
public void keyTyped(KeyEvent e) {
}
}

添加到JFrame
frame.addKeyListener(keyListener);

休息可能是无关紧要的,但我正在将相同的实例传递给KeyBinder

public class KeyBinder {
private final Map<Integer, GameEvent> bindings = new HashMap<>();
private final KeyHandler keyHandler;
public KeyBinder(KeyHandler keyHandler) {
this.keyHandler = keyHandler;
bindings.put(KeyEvent.VK_A, MoveEvent.MOVE_LEFT);
bindings.put(KeyEvent.VK_D, MoveEvent.MOVE_RIGHT);
bindings.put(KeyEvent.VK_S, MoveEvent.MOVE_DOWN);
bindings.put(KeyEvent.VK_W, MoveEvent.MOVE_UP);
}
public List<GameEvent> mapEvents() {
final var events = new ArrayList<GameEvent>();
keyHandler.pressedKeys().forEach(key -> events.add(bindings.get(key)));
return events;
}
}

然后,我将这些GameEvents传递到实例Player让他移动

@Override
public void update(java.util.List<GameEvent> events) {
events.forEach(this::handleEvent);
}
private void handleEvent(GameEvent event) {
if (event instanceof MoveEvent) {
updatePosition((MoveEvent) event);
}
}
private void updatePosition(MoveEvent event) {
switch (event) {
case MOVE_UP -> position = new Position(position.getX(), position.getY() - speed);
case MOVE_DOWN -> position = new Position(position.getX(), position.getY() + speed);
case MOVE_RIGHT -> position = new Position(position.getX() + speed, position.getY());
case MOVE_LEFT -> position = new Position(position.getX() - speed, position.getY());
}
}

如果我运行应用程序的单个实例,它工作得很好。但是,由于这是打算在线游戏,因此我想同时运行 2 个实例进行测试。不幸的是,我开始第二个实例,我的KeyHandler在其中任何一个都不再工作,它只是不记录任何KeyEvents.我知道我的应用程序正在运行,因为我的服务器应用程序不断从两个客户端接收数据。

编辑:

我刚刚意识到还有其他问题。KeyHandler单击画布后停止工作...我什至不需要我的应用程序的第二个实例。这是我用来绘制东西的JFrameCanvas的代码......

public class Display {
private JFrame frame;
private Canvas canvas;

public Display(KeyListener keyListener) {
initFrame(keyListener);
initCanvas();
frame.add(canvas);
frame.pack();
}

private void initFrame(KeyListener keyListener) {
frame = new JFrame(GameConfig.TITLE);
frame.setSize(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.addKeyListener(keyListener);
}

private void initCanvas() {
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT));
canvas.setMaximumSize(new Dimension(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT));
canvas.setMinimumSize(new Dimension(GameConfig.SCREEN_WIDTH, GameConfig.SCREEN_HEIGHT));
}

public Canvas getCanvas() {
return canvas;
}
}

keylistener 不侦听任何key事件的原因是,keyListeners 仅在组件具有焦点时才起作用。似乎当您单击画布时,画布现在是焦点的所有者,因此框架不再聚焦。

通常,我建议为此使用键绑定。键绑定可以侦听键事件,即使组件未聚焦。但是,如果您想继续使用 KeyListeners,这里有两个解决方案:

将焦点侦听器添加到框架。

frame.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {}
public void focusLost(FocusEvent e) {frame.requestFocus();}
});

禁用画布的可聚焦性。

canvas.setFocusable(false);

不建议使用这些解决方案,但它应该适合您的情况。

最新更新