可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
First of all you have a lot of white spaces between each line, it makes it hard to read the code.
Yes, you could try using a Swing Timer
, here is an example and another example and another example.
You have an empty catch
block which is not secure, at least do this:
catch (IOException e){
e.printStackTrace();
}
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
}
});
}
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
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);
}
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);
}
}
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.
回答2:
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);
}
}