Java keylistener stutters

I make a very simple table tennis game in Java. I'm using keylistener to do this I want it, so when the user presses the right or left key on the keyboard, the pong block moves in that direction This is a simple enough task, but I found that when the user holds down the key, the block moves once, stops for a short time, and then continues to move until the user releases the key I noticed this happens when you try to hold down a letter key on the computer If I try to hold down the 'a' key, the computer will do the following:

Is there any way to disable this stuttering because it hinders the flow of my little game A quick solution would be appreciated

Solution

Don't rely on the repetition rate of the operating system It can be different for each platform, and users can customize it

Instead, timers are used to schedule events Start timer on keypressed and stop timer on keyreleased

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);
    }

}

This code has been tested on windows. The sequence of events is keypressed, keypressed, keypressed... Keyreleased

However, I think the sequence of events on MAC (or Unix) is keypressed, keyreleased, keyreleased... So I'm not sure if this code is better than your current code

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>