import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable{
private static final long serialVersionUID = 1L;
private final int WIDTH = 400;
private final int HEIGHT = 400;
private static BufferedImage ship;
private int shipX;
private int shipY;
private boolean running;
public GamePanel(){
super();
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
requestFocus();
try {ship = ImageIO.read(new File("res/ship2.png"));}
catch (IOException e) {e.printStackTrace();}
running = true;
}
private void gameUpdate() {
shipX++;
shipY++;
}
@Override
public void run() {
while(running){
gameUpdate();
repaint();
try {Thread.sleep(3);}
catch (InterruptedException e){e.printStackTrace();}
}
}
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, WIDTH, HEIGHT);
g.drawImage(ship, shipX, shipY, 100, 100, null);
}
}
import javax.swing.JFrame;
public class Game extends JFrame{
private static final long serialVersionUID = 1L;
public Game(){
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
GamePanel g = new GamePanel();
Thread t = new Thread(g);
t.start();
add(new GamePanel());
pack();
setVisible(true);
}
public static void main(String[] args) {
new Game();
}
}
我已经阅读了许多像我这样的问题的答案,但我已经坚持了几个小时。如果repaint()
应该调用覆盖的paintComponent()
,为什么我看不到任何动画?我的意思是大多数事情都有效:如果我放System.out.println("test")
我可以看到该线程正在工作并且处于调试模式,我看到shipX
和shipY
值发生了变化,但是在窗口中图像停留在0,0坐标开始。我一直在尝试覆盖paint();
并覆盖两者的所有内容,但似乎没有任何动画可以进行。
任何人都可以提供帮助吗?
答案 0 :(得分:2)
<强>问题强>
Thread.sleep()
- Swing是单线程的,在Event Dispatch Thread(EDT)上运行。这就是它所做的绘画。你基本上阻止了EDT
Thread.sleep(3)
- 可能误解了3是什么。这是几毫秒。 3毫秒很短。你基本上暗示你想要每秒300帧以上。会很艰难。
创建两个GamePanels
。 - 你用线程创建一个,然后在框架中添加一个(这可能是最大的问题 - 但我将Thread.sleep放在它旁边)
可能的解决方案
使用javax.swing.Timer
代替Swing动画。此计时器将在EDT上运行。详情请见How to use Swing Timers。
使用计时器时选择更合理的延迟。 25-30 fps之间的东西是好的。所以像40毫秒的延迟大概是25 fps。
不要创建两个GamePanels
。只需使用一个。
计时器的基本构造
Timer timer = new Timer(40, new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
// do something every 40 milliseconds
}
});
timer.start();
基本上,计时器在某种程度上就像按钮一样工作ActionListener
。每延迟毫秒,它会触发ActionEvent
,侦听器将捕获它,并调用其actionPerformed
。请参阅链接以获得更好的解释。我现在太懒了以获得更彻底的
另请参阅Initial Threads,了解有关在EDT上运行应用的一些信息。你应该用SwingUtilities.invokeLater(...)
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Game();
}
});
}
g.drawImage(ship, shipX, shipY, 100, 100, null);
应该是
g.drawImage(ship, shipX, shipY, 100, 100, this);
^
|
The panel is the ImageObserver
答案 1 :(得分:0)
Java Docs Custom Painting Demo在学习绘画时非常有用,我建议你阅读它。下面是编辑的相同演示,用于将船直线移动,直到它到达面板上的某个点。
这可能不是你想要的答案,但在我学习油漆时,这对我帮助很大。
package messaround;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Game {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
}
class MyPanel extends JPanel {
BufferedImage boat;
Timer timer;
private int boatX = 0;
private int boatY = 0;
private int boatW;
private int boatH;
public MyPanel() {
try {
boat = ImageIO.read(new File("res/ship2.png"));
} catch (IOException e) {
e.printStackTrace();
}
boatW=boat.getWidth();
boatH=boat.getHeight();
timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
moveBoat();
if(boatX>100){
timer.cancel();
timer.purge();
}
}} ,0, 30);
setBorder(BorderFactory.createLineBorder(Color.black));
}
public void moveBoat(){
repaint(boatX,boatY,boatW,boatH);
boatX++;
boatY++;
repaint(boatX,boatY,boatW,boatH);
}
public Dimension getPreferredSize() {
return new Dimension(250,200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(boat, boatX, boatY, this);
}
}