当前位置: 首页 > 面试题库 >

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

吕志诚
2023-03-14
问题内容

我创建了一个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) {}
}

问题答案:
  • 避免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;
            }

        }

    }

}


 类似资料:
  • 我有一个名为“DisplayPanel”的类(它扩展了JPanel),我在那里画了一个正方形,它来自一个名为“square”的类(它扩展了JComponent)。如何使用键在JPanel中移动矩形? 正方形类有通常的绘制方法: “squarishThing”是一个普通矩形: 问题是:与“游戏库”不同,尝试“手动”做这样的事情是相当令人困惑的。我不知道“while循环”去哪里了。我试图在显示面板中放

  • 我有两个矩形:红色和绿色。对于它们中的每一个,我有以下信息: 中心点( 和 坐标)。 旋转角度 宽度和高度 矩形将始终以正坐标移动。编辑:没有坐标可以是负的:矩形总是位于正坐标。因此,中心永远不会是(0,0)。 问题 我有一个起始位置。为了简化示例,假设我的红色和绿色矩形的位置如下: 现在,我使用0º和90º之间的角度φ旋转红色矩形。但是,绿色矩形需要旋转并保持其相对于红色矩形的位置。绿色矩形不仅

  • 我对java中的JFrames和图形非常陌生。我的长期目标是创建一个RayCast游戏世界。下面的代码是我第一次在jframe中以其坐标移动矩形。当用户按下箭头键时,坐标会发生变化。然而,似乎有些问题,因为当我使用该程序时,矩形只会被绘制并创建一条路径。我想在坐标的位置画一个矩形。 请解释我做错了什么。提前谢谢你帮助我!

  • 问题内容: 我正在尝试创建一个简单游戏的开始。我要做的第一件事是将图形导入到我的代码中,然后在屏幕上移动它。我能够在屏幕上画一个球并四处移动,但是当我从文件导入图形时,无法四处移动。我想念什么或做错什么? 我的司机是在另一个班级,如下所示: 问题答案: 这里有两个大问题: 您正在从中读取文件。 永远 不要这样做,因为这会不必要地减慢绘图速度。可能在构造函数中读取一次图像,然后在图形中使用存储的im

  • 问题内容: 目前,每次按键时,精灵仅移动1个像素。按住左右键时,如何使水暖工精灵不断移动? 问题答案: 您可以使用pygame.key.get_pressed来做到这一点。 例:

  • http://jsfiddle.net/genome314/4Hm8X/ 代码问题:如果您按住箭头键并查看控制台 - 每次按键后键都会触发。此外,按住箭头键后,对象停止移动。 为什么在这种情况下这是一个问题:我希望每次发射箭头键时方块都移动,然后在发射键时方块停止。 预期效果:我想按住一个键来移动盒子,然后当我放开这个键的时候它就停止移动。 这是可以实现的吗?如果是这样,大致如何?如果没有,是否有