-1

Can someone tell me how can I slowdown the sprites appearance to create a more smooth animation? When I run the code it appears the last (27th) sprite in the JPanel. The animation processing is too fast!

Someone told me about Swing Timer, but unfortunately I tried several times with that and I couldn't put the code to run well :(

Here is the code that I have so far:

package sprites;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Sprites extends JFrame {

public static void main(String[] args) {
    JFrame frm1 = new JFrame();
    frm1.setSize(400, 400);
    frm1.setLocationRelativeTo(null);
    frm1.setResizable(false);
    frm1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Painel1 pn1 = new Painel1();
    frm1.getContentPane().add(pn1);
    frm1.setVisible(true);
  }
}

class Painel1 extends JPanel {

    BufferedImage img;

    public Painel1() {
        setBackground(Color.yellow);
    try
    {
      img = ImageIO.read(new File("images/dummy.png"));
    }
    catch (IOException e)
    {}
  }

  @Override
  public void paintComponent(Graphics g) {
    int[][] spriteSheetCoords = {{8, 10, 119, 129}, 
                                 {138, 10, 118, 130},
                                 {267, 10, 118, 132},
                                 {402, 11, 113, 132},
                                 {538, 12, 106, 134},
                                 {671, 13, 103, 133},
                                 {804, 12, 102, 132},
                                 {23, 161, 100, 134},
                                 {157, 162, 96, 134},
                                 {287, 159, 95, 135},
                                 {418, 158, 95, 133},
                                 {545, 159, 99, 133},
                                 {673, 159, 102, 134},
                                 {798, 158, 108, 130},
                                 {9, 309, 116, 126},
                                 {137, 309, 118, 127},
                                 {274, 310, 110, 128},
                                 {412, 311, 102, 129},
                                 {541, 312, 103, 130},
                                 {671, 312, 104, 131},
                                 {806, 312, 98, 132},
                                 {29, 463, 94, 135},
                                 {155, 462, 98, 135},
                                 {279, 461, 104, 135},
                                 {409, 461, 106, 135},
                                 {536, 461, 109, 135},
                                 {662, 461, 112, 133}};
    Image subSprite;
    for (int i = 0; i <= 26; i++) {
      super.paintComponent(g);
      subSprite = img.getSubimage(spriteSheetCoords[i][0], spriteSheetCoords[i][1], spriteSheetCoords[i][2], spriteSheetCoords[i][3]);
      g.drawImage(subSprite, 140, 120, null);
    }
  }  
}

It is suppose to create a loop from the 1st sprite to the last (the 27th) sprite.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Pedro Figueiredo
  • 457
  • 5
  • 13
  • 2
    [A more advanced approach](http://stackoverflow.com/questions/35472233/load-a-sprites-image-in-java/35472418#35472418) and [basic principle example](http://stackoverflow.com/questions/35979697/java-basic-2d-game-animation-stutter/35979771#35979771) – MadProgrammer Jan 26 '17 at 19:37
  • 1
    I also suggest having a look at [Concurrency in Swing](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/) and [How to use Swing Timers](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) – MadProgrammer Jan 26 '17 at 19:39
  • 1
    1) `img = ImageIO.read(new File("images/dummy.png"));` Application resources will become embedded resources by the time of deployment, so it is wise to start accessing them as if they were, right now. An [tag:embedded-resource] must be accessed by URL rather than file. See the [info. page for embedded resource](http://stackoverflow.com/tags/embedded-resource/info) for how to form the URL. 2) `catch (IOException e) {}` should be `catch (IOException e) { e.printStackTrace(); }` 3) `public void paintComponent(Graphics g) { int[][] spriteSheetCoords` since this method .. – Andrew Thompson Jan 27 '17 at 03:55
  • .. might be called many times, it make more sense to declare the array outside the method. 4) `for (int i = 0; i <= 26; i++) { super.paintComponent(g);` Call the super method once, not many times in a loop. 5) `g.drawImage(subSprite, 140, 120, null);` thould best be `g.drawImage(subSprite, 140, 120, this);` since every `JComponent` is an instance of an `ImageObserver`. 6) As a general comment, it seems like you are tossing code statements together in the vague hope that some combination will work. This is also known as 'coding by magic' and it never works. Figure out what code means. – Andrew Thompson Jan 27 '17 at 03:59
  • Thank you all for your tips. No @AndrewThompson i'm not coding by magic, i just don't have many knowledge of Java :( – Pedro Figueiredo Jan 27 '17 at 18:41
  • 1
    *"i just don't have many knowledge of Java"* Well @MadProgrammer linked to two parts of the tutorial that gives knowledge of Java. Make use of it. – Andrew Thompson Jan 27 '17 at 19:24

2 Answers2

5
  1. First of all you have a lot of white spaces between each line, it makes it hard to read the code.

  2. Yes, you could try using a Swing Timer, here is an example and another example and another example.

  3. You have an empty catch block which is not secure, at least do this:

    catch (IOException e){
        e.printStackTrace();
    }
    
  4. You're not placing your program on the Event Dispatch Thread (EDT) to solve it just change your main method as follows:

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                //Your constructor here
            }
        });
    }
    
  5. You're extending JFrame but not making use of the frame generated by it, and at the same time you're creating an instance of a JFrame, remove the extends JFrame in your code. Related reading: Java Swing using extends JFrame vs calling it inside of class

  6. Instead of calling frm1.setSize(400, 400); override the Painel1's getPreferredSize() method to return a new Dimension of 400, 400 and call frm1.pack()

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 400);
    }
    
  7. The animation processing is too fast!

    It's not the animation processing too fast, but the for loop prevents the GUI to be painted before it ends, that's why you're only seeing the last sprite being painted.


With all the above points in mind, you now can have your code as follows, which includes the use of a Swing Timer and the above recommendations already included:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Sprites {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frm1 = new JFrame();
                Painel1 pn1 = new Painel1();
                frm1.getContentPane().add(pn1);

                frm1.pack();
                frm1.setVisible(true);
                frm1.setLocationRelativeTo(null);
                frm1.setResizable(false);
                frm1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        });
    }
}

class Painel1 extends JPanel {

    int[][] spriteSheetCoords = { { 8, 10, 119, 129 }, { 138, 10, 118, 130 }, { 267, 10, 118, 132 },
            { 402, 11, 113, 132 }, { 538, 12, 106, 134 }, { 671, 13, 103, 133 }, { 804, 12, 102, 132 },
            { 23, 161, 100, 134 }, { 157, 162, 96, 134 }, { 287, 159, 95, 135 }, { 418, 158, 95, 133 },
            { 545, 159, 99, 133 }, { 673, 159, 102, 134 }, { 798, 158, 108, 130 }, { 9, 309, 116, 126 },
            { 137, 309, 118, 127 }, { 274, 310, 110, 128 }, { 412, 311, 102, 129 }, { 541, 312, 103, 130 },
            { 671, 312, 104, 131 }, { 806, 312, 98, 132 }, { 29, 463, 94, 135 }, { 155, 462, 98, 135 },
            { 279, 461, 104, 135 }, { 409, 461, 106, 135 }, { 536, 461, 109, 135 }, { 662, 461, 112, 133 } };

    int i = 0;
    BufferedImage img;

    private ActionListener actionListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            i++;
            if (i == spriteSheetCoords.length) {
                i = 0;
            }
            revalidate();
            repaint();
        }
    };

    public Painel1() {
        Timer timer = new Timer(50, actionListener);
        timer.setInitialDelay(0);
        timer.start();
        setBackground(Color.yellow);
        try {
            img = ImageIO.read(new File("/home/jesus/Pictures/tokyo.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        Image subSprite;
        super.paintComponent(g);
        subSprite = img.getSubimage(spriteSheetCoords[i][0], spriteSheetCoords[i][1], spriteSheetCoords[i][2], spriteSheetCoords[i][3]);
        g.drawImage(subSprite, 140, 120, null);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 400);
    }
}

enter image description here

As you can see the Timer has a delay of 50ms to make the transition of the sprites smoother, you can adjust it as you please.

Community
  • 1
  • 1
Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • Many thanks @Frakcool, i will study the recommendations that you post. – Pedro Figueiredo Jan 27 '17 at 18:43
  • @PedroFigueiredo if the answer solved your problem, please [accept](http://stackoverflow.com/help/accepted-answer) it – Frakcool Jan 27 '17 at 19:14
  • 2
    To the downvoter, since none of the other (less quality) answers have been downvoted and the question has no new downvotes or close votes, we can only assume you either have a personal vendetta against the answerer and/or don't actually understand the answer, unless you're willing to make an effort to offer suggestions on how to make the answer better, nothing is going to change. If there is a problem with the question, the downvote it and/or vote to close it. Please don't punish people for trying to help others – MadProgrammer Jan 27 '17 at 21:25
0

I have changed some sprite sheet coords because I could find a similar image, but it should give you the idea:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
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.JFrame;
import javax.swing.JPanel;

public class Sprites extends JFrame {

    public static void main(String[] args) {
        JFrame frm1 = new JFrame();
        frm1.setSize(400,400);
        frm1.setLocationRelativeTo(null);
        frm1.setResizable(false);
        frm1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Painel1 pn1 = new Painel1();
        frm1.getContentPane().add(pn1);
        frm1.setVisible(true);
    }

}

class Painel1 extends JPanel {

    BufferedImage img;
    Timer timer;
    int i;
    Image subSprite;
    int[][] spriteSheetCoords = { { 8, 10, 119, 129 }, { 138, 10, 118, 130 }, { 267, 10, 118, 132 },
            { 402, 11, 113, 132 }, { 538, 12, 106, 134 }, { 671, 13, 103, 133 }, { 671, 12, 102, 132 },
            { 23, 161, 100, 134 }, { 157, 162, 96, 134 }, { 287, 159, 95, 135 }, { 418, 158, 95, 133 },
            { 545, 159, 99, 133 }, { 673, 159, 102, 134 }, { 550, 158, 108, 130 }, { 9, 309, 116, 126 },
            { 137, 309, 118, 127 }, { 274, 310, 110, 128 }, { 412, 311, 102, 129 }, { 541, 312, 103, 130 },
            { 671, 312, 104, 131 }, { 600, 312, 98, 132 }, { 29, 463, 94, 135 }, { 155, 462, 98, 135 },
            { 279, 461, 104, 135 }, { 409, 461, 106, 135 }, { 536, 461, 109, 135 }, { 662, 461, 112, 133 } };

    public Painel1() {
        setBackground(Color.yellow);
        try
        {
            img = ImageIO.read(new File("images/ddd.png"));
            timer = new Timer();
            timer.scheduleAtFixedRate(new TimerTask() {
                @Override
                public void run() {
                    subSprite = img.getSubimage(spriteSheetCoords[i][0], spriteSheetCoords[i][1], spriteSheetCoords[i][2],
                            spriteSheetCoords[i][3]);
                    i++;
                    repaint();
                    revalidate();
                }
            }, 500, 500);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(subSprite, 140, 120, null);
    }
}
uahakan
  • 576
  • 1
  • 6
  • 23
  • 2
    Just beware that `java.util.Timer` executes within its own thread context, making it a bad choice when dealing with Swing as Swing could be trying paint while you're updating a state it relies on. Also, you should be passing `this` to `drawImage` – MadProgrammer Jan 26 '17 at 19:33