【问题标题】:Animated Sprites with Java Swing使用 Java Swing 的动画精灵
【发布时间】:2017-06-12 04:18:52
【问题描述】:

谁能告诉我如何减慢精灵的外观以创建更流畅的动画?当我运行代码时,它会出现在 JPanel 中的最后一个(第 27 个)精灵。动画处理太快了!

有人告诉我关于 Swing Timer,但不幸的是我尝试了几次,但我无法让代码运行良好:(

这是我到目前为止的代码:

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

假设创建一个从第一个精灵到最后一个(第 27 个)精灵的循环。

【问题讨论】:

  • 1) img = ImageIO.read(new File("images/dummy.png")); 应用程序资源将在部署时成为嵌入式资源,因此明智的做法是立即开始访问它们。 embedded-resource 必须通过 URL 而不是文件访问。请参阅info. page for embedded resource 了解如何形成 URL。 2)catch (IOException e) {} 应该是catch (IOException e) { e.printStackTrace(); } 3)public void paintComponent(Graphics g) { int[][] spriteSheetCoords 因为这个方法..
  • .. 可能会被多次调用,在方法之外声明数组更有意义。 4)for (int i = 0; i &lt;= 26; i++) { super.paintComponent(g);调用super方法一次,循环中不会多次。 5) g.drawImage(subSprite, 140, 120, null); 最好是g.drawImage(subSprite, 140, 120, this);,因为每个JComponent 都是ImageObserver 的一个实例。 6)作为一般性评论,您似乎在模糊地把代码语句扔在一起,希望某种组合能够奏效。这也被称为“魔法编码”,它永远不会奏效。弄清楚代码的含义。
  • “我只是没有太多 Java 知识” 好吧,@MadProgrammer 链接到本教程的两个部分,它们提供了 Java 知识。好好利用吧。

标签: java swing animation timer jpanel


【解决方案1】:
  1. 首先,每行之间有很多空格,这使得代码难以阅读。

  2. 是的,您可以尝试使用 Swing Timer,这里是 example 和另一个 example 和另一个 example

  3. 您有一个不安全的空 catch 块,至少这样做:

    catch (IOException e){
        e.printStackTrace();
    }
    
  4. 您没有将程序放在Event Dispatch Thread (EDT) 上来解决它,只需更改您的main 方法如下:

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                //Your constructor here
            }
        });
    }
    
  5. 您正在扩展JFrame,但没有使用由它生成的框架,同时您正在创建JFrame 的实例,请删除代码中的extends JFrame。相关阅读:Java Swing using extends JFrame vs calling it inside of class

  6. 而不是调用frm1.setSize(400, 400); 覆盖Painel1getPreferredSize() 方法以返回400, 400 的新Dimension 并调用frm1.pack()

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 400);
    }
    
  7. 动画处理太快了!

    不是动画处理太快,而是 for 循环阻止了 GUI 在结束之前被绘制,这就是为什么你只看到最后一个被绘制的精灵。


考虑到以上所有要点,您现在可以编写如下代码,其中包括使用 Swing Timer 和上述建议:

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

如您所见,Timer 有 50 毫秒的延迟以使精灵的过渡更平滑,您可以随意调整。

【讨论】:

  • 非常感谢@Frakcool,我会研究您发布的建议。
  • @PedroFigueiredo 如果答案解决了您的问题,请acceptit
  • 致投反对票的人,由于没有其他(质量较差的)答案被投反对票,并且该问题没有新的投反对票或接近投票,我们只能假设您对回答者有个人仇杀,并且/ 或实际上并不理解答案,除非您愿意努力提供有关如何使答案更好的建议,否则不会有任何改变。如果问题有问题,请投反对票和/或投票结束。请不要惩罚试图帮助他人的人
【解决方案2】:

我已经更改了一些精灵表坐标,因为我可以找到类似的图像,但它应该给你一个想法:

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

【讨论】:

  • 请注意 java.util.Timer 在其自己的线程上下文中执行,这在处理 Swing 时是一个糟糕的选择,因为在您更新它所依赖的状态时,Swing 可能会尝试绘制。另外,您应该将this 传递给drawImage
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-06
  • 1970-01-01
  • 2011-12-01
  • 2013-01-17
  • 1970-01-01
  • 2010-12-18
相关资源
最近更新 更多