我编写了一个生成贪吃蛇游戏中的“蛇”的代码以供练习。 (如果您不熟悉贪吃蛇游戏中的蛇,它是一条 5 格长的蛇,有一个头部(使用 JLabel 创建)和跟随头部的 body 部位(也使用 JLabels 创建)。)
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import javax.swing.*;
public class SnakeGameFrame extends JFrame {
Thread snakeThread;
GroundPanel p;
public SnakeGameFrame() {
super("Moving Snake!");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p = new GroundPanel();
setContentPane(p);
setSize(400,400);
setVisible(true);
p.requestFocus();
snakeThread = new Thread(p);
snakeThread.start();
}
class GroundPanel extends JPanel implements Runnable{
static final int LEFT = 0;
static final int RIGHT = 1;
static final int UP = 2;
static final int DOWN = 3;
int direction;
Image img;
SnakeBody snakeBody;
final int delay = 200;
public GroundPanel() {
setLayout(null);
snakeBody = new SnakeBody();
snakeBody.addIn(this);
direction = LEFT;
this.addKeyListener(new MyKeyListener());
ImageIcon icon = new ImageIcon("twilight.jpg");
img = icon.getImage();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0,0,getWidth(), getHeight(), null);
}
public void run() {
while(true) {
try {
Thread.sleep(delay);
snakeBody.move(direction);
}catch(InterruptedException e) {
return;
}
}
}
class MyKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_LEFT:
direction = LEFT;
break;
case KeyEvent.VK_RIGHT:
direction = RIGHT;
break;
case KeyEvent.VK_UP:
direction = UP;
break;
case KeyEvent.VK_DOWN:
direction = DOWN;
break;
}
}
}
}
class SnakeBody {
Vector<JLabel> v = new Vector<JLabel>();
public SnakeBody() {
ImageIcon head = new ImageIcon("head.jpg");
JLabel la = new JLabel(head);
la.setSize(head.getIconWidth(), head.getIconHeight());
la.setLocation(100, 100);
v.add(la);
ImageIcon body = new ImageIcon("body.jpg");
for(int i=1; i<10; i++) {
la = new JLabel(body);
la.setSize(body.getIconWidth(), body.getIconHeight());
la.setLocation(100+i*20, 100);
v.add(la);
}
}
public void addIn(JPanel p) {
for(int i=0; i<v.size(); i++)
p.add(v.get(i));
}
public void move(int direction) {
for(int i=v.size()-1; i>0; i--) {
JLabel b = v.get(i);
JLabel a = v.get(i-1);
b.setLocation(a.getX(), a.getY());
}
JLabel head = v.get(0);
switch(direction) {
case GroundPanel.LEFT :
head.setLocation(head.getX()-20, head.getY());
break;
case GroundPanel.RIGHT :
head.setLocation(head.getX()+20, head.getY());
break;
case GroundPanel.UP :
head.setLocation(head.getX(), head.getY()-20);
break;
case GroundPanel.DOWN :
head.setLocation(head.getX(), head.getY()+20);
break;
}
}
}
public static void main(String[] args) {
new SnakeGameFrame();
}
}
我的问题是为了继续“更新”我的蛇,我想我必须在我的蛇中使用 repaint() 方法
public void run()
方法。 像这样
try { Thread.sleep(delay); snakeBody.move(direction); repaint(); }
但事实证明,没有它它也能正常工作.. 我读过很多关于 repaint() 的文章,但我仍然不知道何时需要使用它。 有人可以用菜鸟友好的术语解释一下吗?谢谢:)
最佳答案
只要 RepaintManager
尚未代表您执行此操作(例如更新文本或颜色等绑定(bind)属性),您就必须调用 repaint()
。在您的示例中,更改 JLabel
的大小和位置会自动触发重绘。
更严重的是,您的示例以两种方式错误地同步:
它在 initial thread 上创建 GUI而不是 event dispatch thread .
它更新事件调度线程以外的线程上的 GUI 组件,而不同步对共享数据的访问。
相反,请使用 javax.swing.Timer
调整动画的节奏。您的 actionPerformed()
实现将在事件调度线程上调用。
关于Java AWT/Swing 何时使用 repaint() 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34975768/