为什么动画没有更新?

时间:2014-07-21 18:00:39

标签: java animation paintcomponent

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")我可以看到该线程正在工作并且处于调试模式,我看到shipXshipY值发生了变化,但是在窗口中图像停留在0,0坐标开始。我一直在尝试覆盖paint();并覆盖两者的所有内容,但似乎没有任何动画可以进行。

任何人都可以提供帮助吗?

2 个答案:

答案 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);
    }  
}