/ / Java: transición de color suave - java, animación, colores, transiciones

Java: transición de color suave - java, animación, colores, transiciones

Estoy tratando de hacer un health bar, y como podría ser original, comenzará en verde, y después de perder salud, encontrará que se volverá amarillo, luego naranja, luego rojo ... 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 un IllegalArgumentException normalmente Red y Green, y mi suposición es que está por encima del 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));

Realmente no funcionó, y no tengo ni idea de cómo puedo lograrlo transition como yo quisiera.

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

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 cierta values del 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 a hacer, y un color Eso es una base. No estoy tan seguro si necesito un color por corriente. 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 estoy intentando, todo lo que sé con certeza es que necesito una base color, y proporcioné un enlace a una respuesta que vi, pero realmente no pude entenderlo. Con la información dada, ¿cómo podría obtenerla? transition colors ?

Respuestas

11 para la respuesta № 1

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

He usado este enfoque para generar una transición de gradiente que mezcla varios colores, como se demostró aquí

Básicamente, este enfoque le permite configurar una serie de colores y marcas de porcentaje para que obtenga un control mucho mayor sobre los puntos de transición de los colores.

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

5 para la respuesta № 2

DE ACUERDO, antes de Mad publicó su respuesta (y 1+), yo también estaba trabajando en esto, así que bien 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<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);
}
}