Java 为什么动画没有更新?

Java 为什么动画没有更新?,java,animation,paintcomponent,Java,Animation,Paintcomponent,} 我已经读了很多关于我的问题的答案,但我已经坚持了好几个小时了。如果repaint()应该调用覆盖的paintComponent(),为什么我根本看不到动画?我的意思是大多数事情都可以工作:如果我把System.out.println(“test”)放进去,我可以看到线程正在工作,在调试模式下,我可以看到shipX和shipY值在变化,但在窗口中,图像卡在0,0坐标的开头。我一直在尝试一切,从覆盖paint()和重写这两个选项,但似乎没有什么可以让动画继续运行 有人能提供帮助吗?问题 Thr

}

我已经读了很多关于我的问题的答案,但我已经坚持了好几个小时了。如果
repaint()
应该调用覆盖的
paintComponent()
,为什么我根本看不到动画?我的意思是大多数事情都可以工作:如果我把
System.out.println(“test”)
放进去,我可以看到线程正在工作,在调试模式下,我可以看到
shipX
shipY
值在变化,但在窗口中,图像卡在0,0坐标的开头。我一直在尝试一切,从覆盖
paint()
和重写这两个选项,但似乎没有什么可以让动画继续运行


有人能提供帮助吗?

问题

  • Thread.sleep()
    -Swing是单线程的,在事件调度线程(EDT)上运行。这就是画的地方。你基本上阻止了EDT

  • 线程。睡眠(3)
    -可能是对3的误解。是毫秒。3毫秒相当短。你基本上是在暗示你想要每秒300多帧。会很难的

  • 创建两个
    游戏面板
    -用线程创建一个,然后在框架中添加一个不同的线程(这可能是最大的问题,但我会将thread.sleep放在它旁边)

可能的解决方案

  • 使用
    javax.swing.Timer
    代替swing动画。此计时器将在EDT上工作。更多信息请访问

  • 使用计时器时,请选择更合理的延迟。每秒25-30帧之间的速度比较好。因此,40毫秒的延迟大约是25 fps

  • 不要创建两个
    游戏面板
    。就用一个


定时器的基本结构

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();
}
从某种意义上讲,计时器的工作原理就像一个按钮,就它而言
ActionListener
。每延迟几毫秒,它就会触发一个
ActionEvent
,侦听器将捕获它,并调用它的
actionPerformed
。请参阅链接以获得更好的解释。我现在太懒了,没法更彻底地了解


有关在EDT上运行应用程序的一些信息,请参阅。您应该将程序包装在一个
SwingUtilities.invokeLater(…)


应该是

g.drawImage(ship, shipX, shipY, 100, 100, null);
Java文档在学习绘画时非常有用,我建议您阅读它。下面是编辑的同一个演示,用于沿直线移动船舶,直到到达面板上的某个点

这可能不是你想要的答案,但这在我学习绘画时帮了我很大的忙

g.drawImage(ship, shipX, shipY, 100, 100, this);
                                           ^
                                           |
                            The panel is the ImageObserver

什么
Thread
在列出的代码中没有创建新的
Thread
。这个问题似乎离题了,因为这个代码有太多错误,需要一本书来解释。事实上,亚马逊上有很多书解释了这一切。我不确定这是否构成“离题”。300 FPS就可以了——问问任何玩家。但在这种情况下,图像将在大约1.3秒后消失,这对于这种动画来说可能有点短。。。同样值得添加到您的答案中-OP启动一个
线程
,没有同步或可见性保证(在这里添加到swing并发教程的链接?)
g.drawImage(ship, shipX, shipY, 100, 100, null);
g.drawImage(ship, shipX, shipY, 100, 100, this);
                                           ^
                                           |
                            The panel is the ImageObserver
    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);
    }  
}