我在
java中制作一个非常简单的乒乓球游戏,我正在使用KeyListener进行此操作.我想要它,所以当用户按下键盘上的右或左键时,pong块就会向那个方向移动.这是一个足够简单的任务,但我发现当用户按住键时,块移动一次,停止一小段时间,然后继续移动直到用户释放键.我注意到当你试图在计算机上按住一个字母键时会发生这种情况.如果我尝试按住’a’键,计算机将执行以下操作:
a [pause] aaaaaaaaaaaaaaaa
解决方法
I originally had an answer about Key Bindings,but after a little testing I found that they still had the same stutter problem.
不要依赖操作系统的重复率.对于每个平台,它可以是不同的,并且用户也可以对其进行定制.
而是使用Timer来安排事件.在keyPressed上启动Timer并在keyReleased上停止Timer.
import java.awt.*; import java.awt.event.*; import java.net.*; import java.util.Map; import java.util.HashMap; import javax.imageio.ImageIO; import javax.swing.*; public class KeyboardAnimation implements ActionListener { private final static String PRESSED = "pressed "; private final static String RELEASED = "released "; private final static Point RELEASED_POINT = new Point(0,0); private JComponent component; private Timer timer; private Map<String,Point> pressedKeys = new HashMap<String,Point>(); public KeyboardAnimation(JComponent component,int delay) { this.component = component; timer = new Timer(delay,this); timer.setInitialDelay( 0 ); } public void addAction(String keyStroke,int deltaX,int deltaY) { // InputMap inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); InputMap inputMap = component.getInputMap(); ActionMap actionMap = component.getActionMap(); String pressedKey = PRESSED + keyStroke; KeyStroke pressedKeyStroke = KeyStroke.getKeyStroke( pressedKey ); Action pressedAction = new AnimationAction(keyStroke,new Point(deltaX,deltaY)); inputMap.put(pressedKeyStroke,pressedKey); actionMap.put(pressedKey,pressedAction); String releasedKey = RELEASED + keyStroke; KeyStroke releasedKeyStroke = KeyStroke.getKeyStroke( releasedKey ); Action releasedAction = new AnimationAction(keyStroke,RELEASED_POINT); inputMap.put(releasedKeyStroke,releasedKey); actionMap.put(releasedKey,releasedAction); } private void handleKeyEvent(String keyStroke,Point moveDelta) { // Keep track of which keys are pressed if (RELEASED_POINT == moveDelta) pressedKeys.remove( keyStroke ); else pressedKeys.put(keyStroke,moveDelta); // Start the Timer when the first key is pressed if (pressedKeys.size() == 1) { timer.start(); } // Stop the Timer when all keys have been released if (pressedKeys.size() == 0) { timer.stop(); } } // Invoked when the Timer fires public void actionPerformed(ActionEvent e) { moveComponent(); } // Move the component to its new location private void moveComponent() { int componentWidth = component.getSize().width; int componentHeight = component.getSize().height; Dimension parentSize = component.getParent().getSize(); int parentWidth = parentSize.width; int parentHeight = parentSize.height; // Calculate new move int deltaX = 0; int deltaY = 0; for (Point delta : pressedKeys.values()) { deltaX += delta.x; deltaY += delta.y; } // Determine next X position int nextX = Math.max(component.getLocation().x + deltaX,0); if ( nextX + componentWidth > parentWidth) { nextX = parentWidth - componentWidth; } // Determine next Y position int nextY = Math.max(component.getLocation().y + deltaY,0); if ( nextY + componentHeight > parentHeight) { nextY = parentHeight - componentHeight; } // Move the component component.setLocation(nextX,nextY); } private class AnimationAction extends AbstractAction implements ActionListener { private Point moveDelta; public AnimationAction(String keyStroke,Point moveDelta) { super(PRESSED + keyStroke); putValue(ACTION_COMMAND_KEY,keyStroke); this.moveDelta = moveDelta; } public void actionPerformed(ActionEvent e) { handleKeyEvent((String)getValue(ACTION_COMMAND_KEY),moveDelta); } } public static void main(String[] args) { JPanel contentPane = new JPanel(); contentPane.setLayout( null ); Icon dukeIcon = null; try { dukeIcon = new ImageIcon( "dukewavered.gif" ); // dukeIcon = new ImageIcon( ImageIO.read( new URL("http://duke.kenai.com/iconSized/duke4.gif") ) ); } catch(Exception e) { System.out.println(e); } JLabel duke = new JLabel( dukeIcon ); duke.setSize( duke.getPreferredSize() ); duke.setLocation(100,100); contentPane.add( duke ); KeyboardAnimation navigation = new KeyboardAnimation(duke,24); navigation.addAction("LEFT",-3,0); navigation.addAction("RIGHT",3,0); navigation.addAction("UP",-3); navigation.addAction("DOWN",3); navigation.addAction("A",-5,0); navigation.addAction("S",5,0); navigation.addAction("Z",-5); navigation.addAction("X",5); navigation.addAction("V",5); JFrame frame = new JFrame(); frame.setDefaultCloSEOperation( JFrame.EXIT_ON_CLOSE ); // frame.getContentPane().add(new JTextField(),BorderLayout.SOUTH); frame.getContentPane().add(contentPane); frame.setSize(600,600); frame.setLocationRelativeTo( null ); frame.setVisible(true); } }
此代码在Windows上进行了测试,其中事件的顺序为keyPressed,keyPressed,keyPressed … keyReleased.
但是,我认为在Mac(或Unix)上事件的顺序是keyPressed,keyReleased,keyReleased ……所以我不确定这段代码是否比你当前的代码更好用.