您的目标是绘制一次,解决方案是摆脱 if 块,并在 paintComponent 方法中简单地绘制需要绘制的内容。例如,假设您有一个带有 x 和 y 位置的 Fruit2 类以及一个 draw 方法:
class Fruit2 {
private static final Color FRUIT_COLOR = Color.BLUE.brighter();
public static final int FRUIT_SIDE = 20;
private int x, y;
public Fruit2(int x, int y) {
this.x = x;
this.y = y;
}
public void draw(Graphics g) {
g.setColor(FRUIT_COLOR);
g.fillRect(x, y, FRUIT_SIDE, FRUIT_SIDE);
}
}
比如说,主绘图类包含一个包含 10 个这些项目的数组:
private static final int FRUIT_COUNT = 10;
//.....
private Fruit2[] fruits = new Fruit2[FRUIT_COUNT];
假设绘图 JPanel 也有一个 Snake2 对象,该对象也有一个 draw 方法(知道如何绘制自己),那么您的 paintComponent 方法将很简单:
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Fruit2 fruit : fruits) {
fruit.draw(g);
}
snake.draw(g);
}
就是这样。 Fruit2 对象自己绘制自己,而蛇自己绘制自己——完成。
同样,正如我在上面的 cmets 中所提到的,绘画方法不应该包含移动蛇的代码 - 将其留给计时器的 ActionListener。相反,绘画方法,这里 paintComponent(...) 只是绘制 GUI 状态的表示,仅此而已。
作为我的意思的一个有效示例,请运行以下代码:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class SnakePanel2 extends JPanel {
private static final long serialVersionUID = 1L;
private static final int PANEL_WIDTH = 800;
private static final int PANEL_HEIGHT = 650;
private static final int TIMER_DELAY = 40;
private static final Color BG = Color.WHITE;
private static final int FRUIT_COUNT = 10;
private Snake2 snake = new Snake2(PANEL_WIDTH, PANEL_HEIGHT);
private Fruit2[] fruits = new Fruit2[FRUIT_COUNT];
public SnakePanel2() {
setBackground(BG);
new Timer(TIMER_DELAY, e -> timerStep()).start();
for (int i = 0; i < fruits.length; i++) {
int x = (int) ((PANEL_WIDTH - Fruit2.FRUIT_SIDE) * Math.random());
int y = (int) ((PANEL_HEIGHT - Fruit2.FRUIT_SIDE) * Math.random());
fruits[i] = new Fruit2(x, y);
}
}
private void timerStep() {
snake.move();
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Fruit2 fruit : fruits) {
fruit.draw(g);
}
snake.draw(g);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PANEL_WIDTH, PANEL_HEIGHT);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SnakePanel2 panel = new SnakePanel2();
JFrame frame = new JFrame("Snake Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
class Fruit2 {
private static final Color FRUIT_COLOR = Color.BLUE.brighter();
public static final int FRUIT_SIDE = 20;
private int x, y;
public Fruit2(int x, int y) {
this.x = x;
this.y = y;
}
public void draw(Graphics g) {
g.setColor(FRUIT_COLOR);
g.fillRect(x, y, FRUIT_SIDE, FRUIT_SIDE);
}
}
class Snake2 {
private static final int MAX_POINTS = 60;
private static final int RADIUS = 8;
private static final int DELTA = 8;
private static final int DIRECTION_STEPS = 16;
private static final int DIR_MAX_DELTA = 2;
private static final Point2D[] DIRECTION_ARRAY = new Point2D[DIRECTION_STEPS];
private static final Color SNAKE_COLOR = Color.RED;
private List<Point2D> units = new ArrayList<>();
private int currentDirection = (DIRECTION_STEPS * 3) / 8;
private int maxWidth;
private int maxHeight;
static {
for (int i = 0; i < DIRECTION_ARRAY.length; i++) {
double x = DELTA * Math.cos((2 * Math.PI * i) / DIRECTION_ARRAY.length);
double y = DELTA * Math.sin((2 * Math.PI * i) / DIRECTION_ARRAY.length);
DIRECTION_ARRAY[i] = new Point2D.Double(x, y);
}
}
public Snake2(int maxWidth, int maxHeight) {
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
units.add(new Point2D.Double(0, 0));
}
public void move() {
if (units.size() != 1) {
currentDirection += (2 * DIR_MAX_DELTA + 1) * (Math.random()) - DIR_MAX_DELTA;
currentDirection += DIRECTION_STEPS;
currentDirection %= DIRECTION_STEPS;
}
double x = units.get(0).getX() + DIRECTION_ARRAY[currentDirection].getX();
double y = units.get(0).getY() + DIRECTION_ARRAY[currentDirection].getY();
if (x < 0) {
x += maxWidth;
} else if (x > maxWidth) {
x -= maxWidth;
}
if (y < 0) {
y += maxHeight;
} else if (y > maxHeight) {
y -= maxHeight;
}
units.add(0, new Point2D.Double(x, y));
if (units.size() >= MAX_POINTS) {
units.remove(units.size() - 1);
}
}
public void draw(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(SNAKE_COLOR);
for (Point2D unit : units) {
double x = unit.getX() - RADIUS;
double y = unit.getY() - RADIUS;
double w = 2 * RADIUS;
double h = w;
Ellipse2D e2d = new Ellipse2D.Double(x, y, w, h);
g2.fill(e2d);
}
g2.dispose();
}
}