草庐IT

Java KeyListener 断断续续

coder 2024-03-26 原文

我正在用 Java 制作一个非常简单的乒乓球游戏,并且我正在使用 KeyListener 进行此操作。我想要它,所以当用户按下键盘上的向右或向左键时,乒乓 block 会朝那个方向移动。这是一个足够简单的任务,但我发现当用户按住键时, block 移动一次,停止一小段时间,然后继续移动直到用户释放键。我注意到当您尝试按住计算机上的字母键时会发生这种情况。如果我尝试按住“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.

不要依赖操作系统的重复率。每个平台可能不同,用户也可以自定义。

而是使用计时器来安排事件。您在 keyPressed 上启动计时器并在 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);
    }

}

此代码已在事件顺序为 keyPressed、keyPressed、keyPressed...keyReleased 的 Windows 上进行了测试。

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

关于Java KeyListener 断断续续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16328946/

有关Java KeyListener 断断续续的更多相关文章

  1. javascript - 为什么在单独的函数中应用时转换会闪烁/断断续续(D3) - 2

    我正在处理过渡,当过渡应用于不同函数中的选择时,我注意到有些卡顿和闪烁。但是,如果转换与方法链一起应用,它会完全按照规定工作。下面是简单移动一些文本的小例子(Fiddle)。在过渡开始之前,最左边的第一个字符串神奇地传送到页面下方。最右边的第二个字符串从页面顶部到底部平滑过渡。为什么会发生这种“传送”?显然,在单独的函数中应用转换与链接它不同,但有没有办法实现这一点?比方说,我想对许多不同的对象应用相同的过渡——从不同的选择中检索——那么有没有办法在不出现这种卡顿的情况下将过渡降级为它自己的功能?varsvg=d3.select('svg');vartextElem=svg.appen

  2. javascript - jQuery 动画在 Firefox 中断断续续 - 2

    我喜欢认为我不是傻瓜,但我无法让我的jQuery水平幻灯片流畅地制作动画,尤其是在FireFox中(在Mac上)。有人有什么建议吗?动画是这样完成的:$('#lookbook').stop().animate({left:-((lookbook-1)*825)+'px'},{duration:800,complete:cap_fade(1)});示例链接:http://mayfourteenth.com/w/lookbook?preview=1 最佳答案 我已经在Windows上的Firefox、Chrome(dev)和Safari

  3. javascript - 每张幻灯片的水平 ScrollMagic 容器中的视差内容断断续续 - 2

    我有一个固定的slider,当您通过更新内部包装器的X值到达它时,它会水平移动。这部分效果很好。但是,对于每张单独的幻灯片,我希望文本具有视差效果(滚动时速度变慢-相对于当前幻灯片)。这是我设置的一个小型(简化)测试用例:https://codepen.io/michaelpumo/pen/EJgWgd不幸的是,出于某种原因,文本似乎交错并且动画不流畅。这可能是我误解了ScrollMagic的API(它对我来说是新的)。我有2个Controller,因为获得“视差”部分的唯一方法是将第二个Controller设置为vertical:false。也许与此有关?非常感谢您的帮助!JavaS

  4. javascript - 为什么慢速 jQuery 动画断断续续? - 2

    我很难用谷歌搜索这个问题,因为我能找到的大多数东西都是关于动画的,这些动画应该很快但Action很慢。我的问题是关于我想要持续时间长但仍然流畅的动画。我创建了这个jsfiddle来演示这个问题:http://jsfiddle.net/93Bqx/我试图让一个元素随着时间慢慢移动到另一个位置。但是动画非常不稳定。基本上,它归结为如下内容:$elem.animate({left:x,top:y},someLargeNumber);我想知道问题是否出在动画速度太慢以致于每一步都小于一个像素,因此它将它们四舍五入为0或1,使其看起来像是丢帧然后一次移动所有。但我不知道如何检查或解决这个问题。有

  5. javascript - Bootstrap 4 可折叠卡片 - 断断续续的动画 - 2

    我正在使用Bootstrap4并创建了一张带有.card-header和.card-block的卡片,如下所示:cardheadercardblock我希望能够单击卡片标题来切换卡片block。我试过使用Bootstrap的折叠机制(您会注意到卡片标题中的data-toggle="collapse")。它有效-但动画非常不稳定。我不知道为什么。Here'sanexampleoncodepen. 最佳答案 延迟问题:问题是.card-block类,它默认添加了1.25rem的填充。如果您从div#test-block中删除类card-

  6. Java KeyListener 断断续续 - 2

    我正在用Java制作一个非常简单的乒乓球游戏,并且我正在使用KeyListener进行此操作。我想要它,所以当用户按下键盘上的向右或向左键时,乒乓block会朝那个方向移动。这是一个足够简单的任务,但我发现当用户按住键时,block移动一次,停止一小段时间,然后继续移动直到用户释放键。我注意到当您尝试按住计算机上的字母键时会发生这种情况。如果我尝试按住“a”键,计算机将执行:a[pause]aaaaaaaaaaaaaaaa有什么办法可以消除这种卡顿,因为它妨碍了我的小游戏的流畅游戏。快速修复将不胜感激。 最佳答案 Ioriginal

  7. ios - 断断续续的全屏退出过渡 - 2

    我有一个自定义ViewController,可以通过按钮进入全屏。它通常是View的subview(嵌入)。我从嵌入进入全屏是这样的:privatefuncenterFullScreenFromEmbed(){self.proxyView=UIView(frame:self.view.frame)self.proxyView?.isHidden=trueself.proxyView?.autoresizingMask=self.view.autoresizingMaskself.view.superview?.addSubview(self.proxyView!)//Nowsetthe

  8. ios - 在 UITextView 中显示富文本文件导致断断续续/缓慢滚动 - 2

    我目前正在像这样将非英语(希伯来语)富文本文件加载到UITextView中。self.textView.attributedText=[NSAttributedString.allocinitWithFileURL:[NSBundle.mainBundleURLForResource:@"TextFile"withExtension:@"rtf"]options:nildocumentAttributes:nilerror:NULL];一切都正确加载并且文件滚动,只是在向下的过程中变得非常不稳定。我认为这是UITextView的渲染问题。是否有任何其他库或方法可以使滚动平滑。注意:UI

  9. ios - 向上滚动时 UITableView 跳动/断断续续/生涩 - 2

    我在使用UITableView时遇到了这个问题,tableView的cells高度不同,自动布局约束设置不当。当您向下滚动到tableView的底部并加载更多数据(无论使用reloadData还是insertRowsAtIndexPaths),然后向上滚动时,tableView会在某个时候开始跳动,然后一直跳动,直到您滚动到最顶层。不仅是我自己的项目,我在github(link)上发现这个项目也有同样的问题,所以你可以重现它。 最佳答案 问题解决了吗?我终于解决了这个问题,关键是计算估计高度。似乎您返回的估计越准确,跳跃/断断续续的

  10. Android 媒体播放器音频故障/断断续续仅在较新的设备上 - 2

    我有一个相当标准的媒体播放器对象,它在onCreate中启动并在我的应用程序中循环播放背景音乐。该文件不是特别大,它是一个6MB的MP3。来自onCreate:MediaPlayermp;mp=MediaPlayer.create(MainActivity.this,R.raw.lostmexicancity);mp.setLooping(true);mp.setVolume(0.4f,0.4f);mp.start();这在我的大多数测试设备上运行良好,包括旧手机、SamsungGalaxyTab210"平板电脑,甚至Nexus4。不幸的是,我在Nexus5和更新的Nexus10上遇到

随机推荐