【问题标题】:Spritesheet Animation in JFrameJFrame 中的 Spritesheet 动画
【发布时间】:2014-12-11 07:58:50
【问题描述】:

我正在尝试使用 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;
        }
    }
}

【问题讨论】:

    标签: java swing animation jframe paintcomponent


    【解决方案1】:
    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 认为视图需要重新绘制,就会调用 paintComponent() 方法。所以一定要删除System.exit(0);

    那么 Timer 需要一个实例,才能启动一次。这最好在构造函数或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;
            }
        }
    }
    

    【讨论】:

    • 我删除了 System.exit(0),但什么也没发生。您能否详细说明“然后 Timer 需要一个实例,启动一次。最好在构造函数或 init() 类型方法中完成。” ?
    • 不,它仍然没有改变图像。更新了问题。
    • setLayout(new BorderLayout()); } 应该是 setLayout(new BorderLayout()); init(); }。这就是Called from constructor 的意思!
    • 有,但图像没有改变。
    • 1) 为了尽快获得更好的帮助,请发布MCVE(最小完整可验证示例)或SSCCE(简短、自包含、正确示例)。 2) 例如,获取图像的一种方法是热链接到在this Q&A 中看到的图像。
    猜你喜欢
    • 2015-11-27
    • 2014-03-25
    • 2012-04-21
    • 1970-01-01
    • 2018-10-10
    • 2013-10-27
    • 1970-01-01
    • 2012-01-10
    • 2014-06-28
    相关资源
    最近更新 更多