如何在 Java 中创建 'cooldown rectangle' 效果?

How can I create a 'cooldown rectangle' effect in Java?

编辑:为了更具体一点,我想知道如何创建如图所示的超时效果。我知道绘制图像之类的,但我不了解超时效果背后的逻辑,因此出现了这个问题。


我一直在研究这个 'cooldown rectangle' 效果,它似乎可以在许多其他语言中实现,但到目前为止我还没有看到很多关于 Java 的解决方案。本质上我想创建一个函数来对图像产生这样的效果。

我已经知道叠加图像的基础知识,并且我遇到了一个 class,它可以做类似的事情,但在更广为人知的 'circular' 版本中。

我确实找到了 this tutorial,其中解释了如何使用 GameMaker 创建上述效果。但我不确定如何将这些知识转移到 Java。

如有任何帮助,我们将不胜感激。

那么,你需要的是...

  • 一些加载图像的方法
  • 一些绘制图像的方法
  • 在图像上绘制超时效果的一些方法
  • 一些定期更新UI的方法,计算剩余时间并更新UI

也许开始于:

例如...

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
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.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }

                    TimeOutPane tp = new TimeOutPane();
                    tp.addMouseListener(new MouseAdapter() {
                        @Override
                        public void mouseClicked(MouseEvent e) {
                            tp.executeTimeout();
                        }
                    });

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(tp);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    public class TimeOutPane extends JPanel {

        private BufferedImage background;
        private float progress = 0;
        private long startedAt;
        private int timeout = 5000;

        private Timer timer;

        public TimeOutPane() throws IOException {
            background = ImageIO.read(new File("/Volumes/Disk02/Dropbox/Ponies/url.png"));
        }

        public void setTimeout(int timeout) {
            this.timeout = timeout;
        }

        public int getTimeout() {
            return timeout;
        }

        public void setProgress(float progress) {
            this.progress = progress;
            repaint();
        }

        public float getProgress() {
            return progress;
        }

        public void executeTimeout() {
            if (timer == null) {
                timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        long diff = System.currentTimeMillis() - startedAt;
                        float progress = diff / (float) timeout;
                        if (diff >= timeout) {
                            progress = 1f;
                            timer.stop();
                        }
                        setProgress(progress);
                    }
                });
            } else if (timer.isRunning()) {
                timer.stop();
            }

            startedAt = System.currentTimeMillis();
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return background == null ? new Dimension(200, 200) : new Dimension(background.getWidth(), background.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (background != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                applyQualityRenderingHints(g2d);
                int x = (getWidth() - background.getWidth()) / 2;
                int y = (getHeight() - background.getHeight()) / 2;
                g2d.drawImage(background, x, y, this);

                g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
                g2d.setColor(Color.BLACK);

                int radius = Math.max(getWidth(), getHeight()) / 2;

                g2d.fillArc(-radius, -radius, radius * 4, radius * 4, 90, (int) (360f * (1f - progress)));

                g2d.dispose();
            }
        }

        public void applyQualityRenderingHints(Graphics2D g2d) {
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
        }

    }

}