小编典典

释放移动键时如何使矩形停止?

java

我创建了一个JFrame,它的中央有一个矩形,当我按某些键时,该矩形会移动。一切都很好,但当我松开按键时,矩形会继续前进。实际上,如果我多次按一个键,则矩形会加速。这可能是(肯定),因为在按下某个键时,我正在使用计时器来避免令人讨厌的0.5秒输入延迟。

我认为我必须在该keyReleased()方法中添加一些内容,但是我对放置在其中的内容一无所知。有小费吗?谢谢。

PS: 不要对我不使用按键绑定大吼大叫。我知道:它们更好,也可以。但目前我只关注主要的听众。

程序:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;

@SuppressWarnings ("serial")
public class GameFrame extends JComponent implements KeyListener
{
    static GameFrame gameFrame = new GameFrame();

    public int x = 350;
    public int y = 250;
    public int keyCode;

    public static void main (String[] args)
    {
        JFrame frame = new JFrame ("Java Game");
        frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
        frame.setSize (800, 600);
        frame.setResizable (false);
        frame.getContentPane().setBackground (Color.WHITE);
        frame.getContentPane().add (gameFrame);
        frame.addKeyListener (gameFrame);
        frame.setVisible (true);
    }

    @Override
    public void paintComponent (Graphics graphics)
    {
        super.paintComponent (graphics);
        graphics.setColor (Color.BLACK);
        graphics.fillRect (x, y, 100, 100);
    }

    public void keyPressed (KeyEvent event)
    {
        keyCode = event.getKeyCode();

        new Timer (100, new ActionListener()
        {
            public void actionPerformed (ActionEvent event)
            {
                if (keyCode == KeyEvent.VK_LEFT)
                {
                    x--;
                    repaint();
                }
                if (keyCode == KeyEvent.VK_RIGHT)
                {
                    x++;
                    repaint();
                }
                if (keyCode == KeyEvent.VK_UP)
                {
                    y--;
                    repaint();
                }
                if (keyCode == KeyEvent.VK_DOWN)
                {
                    y++;
                    repaint();
                }
            }
        }).start();
    }

    public void keyReleased (KeyEvent event) {}
    public void keyTyped (KeyEvent event) {}
}

阅读 213

收藏
2020-11-30

共1个答案

小编典典

  • 避免KeyListener,严重的是,它们比它们值得的麻烦更多,请改用键绑定API。如何使用键绑定

您可以通过多种方式实现这一目标。更好的方法之一是使用间接方法。也就是说,用户按下一个键,然后您举起一个标志来指示哪个键被按下,他们松开该键,然后重置该标志,表明不再按下该键。

然后,您可以使用某种更新循环根据当前处于活动状态的键来更改对象的位置。

但是,为什么听到这么多麻烦让我听到你问。当用户按下某个按键时,它们在第一次按键和重复按键通知之间存在短暂的延迟(当按键按下时,操作系统会向您发送按键事件,直到释放为止),这使动作看起来有些“错开”
”。

取而代之的是,我们引发标志并使用一个恒定的更新循环根据标志的状态对对象的状态进行更改,从而使键事件变得平滑,例如…

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test{

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        public enum HorizontalMovement {
            NONE,
            LEFT,
            RIGHT
        }

        private HorizontalMovement horizontalMovement = HorizontalMovement.NONE;

        private int xPos = 0;

        public TestPane() {
            addKeyPressedBinding("left.pressed", KeyEvent.VK_LEFT, new MoveHorizontialAction(HorizontalMovement.LEFT));
            addKeyPressedBinding("right.pressed", KeyEvent.VK_RIGHT, new MoveHorizontialAction(HorizontalMovement.RIGHT));
            addKeyReleasedBinding("left.relesed", KeyEvent.VK_LEFT, new MoveHorizontialAction(HorizontalMovement.NONE));
            addKeyReleasedBinding("right.relesed", KeyEvent.VK_RIGHT, new MoveHorizontialAction(HorizontalMovement.NONE));

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    switch (horizontalMovement) {
                        case LEFT:
                            xPos--;
                            break;
                        case RIGHT:
                            xPos++;
                            break;
                    }
                    if (xPos < 0) {
                        xPos = 0;
                    } else if (xPos + 50 > getWidth()) {
                        xPos = getWidth() - 50;
                    }
                    repaint();
                }
            });
            timer.start();

        }

        protected void addKeyPressedBinding(String name, int keyCode, Action action) {
            KeyStroke ks = KeyStroke.getKeyStroke(keyCode, 0, false);
            addKeyBinding(name, ks, action);
        }

        protected void addKeyReleasedBinding(String name, int keyCode, Action action) {
            KeyStroke ks = KeyStroke.getKeyStroke(keyCode, 0, true);
            addKeyBinding(name, ks, action);
        }

        protected void addKeyBinding(String name, KeyStroke ks, Action action) {
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(ks, name);
            am.put(name, action);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            Rectangle box = new Rectangle(xPos, (getHeight() - 50) / 2, 50, 50);
            g2d.setColor(Color.BLUE);
            g2d.fill(box);
            g2d.dispose();
        }

        protected void addKeyBinding(String left, int VK_LEFT, MoveHorizontialAction moveHorizontialAction) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        protected class MoveHorizontialAction extends AbstractAction {

            private HorizontalMovement movement;

            public MoveHorizontialAction(HorizontalMovement movement) {
                this.movement = movement;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                horizontalMovement = movement;
            }

        }

    }

}
2020-11-30