我创建了一个只在屏幕上移动球的程序。我曾经把它全部放在一个班级中,但我觉得它看起来太乱了,所以我把它分成三个不同的类:Main ...初始化一切,Game ...画出一切,是JPanel,AL是一个KeyListener(也是问题所在)。问题是,无论我尝试传递给它,我都无法从我的AL类重新编写程序。有人能帮忙吗?这是我的三个班级:
import java.awt.Color;
import javax.swing.JFrame;
public class Main {
static Game game;
static JFrame frame;
public static void main(String[] args) {
game = new Game();
frame = new JFrame();
frame.getContentPane().add(game);
frame.addKeyListener(new AL(game, frame));
frame.setTitle("Game");
frame.setSize(500, 500);
frame.setResizable(true);
frame.setVisible(true);
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
-
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JPanel implements Runnable {
int x, y, xCoord, yCoord;
private Image dbImage;
private Graphics dbg;
JFrame frame;
public void changeCoord() {
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
}
public static void main(String[] args) {
Game game = new Game();
Thread t = new Thread(game);
t.start();
}
public Game() {
x = 250;
y = 250;
}
@Override
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
@Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
@Override
public void run() {
try {
while (true) {
changeCoord();
Thread.sleep(30);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
-
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class AL extends KeyAdapter {
Game game;
JFrame frame;
public AL(Game game, JFrame frame) {
this.game = game;
this.frame = frame;
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
game.setXCoord(-1);
}
if (keyCode == e.VK_RIGHT) {
game.setXCoord(+1);
}
if (keyCode == e.VK_UP) {
game.setYCoord(-1);
}
if (keyCode == e.VK_DOWN) {
game.setYCoord(+1);
}
game.repaint();
}
@Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
game.setXCoord(0);
}
if (keyCode == e.VK_RIGHT) {
game.setXCoord(0);
}
if (keyCode == e.VK_UP) {
game.setYCoord(0);
}
if (keyCode == e.VK_DOWN) {
game.setYCoord(0);
}
game.repaint();
}
}
答案 0 :(得分:4)
让我们从明显的......开始。
这是有问题的......
@Override
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
@Override
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbg = dbImage.getGraphics();
paintComponent(dbg);
g.drawImage(dbImage, 0, 0, this);
}
没有必要在Swing组件中实现双缓冲,它们已经存在。另外,你打破绘画合约,不要调用绘画方法超级方法
整件事应该是......
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
有关详细信息,请参阅Painting in AWT and Swing和Performing Custom Painting
众所周知, KeyListener
存在问题。如果它注册的组件是可聚焦的并且具有键盘焦点,它将仅引发键事件。默认情况下,JPanel
不可调焦。在你跑步并试着让它变得可聚焦(并且感到非常失望)之前,你应该使用Key Bindings API来代替KeyListener
作为一个基本的例子......
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 Game());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Game extends JPanel {
int x, y, xCoord, yCoord;
public Game() {
x = 250;
y = 250;
addKeyBinding(KeyEvent.VK_LEFT, "move.left", new MoveAction(this, -1, 0));
addKeyBinding(KeyEvent.VK_RIGHT, "move.right", new MoveAction(this, 1, 0));
addKeyBinding(KeyEvent.VK_UP, "move.up", new MoveAction(this, 0, -1));
addKeyBinding(KeyEvent.VK_DOWN, "move.down", new MoveAction(this, 0, 1));
}
protected void addKeyBinding(int keyCode, String name, Action action) {
addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0), name, action);
}
protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(keyStroke, name);
actionMap.put(name, action);
}
public void changeCoord() {
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
repaint();
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
changeCoord();
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
changeCoord();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(480, 480);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
}
public class MoveAction extends AbstractAction {
private int xDelta;
private int yDelta;
// I'd prefer an interface with just the "move" methods, but
// that's more time I don't have
private Game game;
public MoveAction(Game game, int xDelta, int yDelta) {
this.xDelta = xDelta;
this.yDelta = yDelta;
this.game = game;
}
@Override
public void actionPerformed(ActionEvent e) {
game.setXCoord(xDelta);
game.setYCoord(yDelta);
}
}
}
但是,等等,这不完全是你想要的(相信我,我是互联网上的anoymouse人;)),一个更好的例子可能是......
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
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 Main {
public static void main(String[] args) {
new Main();
}
public Main() {
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 Game());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum Direction {
UP,
LEFT,
DOWN,
RIGHT;
}
public class Game extends JPanel {
int x, y, xCoord, yCoord;
private Set<Direction> movement;
public Game() {
x = 250;
y = 250;
movement = new HashSet<>(4);
addKeyPressedBinding(KeyEvent.VK_LEFT, "left.pressed", new MoveAction(movement, Direction.LEFT, true));
addKeyReleasedBinding(KeyEvent.VK_LEFT, "left.released", new MoveAction(movement, Direction.LEFT, false));
addKeyPressedBinding(KeyEvent.VK_RIGHT, "right.pressed", new MoveAction(movement, Direction.RIGHT, true));
addKeyReleasedBinding(KeyEvent.VK_RIGHT, "right.released", new MoveAction(movement, Direction.RIGHT, false));
addKeyPressedBinding(KeyEvent.VK_UP, "up.pressed", new MoveAction(movement, Direction.UP, true));
addKeyReleasedBinding(KeyEvent.VK_UP, "up.released", new MoveAction(movement, Direction.UP, false));
addKeyPressedBinding(KeyEvent.VK_DOWN, "down.pressed", new MoveAction(movement, Direction.DOWN, true));
addKeyReleasedBinding(KeyEvent.VK_DOWN, "down.released", new MoveAction(movement, Direction.DOWN, false));
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
changeCoord();
}
});
timer.start();
}
protected void addKeyBinding(int keyCode, String name, Action action) {
addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0), name, action);
}
protected void addKeyPressedBinding(int keyCode, String name, Action action) {
addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, false), name, action);
}
protected void addKeyReleasedBinding(int keyCode, String name, Action action) {
addKeyBinding(KeyStroke.getKeyStroke(keyCode, 0, true), name, action);
}
protected void addKeyBinding(KeyStroke keyStroke, String name, Action action) {
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(keyStroke, name);
actionMap.put(name, action);
}
public void changeCoord() {
if (movement.contains(Direction.UP)) {
y--;
} else if (movement.contains(Direction.DOWN)) {
y++;
}
if (movement.contains(Direction.LEFT)) {
x--;
} else if (movement.contains(Direction.RIGHT)) {
x++;
}
x += xCoord;
y += yCoord;
if (x <= 20) {
x = 20;
}
if (x >= 480) {
x = 480;
}
if (y <= 40) {
y = 40;
}
if (y >= 480) {
y = 480;
}
repaint();
}
public void setXCoord(int xcoord) {
xCoord = xcoord;
changeCoord();
}
public void setYCoord(int ycoord) {
yCoord = ycoord;
changeCoord();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(480, 480);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillOval(x, y, 15, 15);
}
}
public class MoveAction extends AbstractAction {
private Set<Direction> movement;
private Direction direction;
private boolean pressed;
public MoveAction(Set<Direction> movement, Direction direction, boolean pressed) {
this.movement = movement;
this.direction = direction;
this.pressed = pressed;
}
@Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
movement.add(direction);
} else {
movement.remove(direction);
}
}
}
}
这样做只是在按下一个键时激活一个标志(当它被释放时停用它),然后在Swing Timer
中,我们检查哪些键是“活动的”并更新球的位置
这样做,消除了首次按下和按住按键时由操作系统引起的关键“断续”。在第一个键和重复的键事件之间插入延迟。相反,我们只是按照我们的意愿打开和关闭标志。
它还允许您同时在两个方向上移动(水平和垂直)
有关详细信息,请查看Concurrency in Swing和How to use Swing Timers