Java KeyListener 口吃 [英] Java KeyListener stutters

查看:33
本文介绍了Java KeyListener 口吃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用 Java 制作一个非常简单的乒乓球游戏,并且我正在使用 KeyListener 进行此操作.我希望这样当用户按下键盘上的向左或向右键时,乒乓球块就会朝那个方向移动.这是一个足够简单的任务,但我发现当用户按住键时,块移动一次,停止一小段时间,然后继续移动直到用户释放键.我注意到当您尝试按住计算机上的字母键时会发生这种情况.如果我尝试按住a"键,计算机将执行以下操作:

I'm making a very simple pong game in java and I'm doing this using KeyListener. I want it so when the user presses the right or left keys on the keypad, the pong block goes in that direction. This is a simple enough task, but what I'm finding out is that when the user holds down the key, the block moves once, stops for a short time, then continues moving until the user releases the key. I notice this happens when you try to hold down a letter key on a computer. If I try to hold down the 'a' key, the computer will do:

[停顿] aaaaaaaaaaaaaaa

a [pause] aaaaaaaaaaaaaaaa

有什么办法可以禁用这种卡顿,因为它妨碍了我的小游戏的流畅游戏体验.快速修复将不胜感激.

Is there someway to disable this stutter, because it is getting in the way of smooth gameplay for my little game. A quick fix would be deeply appreciated.

推荐答案

我最初有一个关于 Key Bindings 的答案,但经过一些测试后我发现他们仍然有同样的口吃问题.

I originally had an answer about Key Bindings, but after a little testing I found that they still had the same stutter problem.

不要依赖操作系统的重复率.每个平台都可能有所不同,用户也可以对其进行自定义.

Don't rely on the repeat rate of the OS. It can be different for every platform and a user may also customize it.

改为使用计时器来安排事件.您在 keyPressed 上启动 Timer,在 keyReleased 上停止 Timer.

Instead use a Timer to schedule the event. You start the Timer on a keyPressed and stop the 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",    0, -3);
        navigation.addAction("DOWN",  0,  3);

        navigation.addAction("A", -5,  0);
        navigation.addAction("S",  5,  0);
        navigation.addAction("Z",  0, -5);
        navigation.addAction("X",  0,  5);
        navigation.addAction("V",  5,  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.

This code was tested on Windows where the order of events is keyPressed, keyPressed, keyPressed... keyReleased.

但是,我认为在 Mac(或 Unix)上,事件的顺序是 keyPressed、keyReleased、keyPressed、keyReleased...所以我不确定这段代码是否会比你当前的代码更好.

However, I think on a Mac (or Unix) the order of events is keyPressed, keyReleased, keyPressed, keyReleased... So I'm not sure if this code would works any better than your current code.

这篇关于Java KeyListener 口吃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆