如何删除动画中的最后一个图像

我要做的是创建一个动画,创建一个“运行”的动作。 每当我在屏幕上绘制它时,动画中的最后一帧都会被遗留(因此当精灵移动时会留下一些动画帧的痕迹)。 我已经尝试过if语句并在帧更改时更改图像的绘制位置:

if(a2.sceneNum() == 0) spectre_Draw1 = (screenWidth() / 2 - 120 / 2 + 120 - 6); else spectre_Draw1 = 0; g.drawImage(pic[2], spectre_Draw1, (screenHeight() / 2 - 180 / 2), null); if(a2.sceneNum() == 1) spectre_Draw2 = (screenWidth() / 2 - 120 / 2 + 120 - 6); else spectre_Draw2 = 0; g.drawImage(pic[3], spectre_Draw2, (screenHeight() / 2 - 180 / 2), null); if(a2.sceneNum() == 2) spectre_Draw3 = (screenWidth() / 2 - 120 / 2 + 120 - 6); else spectre_Draw3 = 0; g.drawImage(pic[4], spectre_Draw3, (screenHeight() / 2 - 180 / 2), null); 

有没有办法在删除尾随图像时执行此操作?

我知道它说“避免回答其他答案”但作为一个新的注册人(但长期用户)我只有资格写“答案”或建议编辑..我不能在答案中添加评论 ,直到我被投票! 🙂

但是,在peeskillet的答案中,源代码中的错误太多,只是简单地称为“建议编辑”:-)

  1. ROWS和COLUMNS的意外交换/混淆:

      SPRITE_ROWS = 5; SPRITE_COLUMNS = 2; DIM_W = img.getWidth() / SPRITE_ROWS; DIM_H = img.getHeight() / SPRITE_COLUMNS; 

在代码的下方,程序显然正在尝试正确处理网格中动画图片的行和列,但这只是因为这两个都是程序工作的向后。 (即样本nerdgirl的图像网格中有5 和2 )。

  1. 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 ..仅仅是它!)

  1. 如图所示的当前代码仅处理2行动画帧(甚至认为通过将例如SPRITE_COLUMNS(原文如此)改为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行精灵图像,即使有更多。 (这就解释了为什么拍打鸟样本工作“没问题”而没有显示最终的全白框架……仔细看,它只显示前两行图像)。

  1. 使用硬编码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); } }); } } 
  1. 最后,请注意,独立于这些问题,样本动画源网格很难放在一起(精灵帧对齐并不总是一致),因此在此页面上的示例中,您有时会看到相邻帧的片段。 仔细观察上面的鸟帧动画,并在此处和此处查看说明图像。)

如果网格全部被编译为单个帧大小的整数倍(如运行人png图像@ 900×600的情况 – 即使所提供的样本具有图片“重叠” – 请参见上面的图像链接),然后坐标检查的程序代码可能更容易:

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

但是,由于输入样本网格的总体大小和组成不可靠,因此建议使用较早的代码,因为它将解决这些不一致问题。

从长远来看,我希望我的回答可以节省一些宝贵的时间!

干杯,

注意:示例程序中的下面的代码有一些逻辑错误。 请参阅Warren K的答案以获得解释和修复

我注意到你正在尝试为动画图像使用不同的图像。 你知道你可以使用一个动画精灵(假设它的格式为网格状图案),只需更改drawImage方法中某些x y位置的位置

 public abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) img - the specified image to be drawn. This method does nothing if img is null. dx1 - the x coordinate of the first corner of the destination rectangle. dy1 - the y coordinate of the first corner of the destination rectangle. dx2 - the x coordinate of the second corner of the destination rectangle. dy2 - the y coordinate of the second corner of the destination rectangle. sx1 - the x coordinate of the first corner of the source rectangle. sy1 - the y coordinate of the first corner of the source rectangle. sx2 - the x coordinate of the second corner of the source rectangle. sy2 - the y coordinate of the second corner of the source rectangle. observer - object to be notified as more of the image is scaled and converted. 

查看完整描述API

话虽这么说,您可以使用javax.swing.Timer来设置动画并更改源图像的位置。

以下是您在下面看到的所有示例中使用相同代码的一些示例。 我只是更改了图像并相应地更改了SPRITE_ROWSSPRITE_COLUMNSDELAY 。 有关如何使用Swing Times的更多信息,请参阅

 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 final int SPRITE_ROWS = 5; private static final int SPRITE_COLUMNS = 2; private static final int DELAY = 150; private int DIM_W; private int DIM_H; private int x1Src; private int y1Src; private int x2Src; private int y2Src; private BufferedImage img; public NerdGirl() { try { img = ImageIO.read(getClass().getResource("/resources/nerd-girl.jpg")); } 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) { if (x1Src >= img.getWidth() - DIM_H - 5) { // 5 to take care of precision loss x1Src = 0; x2Src = x1Src + DIM_W; if (y1Src >= DIM_H - 5) { // 5 to take care of precision loss y1Src = 0; y2Src = y1Src + DIM_H; } else { y1Src += DIM_H; y2Src = y1Src + DIM_H; } } else { x1Src += DIM_W; x2Src = x1Src + DIM_W; } 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); } }); } } 

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述