Java2d 中的动画图像

Animate Image in Java2d

我正在学习 Java2d,我正在尝试使用计时器在 x 坐标中为我的图像设置动画,但是没有用,这个想法是在一个时间帧之间,图像 x 值递增一个值使其移动,有人可以算出我的代码有什么问题?

代码如下:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class Screen extends JPanel {
    int posX;
    Timer timer;
    private BufferedImage image;

    public Screen() {
        setDoubleBuffered(true);
        posX = 1;
        timer = new Timer();
        timer.scheduleAtFixedRate(new Anima(), 100, 10);

        //Smile Icon
        try{
            image = ImageIO.read(getClass().getResource("/smily.png"));
        }catch(IOException e){

            e.printStackTrace();        
        }  

    }
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(image,this.posX,100,null);


    }

    class Anima extends TimerTask{

        public void run() {

            posX += 20;
            repaint();      

        }

    }

    public void incMove() {
        posX += 20;
    }

}

您的代码可以正常工作,但您的更新速度太快了。

尝试

timer.scheduleAtFixedRate(new Anima(), 100, 1000);

检查你的动画。

两个主要的东西:

  1. 延迟小
  2. 变化大

这意味着可以将对象快速移出可见边界,通常比在屏幕上实现屏幕更快。

您可以控制时间,但是,动画是随时间变化的错觉,您可能会发现减少变化的大小比延迟更好(尽管 100fps 可能要求有点高; ))

也没有边界检查,所以对象可以自由地离开可视区域,这可能是可取的,但可能至少会提示您遇到的问题。

由于 Swing 不是线程安全的(您不应该从 EDT 上下文之外更新 UI),您还 运行 存在线程竞争条件的风险。在这个例子中,这可能很难做到,但是你如何改变状态的概念是危险的。

因为 Swing 使用被动渲染引擎,绘制周期可能随时发生,而无需您的交互或知识,因此您应该小心更新绘制方法需要在 EDT 上下文之外呈现状态的变量.

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Screen extends JPanel {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new Screen());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private int posX;
    private int delta = 2;

    public Screen() {
        setDoubleBuffered(true);
        posX = 1;

        Timer timer = new Timer(10, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                incMove();
                repaint();
            }
        });
        timer.start();

    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); //To change body of generated methods, choose Tools | Templates.
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawRect(this.posX, 100, 10, 10);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 200);
    }

    public void incMove() {
        posX += delta;
        if (posX + 10 > getWidth()) {
            posX = getWidth() - 10;
            delta *= -1;
        } else if (posX < 0) {
            posX = 0;
            delta *= -1;
        }
    }

}

这个简单的示例使用 Swing Timer 作为主要引擎,它减少了更改量(至 2)并添加了边界检查

查看 Concurrency in Swing and How to use Swing Timers 了解更多详情