使用“游戏循环”到驱动动画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;
}
}
让它调用一个循环移动直到被中断的方法。 – DejaVuSansMono