1

I am trying to get an animation using a spritesheet in JFrame. The problem is the once loaded, the image doesn't change. It only shows the first image. I have searched a lot and tried almost all the advice but can't get it to work.

By the way, getSprite has a return type of Image. When I do everything in JFrame, only one image is shown. When I do it in separate class extending JPanel, I get only a white Window.

Update 1: Thanks to andrew, got JFrame working. Fixed my old part too. Here's the working code at ideone

Update 2: Here's my version with timer.

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;
        }
    }
}
Palash
  • 498
  • 4
  • 12

1 Answers1

2
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);
}

This part is entirely wrong, since the paintComponent() method is called whenever the JRE thinks the view needs repainting. So definitely remove the System.exit(0);!

Then the Timer needs a single instance, to be started once. That would best be done in the constructor or an init() type method.

It might look something like this:

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();
}

Update

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;
        }
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • I removed System.exit(0), but nothing happened. Can you elaborate on "Then the Timer needs a single instance, to be started once. That would best be done in the constructor or an init() type method." ? – Palash Dec 11 '14 at 08:52
  • Nope, it still doesn't change the image. Updated the question. – Palash Dec 11 '14 at 09:04
  • 1
    `setLayout(new BorderLayout()); }` should be `setLayout(new BorderLayout()); init(); }`. That's what `Called from constructor` means! – Andrew Thompson Dec 11 '14 at 09:07
  • Did, but the image doesn't change. – Palash Dec 11 '14 at 09:08
  • 1) For better help sooner, post an [MCVE](http://stackoverflow.com/help/mcve) (Minimal Complete Verifiable Example) or [SSCCE](http://www.sscce.org/) (Short, Self Contained, Correct Example). 2) One way to get images for an example, is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). – Andrew Thompson Dec 11 '14 at 09:13
  • Thanks for the help! I figured it out later too, that there was also a problem in SpriteSheetManager. – Palash Dec 11 '14 at 14:31