Java: Smooth Color Transition

前端 未结 2 1584
慢半拍i
慢半拍i 2020-11-27 08:31

I am trying to make a health bar, and as what might be original, it will start out green, and after losing health you find that it will turn yellow, then orange

相关标签:
2条回答
  • 2020-11-27 09:19

    OK, before Mad posted his answer (and 1+ to it), I was working on this too, so I might as well post what I came up with....

    import java.awt.*;
    import java.awt.event.*;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.util.EnumMap;
    import java.util.Map;
    import javax.swing.*;
    import javax.swing.event.*;
    
    @SuppressWarnings("serial")
    public class ColorTransition extends JPanel {
    
       private static final int TRANSITION_DELAY = 30;
       private static final int PREF_W = 800;
       private static final int PREF_H = 600;
       private RgbSliderPanel rgbSliderPanel1 = new RgbSliderPanel("Color 1");
       private RgbSliderPanel rgbSliderPanel2 = new RgbSliderPanel("Color 2");
       private Color background1;
       private Color background2;
       private JButton button = new JButton(new ButtonAction("Push Me"));
    
       public ColorTransition() {
          setBackground(Color.black);
    
          add(rgbSliderPanel1.getMainPanel());
          add(rgbSliderPanel2.getMainPanel());
    
          add(button);
    
          rgbSliderPanel1.addPropertyChangeListener(new PropertyChangeListener() {
    
             @Override
             public void propertyChange(PropertyChangeEvent evt) {
                if (RgbSliderPanel.COLOR.equals(evt.getPropertyName())) {
                   setBackground(rgbSliderPanel1.calculateColor());
                }
             }
          });
       }
    
       @Override
       public Dimension getPreferredSize() {
          return new Dimension(PREF_W, PREF_H);
       }
    
       @Override
       public void setEnabled(boolean enabled) {
          super.setEnabled(enabled);
          button.setEnabled(enabled);
          rgbSliderPanel1.setEnabled(enabled);
          rgbSliderPanel2.setEnabled(enabled);
       }
    
       private class ButtonAction extends AbstractAction {
    
          public ButtonAction(String name) {
             super(name);
          }
    
          @Override
          public void actionPerformed(ActionEvent e) {
             ColorTransition.this.setEnabled(false);
             background1 = rgbSliderPanel1.calculateColor();
             background2 = rgbSliderPanel2.calculateColor();
    
             setBackground(background1);
    
             Timer timer = new Timer(TRANSITION_DELAY, new TransitionListener());
             timer.start();
          }
    
          private class TransitionListener implements ActionListener {
             private int index = 0;
    
             @Override
             public void actionPerformed(ActionEvent e) {
                if (index > 100) {
                   ((Timer) e.getSource()).stop();
                   ColorTransition.this.setEnabled(true);
                } else {
                   int r = (int) (background2.getRed() * index / 100.0 + background1
                         .getRed() * (100 - index) / 100.0);
                   int g = (int) (background2.getGreen() * index / 100.0 + background1
                         .getGreen() * (100 - index) / 100.0);
                   int b = (int) (background2.getBlue() * index / 100.0 + background1
                         .getBlue() * (100 - index) / 100.0);
                   setBackground(new Color(r, g, b));
                }
                index++;
             }
          }
       }
    
       private static void createAndShowGui() {
          JFrame frame = new JFrame("ColorTransition");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.getContentPane().add(new ColorTransition());
          frame.pack();
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
       }
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                createAndShowGui();
             }
          });
       }
    }
    
    enum Rgb {
       RED("Red"), GREEN("Green"), BLUE("Blue");
       private String name;
    
       private Rgb(String name) {
          this.name = name;
       }
    
       public String getName() {
          return name;
       }
    }
    
    class RgbSliderPanel {
       public static final String COLOR = "color";
       private JPanel mainPanel = new JPanel();
       private SwingPropertyChangeSupport propertyChangeSupport = new SwingPropertyChangeSupport(
             this);
       private Map<Rgb, JSlider> colorSliderMap = new EnumMap<>(Rgb.class);
       private String name;
       protected Color color;
    
       public RgbSliderPanel(String name) {
          this.name = name;
          mainPanel.setBorder(BorderFactory.createTitledBorder(name));
          //mainPanel.setOpaque(false);
          mainPanel.setLayout(new GridLayout(0, 1));
          for (Rgb rgb : Rgb.values()) {
             JSlider colorSlider = new JSlider(0, 255, 0);
             colorSliderMap.put(rgb, colorSlider);
             mainPanel.add(colorSlider);
             colorSlider.setBorder(BorderFactory.createTitledBorder(rgb.getName()));
             colorSlider.setPaintTicks(true);
             colorSlider.setPaintTrack(true);
             colorSlider.setMajorTickSpacing(50);
             colorSlider.setMinorTickSpacing(10);
             colorSlider.addChangeListener(new ChangeListener() {
    
                @Override
                public void stateChanged(ChangeEvent e) {
                   Color oldValue = color;
                   Color newValue = calculateColor();
                   color = newValue;
                   propertyChangeSupport.firePropertyChange(COLOR, oldValue,
                         newValue);
                }
             });
    
          }
       }
    
       public JComponent getMainPanel() {
          return mainPanel;
       }
    
       public void setEnabled(boolean enabled) {
          for (JSlider slider : colorSliderMap.values()) {
             slider.setEnabled(enabled);
          }
       }
    
       public Color calculateColor() {
          int r = colorSliderMap.get(Rgb.RED).getValue();
          int g = colorSliderMap.get(Rgb.GREEN).getValue();
          int b = colorSliderMap.get(Rgb.BLUE).getValue();
          return new Color(r, g, b);
       }
    
       public String getName() {
          return name;
       }
    
       public void addPropertyChangeListener(PropertyChangeListener listener) {
          propertyChangeSupport.addPropertyChangeListener(listener);
       }
    
       public void removePropertyChangeListener(PropertyChangeListener listener) {
          propertyChangeSupport.removePropertyChangeListener(listener);
       }
    }
    
    0 讨论(0)
  • 2020-11-27 09:20

    I spent a lot of time trying to find/create a blending algorithm that worked for me, this is basically what I was able to hobble together.

    I've used this approach to generate a gradient transition mixing multiple colors, as demonstrated here

    Basically, this approach allows you to set up a series of colors and percentage marks so that you gain much greater control over which points the colors transition between.

    Blend

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.text.NumberFormat;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JSlider;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    
    public class ColorFading {
    
        public static void main(String[] args) {
            new ColorFading();
        }
    
        public ColorFading() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new FadePane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class FadePane extends JPanel {
    
            private final float[] fractions = new float[]{0f, 0.5f, 1f};
            private final Color[] colors = new Color[]{Color.RED, Color.YELLOW, Color.GREEN};
            private float progress = 1f;
            private JSlider slider;
    
            public FadePane() {
                slider = new JSlider(0, 100);
                setLayout(new BorderLayout());
                add(slider, BorderLayout.SOUTH);
    
                slider.addChangeListener(new ChangeListener() {
                    @Override
                    public void stateChanged(ChangeEvent e) {
                        progress = ((float)slider.getValue() / 100f);
                        repaint();
                    }
                });
                slider.setValue(100);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                int width = getWidth();
                int height = getHeight();
                Color startColor = blendColors(fractions, colors, progress);
                g2d.setColor(startColor);
                g2d.fillRect(0, 0, width, height);
                g2d.dispose();
            }
        }
    
        public static Color blendColors(float[] fractions, Color[] colors, float progress) {
            Color color = null;
            if (fractions != null) {
                if (colors != null) {
                    if (fractions.length == colors.length) {
                        int[] indicies = getFractionIndicies(fractions, progress);
    
                        float[] range = new float[]{fractions[indicies[0]], fractions[indicies[1]]};
                        Color[] colorRange = new Color[]{colors[indicies[0]], colors[indicies[1]]};
    
                        float max = range[1] - range[0];
                        float value = progress - range[0];
                        float weight = value / max;
    
                        color = blend(colorRange[0], colorRange[1], 1f - weight);
                    } else {
                        throw new IllegalArgumentException("Fractions and colours must have equal number of elements");
                    }
                } else {
                    throw new IllegalArgumentException("Colours can't be null");
                }
            } else {
                throw new IllegalArgumentException("Fractions can't be null");
            }
            return color;
        }
    
        public static int[] getFractionIndicies(float[] fractions, float progress) {
            int[] range = new int[2];
    
            int startPoint = 0;
            while (startPoint < fractions.length && fractions[startPoint] <= progress) {
                startPoint++;
            }
    
            if (startPoint >= fractions.length) {
                startPoint = fractions.length - 1;
            }
    
            range[0] = startPoint - 1;
            range[1] = startPoint;
    
            return range;
        }
    
        public static Color blend(Color color1, Color color2, double ratio) {
            float r = (float) ratio;
            float ir = (float) 1.0 - r;
    
            float rgb1[] = new float[3];
            float rgb2[] = new float[3];
    
            color1.getColorComponents(rgb1);
            color2.getColorComponents(rgb2);
    
            float red = rgb1[0] * r + rgb2[0] * ir;
            float green = rgb1[1] * r + rgb2[1] * ir;
            float blue = rgb1[2] * r + rgb2[2] * ir;
    
            if (red < 0) {
                red = 0;
            } else if (red > 255) {
                red = 255;
            }
            if (green < 0) {
                green = 0;
            } else if (green > 255) {
                green = 255;
            }
            if (blue < 0) {
                blue = 0;
            } else if (blue > 255) {
                blue = 255;
            }
    
            Color color = null;
            try {
                color = new Color(red, green, blue);
            } catch (IllegalArgumentException exp) {
                NumberFormat nf = NumberFormat.getNumberInstance();
                System.out.println(nf.format(red) + "; " + nf.format(green) + "; " + nf.format(blue));
                exp.printStackTrace();
            }
            return color;
        }
    }
    
    0 讨论(0)
提交回复
热议问题