2016-12-01 125 views
0

我正在做一个蛇游戏,我希望我的蛇一旦按下一个键就会不断移动。所以,我按下了向下键,即使释放了键,它也会继续移动。现在,它只是在按住键的同时移动。如何使用箭头键保持对象移动?

public void keyPressed(KeyEvent e) { 
     if (e.getKeyCode() == KeyEvent.VK_DOWN) { 
      mySegment[0].moveSouth(); 
      repaint(); 
     } 
    else if (e.getKeyCode() == KeyEvent.VK_UP) { 
     mySegment[0].moveNorth(); 
     repaint(); 
    } 
    else if(e.getKeyCode() == KeyEvent.VK_LEFT){ 
     mySegment[0].moveWest(); 
     repaint(); 
    } 
    else if (e.getKeyCode() == KeyEvent.VK_RIGHT){ 
     mySegment[0].moveEast(); 
     repaint(); 
    } 

    for (int a = 0; a < 10; a++) { 
     if (myFruit[a].distance (mySegment[0].getX(), mySegment[0].getY())     
     <= 20) { 
      myFruit[a].hide(); 
     } 
    } 

的“mySegment [0]”是蛇,而“moveSouth”或任何方向只是移动它在directin

+0

让它调用一个循环移动直到被中断的方法。 – DejaVuSansMono

回答

0

使用“游戏循环”到驱动动画5个像素。由于这看起来可能是一个Swing或AWT GUI,那么最好的办法就是使用Swing Timer - 请查看tutorial。要点在于,在定时器的ActionListener中,您可以增加蛇的位置,根据按键的状态改变它的方向。

我会用一个枚举来指示方向{UP,DOWN,左,右}:

public enum Direction { 
    UP, 
    DOWN, 
    LEFT, 
    RIGHT 
} 

然后Map<Direction, Boolean>指示头的方向:

private Map<Direction, Boolean> dirMap = new EnumMap<>(Direction.class); 

在其他地方,你会初始化该映射以在所有值中保持为假:

// initialize the map to all false 
for (Direction dir : Direction.values()) { 
    dirMap.put(dir, false); 
} 

然后更改状态您的代码中用于收听按键和释放的地图中的项目 - 例如,当按下向上键时调用map.put(Direction.UP, true),并且在释放时同样呼叫map.put(Direction.UP, false),对于其他键也是如此。请注意,如果你的是一个Swing应用程序,我会使用Key Bindings而不是KeyListener来执行此操作。在听众中,我会在GUI上调用repaint()

在Swing Timer中,遍历Map,根据Map的状态设置方向。

类字段:

private int spriteX = 0; // location of sprite 
private int spriteY = 0; 

private int directionX = 0; // direction sprite is heading 
private int directionY = 0; 

内的ActionListener

// within the Swing Timer's ActionListener 
if (dirMap.get(Direction.UP)) { 
    directionY -= 1; 
} 
if (dirMap.get(Direction.DOWN)) { 
    directionY += 1; 
} 
if (dirMap.get(Direction.RIGHT)) { 
    directionX += 1; 
} 
if (dirMap.get(Direction.LEFT)) { 
    directionY -= 1; 
} 

// here multiply directionX and directionY by some scale factor and use to place new snake head 
// then call repaint(); 

例如(不是蛇,而是一球 - 我会离开蛇给你)

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.util.EnumMap; 
import java.util.Map; 
import java.util.Map.Entry; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class DirTest extends JPanel { 
    private static final int PREF_W = 800; 
    private static final int PREF_H = PREF_W; 
    private static final int TIMER_DELAY = 40; 
    private static final Color SPRITE_COLOR = Color.RED; 
    private static final int SPRITE_W = 20; 
    private static final Color BG = Color.BLACK; 
    public static final int SCALE = 1; 
    private Map<Direction, Boolean> dirMap = new EnumMap<>(Direction.class); 
    private int spriteX = 0; 
    private int spriteY = 0; 
    private int directionX = 0; 
    private int directionY = 0; 
    private Timer gameLoopTimer = new Timer(TIMER_DELAY, new TimerListener()); 

    public DirTest() { 
     setKeyBindings(); 

     setBackground(BG); 
     // initialize map to all 0; 
     for (Direction dir : Direction.values()) { 
      dirMap.put(dir, false); 
     } 

     gameLoopTimer.start(); 
    } 

    private void setKeyBindings() { 
     int condition = WHEN_IN_FOCUSED_WINDOW; // bind to keys if component in active window 
     InputMap inputMap = getInputMap(condition); 
     ActionMap actionMap = getActionMap(); 

     setKeyBinding(inputMap, actionMap, KeyEvent.VK_UP, Direction.UP); 
     setKeyBinding(inputMap, actionMap, KeyEvent.VK_DOWN, Direction.DOWN); 
     setKeyBinding(inputMap, actionMap, KeyEvent.VK_LEFT, Direction.LEFT); 
     setKeyBinding(inputMap, actionMap, KeyEvent.VK_RIGHT, Direction.RIGHT); 
    } 

    private void setKeyBinding(InputMap inputMap, ActionMap actionMap, int keyCode, Direction dir) { 
     KeyStroke press = KeyStroke.getKeyStroke(keyCode, 0, false); 
     KeyStroke released = KeyStroke.getKeyStroke(keyCode, 0, true); 

     Action pressAction = new PressedAction(dir, true); 
     Action releasedAction = new PressedAction(dir, false); 

     inputMap.put(press, press.toString()); 
     inputMap.put(released, released.toString()); 

     actionMap.put(press.toString(), pressAction); 
     actionMap.put(released.toString(), releasedAction); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2 = (Graphics2D) g; 
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     g2.setColor(SPRITE_COLOR); 
     g2.fillOval(spriteX, spriteY, SPRITE_W, SPRITE_W); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     if (isPreferredSizeSet()) { 
      return super.getPreferredSize(); 
     } 
     return new Dimension(PREF_W, PREF_H); 
    } 

    private class PressedAction extends AbstractAction { 
     private boolean pressed; 
     private Direction dir; 

     public PressedAction(Direction dir, boolean pressed) { 
      this.dir = dir; 
      this.pressed = pressed; 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      dirMap.put(dir, pressed); 
     } 
    } 

    private class TimerListener implements ActionListener { 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      for (Entry<Direction, Boolean> entry : dirMap.entrySet()) { 
       if (entry.getValue()) { 
        directionX += entry.getKey().getX(); 
        directionY += entry.getKey().getY(); 
       } 
      } 

      spriteX += SCALE * directionX; 
      spriteY += SCALE * directionY; 

      repaint(); 
     } 
    } 

    private static void createAndShowGui() { 
     JFrame frame = new JFrame("DirTest"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(new DirTest()); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> createAndShowGui()); 
    } 
} 

enum Direction { 
    UP(0, -1), 
    DOWN(0, 1), 
    LEFT(-1, 0), 
    RIGHT(1, 0); 

    private int x; 
    private int y; 

    private Direction(int x, int y) { 
     this.x = x; 
     this.y = y; 
    } 
    public int getX() { 
     return x; 
    } 
    public int getY() { 
     return y; 
    } 

} 
+0

这样,OP需要确保HashMap中只有一个值被设置为“true”,否则它可能会表现得相当奇怪。我会选择设置/检查当前方向的单个字段。除了EnumHasMap在使用枚举的Map实现时可能是更好的选择。 – n247s

+0

此外,OP正在寻找一种方式,即使钥匙已经释放,蛇仍然在移动。所以也许修改设置一个小点。截至目前,这将产生与OP目前 – n247s

+0

@ n247s相同的结果:请查看并运行代码。即使钥匙被释放,这也会导致持续的动作。更重要的是,如果按住键,动作会变得更快。尝试一下。 –

0

如果你想保持蛇的移动,你需要某种游戏循环(如前所述)。最简单的方法是有一个包含当前方向的字段,并根据输入进行设置。因此,这里有你可以用它来设置正确的方向/位置

的方向枚举

public enum Direction 
{ 
    NORTH, EAST, SOUTH, WEST; 

    public Direction oposite() 
    { 
     switch(this) 
     { 
      case NORTH: return SOUTH; 
      case SOUTH: return NORTH; 
      case EAST: return WEST; 
      case WEST: return EAST; 
      } 
    } 
} 

设置电流方向的方法的一些方法/类。(这假定存在一个名为“currentDirection”一个字段,它包含表示当前方向的枚举(方向))(

public void setDirection(Direction newDirection) 
{ 
     if(currentDirection != newDirection.oposite()) 
      currentDirection = newDirection; 
} 

这是在游戏环某处任一个定时器,或一个while循环包括一个“睡眠'呼叫,以防止CPU拥抱)

 switch(currentDirection) 
    { 
      case NORTH: mySegment[0].moveNorth(); break; 
      case EAST: mySegment[0].moveEast(); break; 
      case SOUTH: mySegment[0].moveSouth(); break; 
      case WEST: mySegment[0].moveWest(); break; 
    } 
    repaint(); 

当然,而不是调用'mySegment [0] .moveNorth();'或者在keyEvent的actionHandlers中有相同的地方,你应该只调用'setDirection();'使蛇移动。

我希望这对你有所帮助。