PacManObject pacman = new PacManObject();
pacman.setFocusable(true);
pacman.setRequestFocusEnabled(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,600);
frame.setVisible(true);
frame.add(pacman);
pacman.addKeyListener(pacman); // **** note change ****
更妙的是不让自己的GUI类实现监听器接口,因为这样做是给他们太多的责任 - 也就是说,它违反了班OOP原理的单责任的规则。
此外,更好地使用键绑定作为dup的会告诉你。
更好地使用摆动计时器作为您的游戏循环,而不是依赖按键,因为后者会导致初始移动的延迟。
例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
@SuppressWarnings("serial")
public class PacMan2 extends JPanel implements DirMappable {
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
private static final Color BG = Color.DARK_GRAY;
private static final int ANIMATION_DELAY = 15;
private int pmX = 100;
private int pmY = 100;
private EnumMap<Direction, Boolean> dirMap = new EnumMap<>(Direction.class);
private MyPacMan myPacMan = new MyPacMan(pmX, pmY, 30);
private Timer animationTimer;
public PacMan2() {
setBackground(BG);
setKeyBindings();
animationTimer = new Timer(ANIMATION_DELAY, new AnimationListener(this));
animationTimer.start();
}
private void setKeyBindings() {
// fill the dirMap with false's -- no initial motion
for (Direction dir : Direction.values()) {
dirMap.put(dir, Boolean.FALSE);
}
// associate key code with Direction
Map<Integer, Direction> keyToDir = new HashMap<>();
keyToDir.put(KeyEvent.VK_UP, Direction.UP);
keyToDir.put(KeyEvent.VK_DOWN, Direction.DOWN);
keyToDir.put(KeyEvent.VK_LEFT, Direction.LEFT);
keyToDir.put(KeyEvent.VK_RIGHT, Direction.RIGHT);
// get InputMap and ActionMap for binding
int condition = WHEN_IN_FOCUSED_WINDOW;
final InputMap inputMap = getInputMap(condition);
final ActionMap actionMap = getActionMap();
// loop through the keyToDir Map and set up bindings
boolean[] keyPressed = { true, false };
for (Integer keyCode : keyToDir.keySet()) {
Direction dir = keyToDir.get(keyCode);
for (boolean onKeyPress : keyPressed) {
// to make it clear how bindings work
boolean onKeyRelease = !onKeyPress;
KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, 0, onKeyRelease);
Object key = keyStroke.toString();
inputMap.put(keyStroke, key);
// I prefer to use positive boolean variable for Action -- just a bit confusing
actionMap.put(key, new KeyBindingsAction(this, dir, onKeyPress));
}
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
myPacMan.draw(g2); // have our pac man draw itself
}
// safest way to set the GUI's size
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
public void put(Direction dir, boolean pressed) {
dirMap.put(dir, pressed);
}
@Override
public boolean get(Direction dir) {
return dirMap.get(dir);
}
@Override
public void move(Direction dir) {
myPacMan.move(dir); // move our pacman
}
private static void createAndShowGui() {
PacMan2 mainPanel = new PacMan2();
JFrame frame = new JFrame("Pac Man");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
class MyPacMan {
private static final Color COLOR = Color.YELLOW;
private static final int STEP = 3; // moves faster if this is larger
private int x;
private int y;
// for efficiency, draw PacMan as a BufferedImage
// if we want mouth to open and close, and if we want to
// have it change direction, we'll need a Map of images associated with
// the Direction enum
private BufferedImage pacManImage;
public MyPacMan(int x, int y, int w) {
this.x = x;
this.y = y;
double h = w;
double start = 45;
double extent = 360 - 2 * 45;
int type = Arc2D.PIE;
Shape shape = new Arc2D.Double(0, 0, w, h, start, extent, type);
pacManImage = new BufferedImage(w, w, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = pacManImage.createGraphics();
g2.setColor(COLOR);
// smooth drawing with key anti-aliasing
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.fill(shape);
g2.dispose();
}
public void move(Direction dir) {
x += dir.getIncrX() * STEP;
y += dir.getIncrY() * STEP;
}
public void draw(Graphics2D g2) {
if (pacManImage != null) {
g2.drawImage(pacManImage, x, y, null);
}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
enum Direction {
UP(0, -1), DOWN(0, 1), LEFT(-1, 0), RIGHT(1, 0);
private int incrX;
private int incrY;
private Direction(int incrX, int incrY) {
this.incrX = incrX;
this.incrY = incrY;
}
public int getIncrX() {
return incrX;
}
public int getIncrY() {
return incrY;
}
}
// use an interface to encapsulate the methods of the GUI that need to be
// exposed to the helper classes
interface DirMappable {
void put(Direction dir, boolean pressed);
boolean get(Direction dir);
void move(Direction dir);
void repaint();
}
@SuppressWarnings("serial")
class KeyBindingsAction extends AbstractAction {
private Direction dir;
private boolean pressed;
private DirMappable dirMappable;
public KeyBindingsAction(DirMappable dirMappable, Direction dir, boolean pressed) {
this.dirMappable = dirMappable;
this.dir = dir;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent evt) {
dirMappable.put(dir, pressed);
}
}
class AnimationListener implements ActionListener {
private DirMappable dirMappable;
public AnimationListener(DirMappable dirMappable) {
this.dirMappable = dirMappable;
}
@Override
public void actionPerformed(ActionEvent evt) {
boolean repaint = false;
for (Direction dir : Direction.values()) {
if (dirMappable.get(dir)) {
dirMappable.move(dir);
repaint = true;
}
}
if (repaint) {
dirMappable.repaint();
}
}
}
'...它不工作fine'是要帮助尽可能多的“我的电脑不能正常工作”。更具体一些,例如你会得到什么,你期望什么?你是否调试过你的代码来查看事件是否被触发? – Thomas
@Thomas好吧我编辑我的问题随时检查 –
您是否按下任何其他键时检查它是否被调用? – Thomas