单键按下连续移动?

我正在尝试在java中创建一个程序,该程序涉及通过单键按下使对象不断移动。 Think Pacman,你按下一次然后Pacman继续上升,直到你按下另一把钥匙。 如果可能的话,我想保持代码简单。 我原来的动作(一个按键=一个动作)是这样的:

public class AL extends KeyAdapter { public void keyPressed(KeyEvent e){ int keyCode = e.getKeyCode(); if(keyCode == e.VK_A){ x -= 5; } if(keyCode == e.VK_D){ x += 5; } if(keyCode == e.VK_W){ y -= 5; } if(keyCode == e.VK_S){ y += 5; } } 

值中的x和y是椭圆的位置。 这种方法很完美,但是我希望它只在我按下一次键后继续移动,而不是必须按住键以保持运动。 我尝试了一个带有布尔参数的while循环,该参数移动时为true而不是false,但是一旦我激活循环,​​它就会冻结程序。 这是一段代码示例:

 public void keyPressed(KeyEvent e){ int keyCode = e.getKeyCode(); if(keyCode == e.VK_LEFT && moveL==false){ moveL=true; moveR=false; moveU=false; moveD=false; while(moveL){ x--; } } 

请帮我解决这个问题,我一直在努力寻找好几天。 我感谢你们给予的任何帮助。 谢谢。

基本概念围绕着“delta”或“change”值的概念。 然后,通过递增或递减状态值,将此值应用于要更改的状态。

由于Swing的性质,您无法阻止事件调度线程,否则您最终会阻止处理传入事件(例如绘制和键事件)。

同样,您不应该尝试从EDT以外的任何线程更新任何UI组件(或可能影响UI的状态变量)。

虽然有一些技巧可以应用以促进这些要求,但最简单的javax.swing.Timer是使用javax.swing.Timer ,它会在EDT内的常规基础上触发actionPerformed事件。

发生这种情况时,您按规定的数量“更新”所有元素并重新绘制屏幕。

在此处输入图像描述在此处输入图像描述

 import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.swing.AbstractAction; 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 PacManTest { public static void main(String[] args) { new PacManTest(); } public PacManTest() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new MazePane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class PacMan { private int x; private int y; private int deltaX; private int deltaY; private BufferedImage sprite; public PacMan() { try { sprite = ImageIO.read(new File("PacMan.png")); } catch (IOException ex) { ex.printStackTrace(); } } public void move(int x, int y) { deltaX = x; deltaY = y; } public void update(MazePane pane) { x += deltaX; y += deltaY; if (x + sprite.getWidth() > pane.getWidth()) { x = pane.getWidth() - sprite.getWidth(); } else if (x < 0) { x = 0; } if (y + sprite.getHeight() > pane.getHeight()) { y = pane.getHeight() - sprite.getHeight(); } else if (y < 0) { y = 0; } } public void paint(MazePane pane, Graphics2D g2d) { Graphics2D g = (Graphics2D) g2d.create(); float angle = 0; if (deltaX != 0) { angle = deltaX > 0 ? 0 : 180; } else if (deltaY != 0) { angle = deltaY > 0 ? 90 : 270; } AffineTransform t = new AffineTransform(); t.translate(x, y); t.rotate(Math.toRadians(angle), sprite.getWidth() / 2, sprite.getHeight() / 2); g.setTransform(t); g.drawImage(sprite, 0, 0, pane); g.dispose(); } } public class MazePane extends JPanel { private PacMan pacMan; public MazePane() { pacMan = new PacMan(); Timer timer = new Timer(40, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { pacMan.update(MazePane.this); repaint(); } }); timer.start(); InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW); ActionMap am = getActionMap(); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up"); im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down"); am.put("left", new MoveAction(pacMan, -4, 0)); am.put("right", new MoveAction(pacMan, 4, 0)); am.put("up", new MoveAction(pacMan, 0, -4)); am.put("down", new MoveAction(pacMan, 0, 4)); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g.create(); pacMan.paint(this, g2d); g2d.dispose(); } public class MoveAction extends AbstractAction { private int deltaX; private int deltaY; private PacMan pacMan; public MoveAction(PacMan pacMan, int deltaX, int deltaY) { this.deltaX = deltaX; this.deltaY = deltaY; this.pacMan = pacMan; } @Override public void actionPerformed(ActionEvent e) { pacMan.move(deltaX, deltaY); } } } } 

我还建议您花点时间了解Key Bindings , KeyListener遭遇焦点问题,哪些键绑定能够解决…

您需要在单独的线程中处理移动。 即:

 public class Pacman implements Runnable { public void run(){ //moving code, ie in a while loop //every move will notify the EDT: SwingUtilities.invokeLater(new Runnable(){ public void run(){ //update the Swing here - ie move Pacman } } } public void startMoving(){ new Thread(this).start(); } //more methods to set speed, direction, etc... } 

然后你在Gui类中引用一个Pacman类的实例,并通过改变pacman的参数来响应各种按键:

 public void keyPressed(KeyEvent e){ int keyCode = e.getKeyCode(); if(keyCode == e.VK_LEFT){ pacman.newDirection(LEFT); //for exmaple, enum with direction LEFT, RIGHT, UP, DOWN... } //etc... more logic } 
Interesting Posts