java - JFrame 中的 Spritesheet 动画

标签 java swing animation jframe paintcomponent

我正在尝试使用 JFrame 中的 spritesheet 获取动画。问题是一旦加载,图像就不会改变。它仅显示第一张图像。 我进行了很多搜索并尝试了几乎所有建议,但无法使其发挥作用。

顺便说一下,getSprite 的返回类型是 Image。 当我在 JFrame 中执行所有操作时,只显示一张图像。当我在扩展 JPanel 的单独类中执行此操作时,我只得到一个白色窗口。

更新 1: 感谢 Andrew,让 JFrame 正常工作。也修复了我的旧部分。这是工作code at ideone

更新 2: 这是我的带有计时器的版本。

class TestSpriteSheet extends JFrame{

   //same old variables

    public TestSpriteSheet(){
        //same old stuff goes here before this
        add(new PanelSprite(this, ss));
        this.setVisible(true);
    }
}

class PanelSprite extends JPanel{

    private long runningTime = 0;
    private int fps = 3;
    private boolean stop = false;
    private SpriteSheetManager ss;
    private TestSpriteSheet temp;

    public PanelSprite(TestSpriteSheet test, SpriteSheetManager sm){
        ss = sm;
        temp = test;
        setSize(180,180);
        setLayout(new BorderLayout()); init();
    }

    public void paintComponent(Graphics g){
        super.paintComponent(g);
        long time = 5000; 
        animate_with_gfx(g, time);
    }

    public void init(){
        Timer t = new Timer((int)(1000/fps), new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if(!stop) {
                    repaint();
                } else {
                    ((Timer)e.getSource()).stop();
                }
            }
        });
        t.setRepeats(true);
        t.setDelay((int)(1000/fps));
        t.start();
    }

    public void animate_with_gfx(Graphics g, long time){
        if(runningTime <= time){
            try {
                System.out.println(runningTime); //Checking if this part works
                int x = 0; int y = 0;
                g.drawImage(ss.getSprite(x, y), 40, 40, null);
                x++; y++; runningTime+=(1000/fps);
            }catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        else{
            stop = true;
        }
    }
}

最佳答案

public void paintComponent(Graphics g){
    super.paintComponent(g);
    long time = 5000; int fps = 3;
    boolean stop = false;
    Timer t = new Timer((int)(1000/fps), new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if(!stop) {
                animate_with_gfx(g, time, fps, stop);
                repaint();
            } else {
                ((Timer)e.getSource()).stop();
            }
        }
    });
    t.setRepeats(true);
    t.setDelay((int)(1000/fps));
    t.start();
    System.exit(0);
}

这部分是完全错误的,因为只要 JRE 认为 View 需要重新绘制,就会调用 paintComponent() 方法。所以一定要删除 System.exit(0);!

那么计时器需要一个实例,启动一次。这最好在构造函数或 init() 类型方法中完成。

它可能看起来像这样:

private int fps = 3;
private boolean stop = false;

public void paintComponent(Graphics g){
    super.paintComponent(g);
    long time = 5000;
    animate_with_gfx(g, time, fps, stop);
}

/** Called from constructor..  */
public void init(){
    Timer t = new Timer((int)(1000/fps), new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            if(!stop) {
                repaint();
            } else {
                ((Timer)e.getSource()).stop();
            }
        }
    });
    t.setRepeats(true);
    t.setDelay((int)(1000/fps));
    t.start();
}

更新

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.event.*;
import javax.swing.*;

import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;

class SpriteSheetManager {

    private BufferedImage spriteSheet;
    int cols;
    int rows;

    public SpriteSheetManager() {
        setSpriteSheet();
    }

    public void setSpriteSheet() {
        try {
            spriteSheet = ImageIO.read(
                    new URL("http://s8.postimg.org/vso6oed91/spritesheet.png"));
            setColsAndRows(3, 3);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public BufferedImage getSpriteSheet() {
        return spriteSheet;
    }

    public void setColsAndRows(int cols, int rows) {
        this.cols = cols;
        this.rows = rows;
    }

    public Image getSprite(int x, int y) {
        Image sprite = null;
        try {
            sprite = spriteSheet.getSubimage(
                    x * spriteSheet.getWidth() / cols,
                    y * spriteSheet.getHeight() / rows,
                    spriteSheet.getWidth() / cols,
                    spriteSheet.getHeight() / rows);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sprite;
    }
}

class Ideone {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TestSpriteSheet();
            }
        });
    }

}

class TestSpriteSheet extends JFrame {

    private static final long serialVersionUID = 1L;
    private SpriteSheetManager ss;

    public TestSpriteSheet() {
        super("Testing SpriteSheets");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setResizable(false);
        setLayout(new BorderLayout());
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent windowEvent) {
                System.exit(0);
            }
        });

        ss = new SpriteSheetManager();

        add(new PanelSprite(this, ss));
        pack();
        setSize(200, 200);
        this.setVisible(true);
    }
}

class PanelSprite extends JPanel {

    private long runningTime = 0;
    private int fps = 10;
    private boolean stop = false;
    private SpriteSheetManager ss;
    private TestSpriteSheet temp;
    private Timer t;
    int count = 0;
    long time = 50000;

    public PanelSprite(TestSpriteSheet test, SpriteSheetManager sm) {
        ss = sm;
        temp = test;
        init();
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        animate_with_gfx(g);
    }

    public void init() {
        t = new Timer((int) (1000 / fps), new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (!stop) {
                    repaint();
                } else {
                    ((Timer) e.getSource()).stop();
                }
            }
        });
        t.setRepeats(true);
        t.setDelay((int) (1000 / fps));
        t.start();
    }

    public void animate_with_gfx(Graphics g) {
        if (runningTime <= time) {
            Image img = ss.getSprite((count % 9) % 3, (count % 9) / 3);
            g.drawImage(img, 40, 40, this);
            count++;
            runningTime += (1000 / fps);
        } else {
            stop = true;
        }
    }
}

关于java - JFrame 中的 Spritesheet 动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27417901/

相关文章:

java - 将鼠标位置分派(dispatch)给 JList 的自定义单元格渲染器中的组件

java - 当添加透明度时,为什么透明JButton会显示框架图像?

java - 重写 SwingWorker 中的 process() 方法

javascript - 无法使用 Javascript 为 div #box 设置动画

java - 读取受密码保护的工作表(版本 - excel 95,97-2003)Java

java - 即使 jars 包含在类路径中,Eclipse 类也未找到异常

java - 将堆栈元素移回到单链表

java - 多对一搜索查询

angularjs - 阻止 Angular 动画在 ng-show/ng-hide 上发生

javascript - 拉斐尔对 Angular 变换对象和无限 setIntervals