Проблема с таймером Java и ключевыми событиями - PullRequest
0 голосов
/ 12 апреля 2011

Я играю в тетрис, и она почти завершена. У меня проблема с KeyEvents и таймером.

My Timer вызывает actionPerformed каждые 400 мсек, которые выпадают из блока тетриса. Проблема в том, что если я нажимаю что-то с клавиатуры (вниз, влево, вправо и т. Д.), Эти команды записываются также каждые 400 миллисекунд. Как я могу сделать вызов таймера actionPerformed каждые 400 мс, но чтобы я мог нажимать всякий раз, когда и сколько раз я хочу что-то от клавиатуры, и это мгновенно распознается / реагирует на?

РЕДАКТИРОВАТЬ: Вот код, который люди просили

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 также довольно прост, так как я сначала создал текстовую версию своего Tetris, поэтому он в основном запускает текстовую версию в фоновом режиме и просто рисует ситуацию в игре.

Сама текстовая версия представляет собой матрицу с типом символов, куда я перемещаю блоки, например:

..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;

Первоначально моя игра мгновенно реагировала на команды клавиатуры, но отображала текущее состояние игры каждые 400 мс в actionPerformed (), где вызывался repaint (). Теперь мои блоки можно перемещать в любое время, когда я захочу, без «задержки», и они по-прежнему стабильно падают каждые 400 мс:)

Ответы [ 3 ]

0 голосов
/ 12 апреля 2011

Необходимо убедиться, что вы используете Swing Timer и не блокируете поток диспетчеризации событий. Скорее всего, вам нужен отдельный метод actionPerformed для обработки событий клавиш, а не для отбрасывания блока.

0 голосов
/ 12 апреля 2011

Я бы попытался уменьшить интервал таймера, чтобы сделать нажатия клавиш более отзывчивыми, и использовать счетчик, чтобы сбросить блок один раз через каждые столько интервалов.

0 голосов
/ 12 апреля 2011

Возможно, вы захотите взглянуть на связывание клавиш и его примеры внизу этой же страницы.

Взято из 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 = 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()...
...