Java: transición suave del color

Estoy tratando de hacer una health bar , y como lo que podría ser original, comenzará en verde, y después de perder la salud, verá que se volverá amarilla, naranja, roja … o algo relacionado con eso.

Intenté usar el método proporcionado en este enlace: https://stackoverflow.com/questions/19841477/java-smooth-color-transition

El resultado de ese enlace fue este código, solo una prueba del valor 100 a 0, pero terminó en una IllegalArgumentException en normalmente Red y Green , y mi suposición de razón es que supera el valor de 255.

 Color to = Color.red; Color base = Color.green; int red = (int)Math.abs((100 * to.getRed()) + ((1 - 100) * base.getRed())); int green = (int)Math.abs((100 * to.getGreen()) + ((1 - 100) * base.getGreen())); int blue = (int)Math.abs((100 * to.getBlue()) + ((1 - 100) * base.getBlue())); setForeground(new Color(red, green, blue)); 

En realidad, no funcionó, y no tengo absolutamente ninguna idea de cómo puedo lograr la transition la manera que me gustaría.

Entonces, dentro de mi clase HealthBar , tengo un método update()

 public void update() { if (getValue() < 10) setForeground(Color.red); else if (getValue() < 25) setForeground(Color.orange); else if (getValue() < 60) setForeground(Color.yellow); else setForeground(Color.green); } 

Este código hace una transición básica en ciertos puntos.

Necesito crear campos para usar ciertos colors en ciertos values de la health bar , así que ahora tengo esto …

 if (getValue() < 10) { Color to = Color.black; // Color current = getForeground() ? Color from = Color.red; // ? } 

Solo voy a usar un ejemplo para el último bit.

Entonces sé que voy a tener un color que voy, y un color que sea una base. No estoy seguro de si necesito un color para la stream. El problema que veo ahora es para los pasos de la transición porque cada transición tiene una cantidad diferente de pasos.

Resumen y pregunta
No sé cómo lograr lo que bash, todo lo que sé con certeza es que necesito un color base y base, y proporcioné un enlace a una respuesta que vi, pero no pude entenderlo. Con la información dada, ¿cómo podría obtener transition colors ?

Pasé mucho tiempo tratando de encontrar / crear un algoritmo de mezcla que funcionó para mí, esto es básicamente lo que pude coartar juntos.

He utilizado este enfoque para generar una transición de degradado que mezcla varios colores, como se demuestra aquí

Básicamente, este enfoque le permite configurar una serie de colores y marcas de porcentaje para que gane un control mucho mayor sobre los puntos en los que los colores se mueven.

Mezcla

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

OK, antes de que Mad publicara su respuesta (y 1+ a ella), también estaba trabajando en esto, así que también podría publicar lo que se me ocurrió …

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