请不要将KeyListener
/KeyAdapter
那用于 AWT。而是将KeyBinding
s用于 Swing 组件(IMO 也不例外)。
除非另一个类应该可以访问KeyListener
keyPressed
etc 方法(尽管您不应该使用它),或者actionPerformed
该类不需要实现它,而是创建一个实例以在该类中使用。
也宁可覆盖getPreferredSize
,这样你就JPanel
可以调用而不是哪个是不好的做法。在添加所有组件之前也永远不会设置可见pack()
JFrame
setSize()
JFrame
此外,我看到您在 2 个地方(构造函数和paintComponent
)启动计时器,而不是在构造函数中启动它,除非您调用Timer#setRepeats(false)
.
我认为没有用 for ImageIcon
,而只是简单地使用了 aBufferedImage
paintComponent(..)
除了纯绘图之外,不要加载图像或进行冗长的操作等
如上所述,这是您的修复代码:
注意:我使用自己的KeyBinding
课程只是为了让事情变得更容易一些。
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Nfs {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Need for Speed");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new startGame());
frame.pack();
frame.setVisible(true);
}
});
}
}
class startGame extends JPanel {
private int x = 0, y = 0, velX = 0, velY = 0, width = 800, height = 600;
private BufferedImage transformedImage;
private Timer time = new Timer(5, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
if (x < 0) {
velX = 0;
x = 0;
}
if (y < 0) {
velY = 0;
y = 0;
}
if (x > width) {
velX = 0;
x = width;
}
if (y > height) {
velY = 0;
y = height;
}
x = x + velX;
y = y + velY;
repaint();
}
});
public startGame() {
transformedImage = createTransformedImage(createCar(), 45);
addKeyBindings();
time.start();
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D ga = (Graphics2D) g;
ga.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
ga.drawImage(transformedImage, x, y, null);
}
//Simply used for testing (to simulate sprites)
public static BufferedImage createCar() {
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TRANSLUCENT);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.GREEN);
g2.fillRect(0, 0, img.getWidth(), img.getHeight());
g2.dispose();
return img;
}
//https://stackoverflow.com/questions/4156518/rotate-an-image-in-java
public static BufferedImage createTransformedImage(BufferedImage image, double angle) {
double sin = Math.abs(Math.sin(angle)), cos = Math.abs(Math.cos(angle));
int w = image.getWidth(), h = image.getHeight();
int neww = (int) Math.floor(w * cos + h * sin), newh = (int) Math.floor(h * cos + w * sin);
BufferedImage result = new BufferedImage(neww, newh, Transparency.TRANSLUCENT);
Graphics2D g2d = result.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate((neww - w) / 2, (newh - h) / 2);
g2d.rotate(angle, w / 2, h / 2);
g2d.drawRenderedImage(image, null);
g2d.dispose();
return result;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
private void addKeyBindings() {
AbstractAction onReleaseAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
velX = 0;
velY = 0;
}
};
//we are adding multiple keybindigs with same focus map etc to same component so we intitae an instance of class rate than use static methods
KeyBinding kb = new KeyBinding(this, KeyBinding.WHEN_IN_FOCUSED_WINDOW);
kb.addKeyBindingOnPressAndRelease(KeyEvent.VK_DOWN, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
velX = 0;
velY = 1;
}
}, "down pressed", onReleaseAction, "down released");
kb.addKeyBindingOnPressAndRelease(KeyEvent.VK_UP, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
velX = 0;
velY = -1;
}
}, "up pressed", onReleaseAction, "up released");
kb.addKeyBindingOnPressAndRelease(KeyEvent.VK_LEFT, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
velX = -1;
velY = 0;
}
}, "left pressed", onReleaseAction, "left released");
kb.addKeyBindingOnPressAndRelease(KeyEvent.VK_RIGHT, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent ae) {
velX = 1;
velY = 0;
}
}, "right pressed", onReleaseAction, "right released");
}
}
class KeyBinding {
private final JComponent container;
private final int inputMap;
public static final int WHEN_IN_FOCUSED_WINDOW = JComponent.WHEN_IN_FOCUSED_WINDOW,
WHEN_FOCUSED = JComponent.WHEN_FOCUSED,
WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
public KeyBinding(JComponent container, int inputMap) {
this.container = container;
this.inputMap = inputMap;
}
public void addKeyBinding(int key, boolean onRelease, AbstractAction keybindingAction, String description) {
putKeyBinding(container, inputMap, key, onRelease, keybindingAction, description);
}
public void addKeyBindingOnPress(int key, AbstractAction keybindingAction, String description) {
putKeyBinding(container, inputMap, key, false, keybindingAction, description);
}
public void addKeyBindingOnRelease(int key, AbstractAction keybindingAction, String description) {
putKeyBinding(container, inputMap, key, true, keybindingAction, description);
}
public void addKeyBindingOnPressAndRelease(int key, AbstractAction onPressAction, String onPressDesc, AbstractAction onReleaseAction, String onReleaseDesc) {
putKeyBinding(container, inputMap, key, false, onPressAction, onPressDesc);
putKeyBinding(container, inputMap, key, true, onReleaseAction, onReleaseDesc);
}
public static void putKeyBinding(JComponent container, int inputMap, int key, boolean onRelease, AbstractAction keybindingAction, String description) {
container.getInputMap(inputMap).put(KeyStroke.getKeyStroke(key, 0, onRelease), description);
container.getActionMap().put(description, keybindingAction);
}
public static void putKeyBindingOnPress(JComponent container, int inputMap, int key, AbstractAction keybindingAction, String description) {
container.getInputMap(inputMap).put(KeyStroke.getKeyStroke(key, 0, false), description);
container.getActionMap().put(description, keybindingAction);
}
public static void putKeyBindingOnRelease(JComponent container, int inputMap, int key, AbstractAction keybindingAction, String description) {
container.getInputMap(inputMap).put(KeyStroke.getKeyStroke(key, 0, true), description);
container.getActionMap().put(description, keybindingAction);
}
public static void putKeyBindingOnPressAndRelease(JComponent container, int inputMap, int key, AbstractAction onPressAction, String onPressDesc, AbstractAction onReleaseAction, String onReleaseDesc) {
putKeyBinding(container, inputMap, key, false, onPressAction, onPressDesc);
putKeyBinding(container, inputMap, key, true, onReleaseAction, onReleaseDesc);
}
}
参考: