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

9

我知道你们都很忙,所以我会简短明了地说明。我目前正在开发一个小游戏,游戏中有敌人。为了简化,可以把它们看作是有颜色的正方形。我想尽量减少任何HUD,所以我决定通过它们的颜色平滑地显示生物的打击点数(绿色表示健康,黄色表示受损,红色表示濒死)。

请查看图片:enter image description here

然而,我真的很难想出一种有效的方法将(int)hp-value转换为RGB颜色。将其映射到0-255的单个整数不会有任何问题 - 这是一个完全实现此功能的示例函数:

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

有没有一种快速简便的方法可以实现我想做的事情?我会感激任何意见。

1
{btsdaf} - AxelH
{btsdaf} - Zabuzard
2
{btsdaf} - Zabuzard
{btsdaf} - geza
这个方法是可行的,但是如果你通过插值将两个值平滑地从绿色过渡到红色,那么你在中间并不会得到黄色,而是棕色。点击查看图片 - Zabuzard
显示剩余2条评论
4个回答

9

说明

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

使用HSL色相、饱和度、亮度)颜色空间代替RGB(红、绿、蓝)。在这里,红色由色相值表示,绿色由120°表示,在60°处有黄色,并且在色相方面具有平滑过渡

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 方法。它接受一个 percentage 值,介于 0.01.0 之间,以及一个 hue 范围,介于 0360 之间:

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.0到1.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);
}

4
这个答案基于算法:如何使用RGB值从红色到绿色通过黄色淡化中的一个答案,该算法被评论中的某人提到。
请注意,此示例中未使用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
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;
}

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可以更好地称为start/end,因为这才是它们真正的含义。)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接