尝试将整数范围转换为RGB颜色

时间:2017-10-25 09:05:51

标签: java colors

我知道你们都很忙,所以我要保持简短和重点。

我目前正在开发一款有趣的小游戏。游戏中有敌人。为简单起见,将它们视为彩色方块。我想最小化任何HUD,所以我决定通过它们的颜色平滑地显示生物的生命值 (绿色为健康,黄色为受损,红色为近乎死亡)。

见图片: enter image description here

然而,我真的很难想出一个将(int)hp值转换为RGB颜色的高效方法。映射到0-255的单个int根本不会成为问题 - 这是一个完全相同的示例函数:

public int mapHpToGreyscale(int input) {

    //input = current hp
    double minHealth = 0;
    double maxHealth = hpmax;
    double minColValue = 0;
    double maxColValue = 255;

    int output = (int) ((input - minHealth) / (maxHealth - minHealth) * (maxColValue - minColValue) + minColValue);

    return output;
}

有没有快速简便的方法来实现我想做的事情?我很感激任何意见。

4 个答案:

答案 0 :(得分:5)

说明

首先,我的回答是这个的改编版本:Calculate color values from green to red。我决定创建 JavaScript 解决方案的 Java 版本。代码,您可以直接插入代码而无需自己转移所有内容。

我们的想法是使用 HSL hue, saturation, lightness)颜色空间而不是 RGB (红色,绿色,蓝色)。红色由色调值表示,绿色由120°表示,黄色介于60°之间,其中<​​em>平滑过渡的色调:

Hue color circle HSL color space

我们会确定100%的饱和度和50%的亮度,但如果您愿意,可以使用这些值。

用法

以下是在代码中使用它的方法:

// A value between 1.0 (green) to 0.0 (red)
double percentage = ...
// Get the color (120° is green, 0° is red)
Color color = transitionOfHueRange(percentage, 120, 0);

这就是结果范围:

Hue range example

其他方法

这是transitionOfHueRange方法。它接受percentage0.0之间的1.0值以及hue0之间的360范围:

public static Color transitionOfHueRange(double percentage, int startHue, int endHue) {
    // From 'startHue' 'percentage'-many to 'endHue'
    // Finally map from [0°, 360°] -> [0, 1.0] by dividing
    double hue = ((percentage * (endHue - startHue)) + startHue) / 360;

    double saturation = 1.0;
    double lightness = 0.5;

    // Get the color
    return hslColorToRgb(hue, saturation, lightness);
}

这是hslColorToRgb函数。它接受从0.01.0 HSL 值:

public static Color hslColorToRgb(double hue, double saturation, double lightness) {
    if (saturation == 0.0) {
        // The color is achromatic (has no color)
        // Thus use its lightness for a grey-scale color
        int grey = percToColor(lightness);
        return new Color(grey, grey, grey);
    }

    double q;
    if (lightness < 0.5) {
        q = lightness * (1 + saturation);
    } else {
        q = lightness + saturation - lightness * saturation;
    }
    double p = 2 * lightness - q;

    double oneThird = 1.0 / 3;
    double red = percToColor(hueToRgb(p, q, hue + oneThird));
    double green = percToColor(hueToRgb(p, q, hue));
    double blue = percToColor(hueToRgb(p, q, hue - oneThird));

    return new Color(red, green, blue);
}

hueToRgb方法:

public static double hueToRgb(double p, double q, double t) {
    if (t < 0) {
        t += 1;
    }
    if (t > 1) {
        t -= 1;
    }

    if (t < 1.0 / 6) {
        return p + (q - p) * 6 * t;
    }
    if (t < 1.0 / 2) {
        return q;
    }
    if (t < 2.0 / 3) {
        return p + (q - p) * (2.0 / 3 - t) * 6;
    }
    return p;
}

最后是小实用程序方法percToColor

public static int percToColor(double percentage) {
    return Math.round(percentage * 255);
}

答案 1 :(得分:3)

此答案基于某人在评论中提到的Algorithm: How do I fade from Red to Green via Yellow using RGB values?的答案之一的算法。

请注意,此示例中未使用minHealthminColValue,但实现起来应该不会太难。

import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class HealthColors {

    static double minHealth = 0;// unused here
    static double maxHealth = 100;
    static double minColValue = 0;// unused here
    static double maxColValue = 255;

    public static void main(final String[] args) {

        JFrame frame = new JFrame();

        JPanel content = new JPanel();

        content.setLayout(new GridLayout(10, 10, 2, 2));

        for (int i = 0; i < maxHealth; i++) {

            int value = (int) (Math.random() * maxHealth + 1);

            JLabel label = new JLabel("" + value, SwingConstants.CENTER);
            label.setOpaque(true);
            label.setBackground(mapHpToColor(value));

            content.add(label);

        }

        frame.setContentPane(content);
        frame.pack();
        frame.setVisible(true);

    }

    public static Color mapHpToColor(final int input) {

        //input = current hp

        double redValue = (input > maxHealth / 2 ? 1 - 2 * (input - maxHealth / 2) / maxHealth : 1.0) * maxColValue;
        double greenValue = (input > maxHealth / 2 ? 1.0 : 2 * input / maxHealth) * maxColValue;
        double blueValue = 0;

        Color hpColor = new Color((int) redValue, (int) greenValue, (int) blueValue);

        return hpColor;
    }

}

enter image description here

答案 2 :(得分:2)

  

有没有快速简便的方法来实现我想要做的事情?

是的,有,你甚至可以重用你自己的代码,只是那些常量应该是参数:

public int mapHpToComponent(int input,
    double minHealth, double maxHealth,
    double minComponentValue, double maxComponentValue) {

    int output = (int) ((input - minHealth) / (maxHealth - minHealth) *
        (maxComponentValue - minComponentValue) + minComponentValue);

    return output;
}

然后将其应用于调色板片段。有两个,一个从HP = 0 ... 50开始,G = 0 ... 255,然后第二个段是HP = 50 ... 100和R = 255 ... 0:

public int mapHpToColor(int input){
    if(input<50){ // first segment
        int R=255;
        int G=mapHpToComponent(input,0,50,0,255);
        int B=0;
        return (R<<16)+(G<<8)+B;
    } else {
        int R=mapHpToComponent(input,50,100,255,0);
        int G=255;
        int B=0;
        return (R<<16)+(G<<8)+B;
    }
}

(是的,min / maxComponentValue可能更像是开始/结束,因为这就是它们的真实含义。)

答案 3 :(得分:1)

import java.lang.Math;

public class Color {
    public int r;
    public int g;
    public int b;
    public Color() {
        r = 0;
        g = 0;
        b = 0;
    }
};

public static Color hpToColor(float hp, float maxhp) {
    Color color = new Color();
    float alpha = hp / maxhp;

    if (alpha <= 0.5) {
        color.r = 255;
        color.g = Math.round((alpha * 2) * 255);
        color.b = 0;
    } else {
        color.r = Math.round(((1 - alpha) * 2) * 255);
        color.g = 255;
        color.b = 0;
    }

    return color;
}