首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何删除动画中的最后一个图像

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

Stack Overflow用户
提问于 2014-03-08 13:22:28
回答 3查看 3.2K关注 0票数 1

我想要做的是创建一个动画,创建一个“跑步”的运动。每当我在屏幕上绘制它时,动画中的最后一帧都会留在后面(因此,当精灵移动时,会留下一系列动画帧)。我已经尝试了if语句和当框架改变时改变图像的绘制位置:

代码语言:javascript
复制
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);

有没有一种方法可以在删除拖尾图像的同时做到这一点?

EN

回答 3

Stack Overflow用户

发布于 2014-03-08 21:03:17

注意:示例程序中的以下代码存在一些逻辑错误。有关解释和修复的信息,请参阅

我注意到您正在尝试对动画图像使用不同的图像。您知道,您可以使用单个动画子画面(假设它的格式类似于模式的网格),只需在drawImage方法中更改特定x y位置的位置

代码语言:javascript
复制
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.

请参阅完整描述

也就是说,您可以使用javax.swing.Timer来动画源图像并更改其位置。

对于下面看到的所有示例,这里有一些使用相同代码的示例。我只是更改了图像,并相应地更改了SPRITE_ROWSSPRITE_COLUMNSDELAY。欲了解更多信息,请访问

代码语言:javascript
复制
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);
            }
        });
    }
}

票数 2
EN

Stack Overflow用户

发布于 2015-01-30 12:12:45

我知道它说“避免回复其他答案”,但作为一个新注册者(但长期用户),我只有资格写“答案”或建议编辑。我不能添加评论到一个答案,直到我被提升!:-)

然而,peeskillet的答案中的源代码中有太多的错误,无法简单地定义为“建议的编辑”:-)

  1. 行和列的意外交换/混淆:

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以保证精确性

"DIM_H“应为"DIM_W"

如列表所示,如果单个图像的高度明显大于它们的宽度,或者原始网格的每一行中都有许多图像,则此代码将导致过早跳转到网格中的下一行动画图像(不显示每行中的最后一幅图像)。对于nerdgirl示例(833x639),如果整个网格只高10个像素,则每行中的最后一张图像将不会显示。(DIM_H = 319,img.getWidth()-DIM_H-5 = 503,最后一帧显示x1Src =498时..only成功了!)

如图所示,

  1. 当前代码仅处理2行动画帧(即使它通过将SPRITE_COLUMNS (sic)更改为4来正确计算每个帧的大小)。

这是因为下面的if-test:

代码语言:javascript
复制
                    if (y1Src >= DIM_H - 5) { // 5 to take care of lack of prec
                        y1Src = 0;

..。应该是:

代码语言:javascript
复制
                    if (y1Src >= imag.getHeight() - DIM_H - 5) { // 5 to take car
                        y1Src = 0;

..as当前代码只显示2行sprite图像,即使有更多。(这解释了为什么扑动的鸟样本在没有显示最终的全白框架的情况下工作"ok“…仔细观察,它只显示前2行图像)。

  1. 使用硬编码5表示“精度损失”(意思是当源图像没有均匀地组合到组合网格中,并且它们不是帧大小的精确倍数时),实际上应该是指存在的帧数:

if (x1Src >= img.getWidth() - DIM_W - SPRITE_COLUMNS) { // - SPRITE_COLUMNS处理未对齐源图像(参见示例) if (y1Src >= img.getHeight() - DIM_H - SPRITE_ROWS) { // - SPRITE_ROWS处理未对齐源图像(参见示例)

这是因为在计算动画图像的宽度和高度时,可能的“精度损失”不会超过每行和每列中的每帧1个,这是由于整数舍入造成的。例如,833x639的nerdgirl样本计算了166x319的动画帧大小,因此在5个图像之后,我们显示了原始图像的830,638。

然而,我建议下面的内容将使这两个if语句更加清晰和简单:

代码语言:javascript
复制
                if (x2Src > img.getWidth()) {     // Beyond end of Row

                if (y2Src > img.getHeight()) {    // Beyond Last Row

..。还有一些其他的小调整,如下所示。

代码语言:javascript
复制
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. 最后,请注意,与这些问题无关的是,示例动画源网格的组合不佳(精灵-帧对齐方式并不总是一致的),因此在本页的示例中,您有时会看到相邻帧的片段。仔细观看上面的鸟帧动画并查看说明性图像herehere.)

如果网格都被编译为单个帧大小的整数倍(就像跑步者png image @ 900x600的情况一样-即使提供的示例有图片“重叠”-参见上面的图像链接),那么坐标检查的程序代码可能会更容易:

代码语言:javascript
复制
        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();
    }

但是,由于输入样本网格在整体大小和组成上不可靠,因此建议使用较早的代码,因为它将处理这些不一致。

从长远来看,我希望我的回答能为其他人节省一些宝贵的时间!

干杯,

票数 2
EN

Stack Overflow用户

发布于 2021-06-21 19:13:12

如果有人仍然有这个问题,我找到了答案,你可以使用paintComponent(),或者如果你坚持使用那个函数,你可以在循环或计时器中使用repaint()作为你的内容窗格。如下代码所示:

代码语言:javascript
复制
public void run(){
    getContentPane().repaint();
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22265452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档