我知道上面写着“避免回复其他答案”,但作为新注册者(但长期用户),我只能写“答案”或建议编辑。我不能添加 cmets 回答,直到我被投票! :-)
但是,peeskillet 的答案中的源代码错误太多,无法简单地称为“建议的编辑”:-)
-
ROWS 和 COLUMNS 的意外交换/混淆:
SPRITE_ROWS = 5;
SPRITE_COLUMNS = 2;
DIM_W = img.getWidth() / SPRITE_ROWS;
DIM_H = img.getHeight() / SPRITE_COLUMNS;
再往下看,该程序显然试图正确处理网格中动画图片的行和列,但这只是因为两者都是向后的,程序才能工作。 (即 nerdgirl 示例的图像网格中有 5 个列和 2 个行)。
-
DIM_H 和 DIM_W 的意外互换(1 次):
if (x1Src >= img.getWidth() - DIM_H - 5) { // 5 to take care of precisi
“DIM_H”应该是“DIM_W”
如所列,如果单个图像的高度明显高于宽度,或否则原始网格的每一行都有很多图像。对于 nerdgirl 样本 (833 x 639),如果整个网格仅高 10 像素,则不会显示每行中的最后一张图像。 (DIM_H = 319,img.getWidth()-DIM_H-5 = 503,最后一帧显示 x1Src = 498 ..刚刚成功!)
- 当前代码所示仅处理 2 行动画帧(即使认为它通过将例如 SPRITE_COLUMNS (sic) 更改为 4 来正确计算每个帧的 SIZE 以用于正在运行的 Man 示例)。
这是因为下面的 if-test :
if (y1Src >= DIM_H - 5) { // 5 to take care of lack of prec
y1Src = 0;
...应该是:
if (y1Src >= imag.getHeight() - DIM_H - 5) { // 5 to take car
y1Src = 0;
..因为当前代码只显示 2 行精灵图像,即使有更多。 (这解释了为什么拍打的鸟样本“正常”但没有显示最终的全白帧……仔细看,它只显示前 2 行图像)。
-
使用硬编码 5 表示“精度损失”(意味着当源图像没有均匀地组合到组合网格中并且它们不是帧大小的精确倍数时)实际上应该是指帧数现在:
if (x1Src >= img.getWidth() - DIM_W - SPRITE_COLUMNS) { // - SPRITE_COLUMNS to take care of non-aligned source images (see samples)
if (y1Src >= img.getHeight() - DIM_H - SPRITE_ROWS) { // - SPRITE_ROWS to take care of non-aligned source images (see samples)
这是因为可能的“精度损失”在每行和每列中每帧不超过 1 - 由计算动画图像宽度和高度时发生的整数舍入导致。例如,833 x 639 的 nerdgirl 样本计算出的动画帧大小为 166 x 319,因此在 5 张图像之后,我们显示了高达 830,638 的原始图像。
但是,我建议以下内容将使这两个 if 语句更加清晰和简单:
if (x2Src > img.getWidth()) { // Beyond end of Row
if (y2Src > img.getHeight()) { // Beyond Last Row
...还有一些其他的小调整,如下所示。
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class NerdGirl extends JPanel {
private static int SPRITE_COLUMNS = 5; // Number of columns of sprite images in source file
private static int SPRITE_ROWS = 2; // Number of rows of sprite images in source file
private static final int DELAY = 100; // inter-frame pause in milliseconds
private int dim_W; // Width of an individual animation frame
private int dim_H; // Height of an individual animation frame
private int x1Src; // top-left coordinates of current frame
private int y1Src;
private int x2Src; //bottom-right coordinates of current frame
private int y2Src;
private BufferedImage img;
public NerdGirl() {
try {
img = ImageIO.read(getClass().getResource("images/nerdgirl.jpg"));
SPRITE_ROWS = 2;
// Other sample files
//img = ImageIO.read(getClass().getResource("images/explosion.png"));
//SPRITE_ROWS = 3;
//img = ImageIO.read(getClass().getResource("images/birdflight.png"));
//SPRITE_ROWS = 3;
//img = ImageIO.read(getClass().getResource("images/running_man.png"));
//SPRITE_ROWS = 4;
//SPRITE_COLUMNS = 6;
} catch (IOException ex) {
Logger.getLogger(NerdGirl.class.getName()).log(Level.SEVERE, null, ex);
}
dim_W = img.getWidth() / SPRITE_ROWS;
dim_H = img.getHeight() / SPRITE_COLUMNS;
x1Src = 0;
y1Src = 0;
x2Src = x1Src + dim_W;
y2Src = y1Src + dim_H;
Timer timer = new Timer(DELAY, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Move right to next frame (next column)
x1Src += dim_W;
x2Src += dim_W;
if (x2Src > img.getWidth()) { // Past end of current row.
x1Src = 0; // Back to start of row
x2Src = dim_W;
y1Src += dim_H; // Move down to next Row
y2Src += dim_H;
if (y2Src > img.getHeight()) { // Below bottom of source grid of images
y1Src = 0; // Back to Top.
y2Src = dim_H;
}
}
repaint();
}
});
timer.start();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, getWidth(), getHeight(), x1Src, y1Src, x2Src, y2Src, this);
}
@Override
public Dimension getPreferredSize() {
return (img == null) ? new Dimension(300, 300) : new Dimension(dim_W, dim_H);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new NerdGirl());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
- 最后,请注意,与这些问题无关,示例动画源网格的组合很差(精灵帧对齐并不总是一致),因此在本页的示例中,您有时会看到相邻帧的碎片显示。仔细观看上面的鸟框动画,并查看说明图here 和here。)
如果网格全部编译为单个帧大小的整数倍(如运行 man png 图像@900x600 的情况 - 即使提供的示例具有图片“重叠” - 请参阅上面的图片链接) ,那么坐标检查的程序代码会更容易:
Timer timer = new Timer(DELAY, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Move right to next frame (next column)
x1Src += dim_W;
if (x1Src == img.getWidth()) { // At end of current row.
x1Src = 0; // Go Back to start of row
y1Src += dim_H; // Move down to next Row
if (y1Src == img.getHeight()) { // Past all images
y1Src = 0; // Back to Top.
}
}
x2Src += dim_W;
y2Src += dim_H;
repaint();
}
});
timer.start();
}
但是,由于输入样本网格的整体大小和组成不可靠,因此建议使用较早的代码,因为它可以处理这些不一致。
我希望我的回答从长远来看可以为其他人节省宝贵的时间!
干杯,