我一直在制作俄罗斯方块游戏,它几乎完成了。我有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也非常简单,因为我首先制作了我的俄罗斯方块的文本版本,所以它基本上在后台运行它的文本版本,只是描绘了游戏的情况。
文本版本本身是char类型矩阵,我移动块,例如:
..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;
最初我的游戏立即响应了我的键盘命令,但是在actionPerformed()中每隔400ms绘制一次游戏的当前状态,其中调用了repaint()。现在我的块可以随时移动而没有任何“延迟”,并且它们仍然每400毫秒稳定下降:)
答案 0 :(得分:0)
您可能需要查看同一页底部的Key Bindings及其示例。
通过添加新的密钥绑定添加新功能:
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 = 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()...
答案 1 :(得分:0)
您需要确保使用Swing Timer
并且不阻止事件调度线程。很可能你需要一个单独的actionPerformed
方法来处理关键事件而不是块丢弃。
答案 2 :(得分:0)
我会尝试减少定时器间隔,以使按键响应更快,并使用计数器每隔这么多间隔下拉一次。