【问题标题】:Java Timer & KeyEvents problemJava Timer & KeyEvents 问题
【发布时间】:2011-04-12 11:43:04
【问题描述】:

我一直在制作俄罗斯方块游戏,它几乎完成了。我对 KeyEvents 和 Timer 有疑问。

我的计时器每 400 毫秒调用一次actionPerformed,它会下拉俄罗斯方块块。问题是,如果我按下键盘上的某些东西(下、左、右等),这些命令也会每 400 毫秒记录一次。我怎样才能让计时器每 400 毫秒调用一次 actionPerformed,但这样我就可以随时随地按多少次我想要键盘上的东西并立即识别/响应?

编辑:这里有一些类似人们问的代码

public class Game extends JPanel implements ActionListener {

public static final HashMap<Character, Color> colors = new HashMap<Character,Color>();
Timer timer;
Block kpl;
Grid gameBoard;
char[][] grid;
boolean paused = false;

public Game() {

    colors.put('P', Color.blue); colors.put('S', Color.green);
    colors.put('D', Color.pink); colors.put('L', Color.red);
    colors.put('Z', Color.orange); colors.put('A', Color.cyan);
    colors.put('T', Color.magenta);
    kpl = new Block();
    gameBoard = new Grid(21,10); // 21x10 sized gameboard
    grid = gameBoard.getGrid();
    addKeyListener(new KeyListening());
    setDoubleBuffered(true);
    setFocusable(true);
    timer = new Timer(100, this);
    timer.start();

}

@Override
public void paint(Graphics g) { // draws the current game situation
    super.paint(g);

        int height = getHeight()/grid.length;
        int width = getWidth()/grid[0].length/2;


        for (int row = 0; row < grid.length; ++row) {
            for (int column = 0; column < grid[row].length; ++column) {

                if (grid[row][column] == '.') { // if empty, paint white
                    g.setColor(Color.white);
                    g.fillRect(column*width, row*height , width, height);
                    g.setColor(Color.LIGHT_GRAY);
                    g.drawRect(column*width, row*height , width, height);
                }
                else if (grid[row][column] != '.') { // if not empty, paint with the color of the block
                    g.setColor(colors.get(grid[row][column]));
                    g.fillRect(column*width, row*height , width, height);
                    g.setColor(Color.BLACK);
                    g.drawRect(column*width, row*height , width, height);
                }
            }
        }

    Toolkit.getDefaultToolkit().sync();
    g.dispose();
}



public void actionPerformed(ActionEvent e) {
    if (!gameBoard.isFallingBlock())
        gameBoard.drop(kpl); // if not any falling blocks, drops a new block

    gameBoard.updateView(); // moves the block down
    repaint();
}

    private class KeyListening extends KeyAdapter {

    @Override
    public void keyPressed(KeyEvent e) {

        int key = e.getKeyCode();

        switch (key) {
            case KeyEvent.VK_LEFT:
                gameBoard.move("v"); // moves block left
                break;
            case KeyEvent.VK_RIGHT:
                gameBoard.move("o"); // moves block right
                break;
            case KeyEvent.VK_DOWN:
                gameBoard.updateView(); // moves block down
                break;
            case KeyEvent.VK_SPACE:
                gameBoard.move("p"); // drops the block to the bottom
                break;
            case KeyEvent.VK_UP: // rotates block
                gameBoard.move("k");
                break;
            case KeyEvent.VK_P: // makes the game pause
                if (paused) {
                    timer.start();
                    paused = false;
                    return;
                }

                timer.stop();
                paused = true;
                break;

        }

    }

}

}

由于我一直用自己的语言命名变量,因此必须稍微翻译一下变量。 GUI 也很简单,因为我首先制作了我的俄罗斯方块的文本版本,所以它基本上在后台运行它的文本版本,只是描绘游戏的情况。

文本版本本身是字符类型的矩阵,我在其中移动块,例如:

..P..
..ppp
.....
.....

已解决:

问题解决了!在来自键盘的每个命令之后,在 public void keyPressed() 中,我再次调用了 repaint() 方法,就像

        public void keyPressed(KeyEvent e) {

        int key = e.getKeyCode();
        switch (key) {
            case KeyEvent.VK_LEFT:
                gameBoard.move("v");
                repaint();
                break;

最初我的游戏会立即响应我的键盘命令,但在调用 repaint() 的 actionPerformed() 中每 400 毫秒绘制一次游戏的当前状态。现在我的积木可以随时移动而没有任何“延迟”,并且它们仍然每 400 毫秒稳定下降一次 :)

【问题讨论】:

  • 没有足够的信息来解决这个问题。那不应该发生。您必须提供有关 KeyEvents 正在发生的事情的更多信息,例如显示一个 sn-p 代码。
  • 能不能把代码贴在这里,让我们有个清晰的思路!!
  • 您尚未发布所有代码。这可能是事件延迟问题,或重绘延迟问题。把 System.out.println 放在 keyPressed(KeyEvent e) 的顶部,你能找出是什么问题吗?
  • 很抱歉给这个麻烦,但是我需要在 System.out.println() 里面放什么?或者你真的是指没有参数的 println() ?如果是这样,该怎么办?这就是 Game 类的全部代码,当然还有更多的类是游戏逻辑所在的。编辑:当我将计时器设置为 1000 毫秒并将我的块向左移动时,它会及时打印 println(),但会以 1000 毫秒的延迟采取行动。不知道这是不是你的意思,但以防万一写在这里

标签: java swing timer keyevent


【解决方案1】:

您需要确保您使用的是 Swing Timer 并且没有阻塞事件调度线程。您很可能需要一个单独的 actionPerformed 方法来处理关键事件,而不是块丢弃。

【讨论】:

    【解决方案2】:

    您可能想查看同一页底部的Key Bindings 及其示例。

    取自tips4java blog

    通过添加新的键绑定来添加新功能:

    Action action = new AbstractAction() {...};
    String keyStrokeAndKey = "control Z";
    KeyStroke keyStroke = KeyStroke.getKeyStroke(keyStrokeAndKey);
    component.getInputMap(...).put(keyStroke, keyStrokeAndKey);
    component.getActionMap().put(keyStrokeAndKey, action);
    

    通过替换现有绑定的 Action 来更改现有功能:

    Action action = new AbstractAction() {...};
    KeyStroke keyStroke = KeyStroke.getKeyStroke("control Z");
    InputMap im = component.getInputMap(...);
    component.getActionMap().put(im.get(keyStroke), action);
    

    使用不同的 KeyStroke 共享一个动作:

    KeyStroke existingKeyStroke = KeyStroke.getKeyStroke("ENTER");
    KeyStroke addedKeyStroke = KeyStroke.getKeyStroke("control Z");
    InputMap im = component.getInputMap(...);
    im.put(addedKeyStroke, im.get(existingKeyStroke));
    

    删除键绑定:

    KeyStroke remove = KeyStroke.getKeyStroke(...);
    InputMap im =component.getInputMap(...);
    im.put(remove, "none");
    

    请注意,以上示例用于将绑定添加到单个组件。要在框架或对话框级别添加绑定,您需要使用根窗格的 InputMap 和 ActionMap:

    frame.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)...
    frame.getRootPane().getActionMap()...
    

    【讨论】:

      【解决方案3】:

      我会尝试减少计时器间隔以使按键响应更快,并使用计数器每隔这么多间隔放下一次块。

      【讨论】:

      • 这只是一个没有解决真正问题的hack。
      • @Robin 这根本不是 hack!事实上,大多数游戏(包括是的,俄罗斯方块)都是以这种方式运行的。我什至会说提问者的“解决方案”是真正的黑客。每次按键都重新绘制游戏画面,确认。
      • 这不是在 ZX Spectrum 上编程。我想计算机很有能力在每次按键时重新绘制屏幕。
      猜你喜欢
      • 2012-07-10
      • 2013-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多