Unity3D 插件开发教程 #3:制作拾色器 ColorPicker

作者:Lawliet
2017-08-30
6 6 1

编者按

本文已于作者 @Lawliet 授权转载,原载于知乎,如需转载请务必联系原作者。

正文

Unity有一个自带的 Color 拾色器面板,只有16进制(例如D5B1B1FF)显示,而 32位 显示(213, 177, 177, 255)的颜色值是分开四个输入框的,复制起来很不方便。可是我们项目开发时,使用的 ColorColor32 类却不能使用16进制,所以有时候拾取的颜色值要用到代码里需要大费周章。

1

所以今天要做一个颜色拾取器,用于同时显示16进制归一化颜色值32位颜色值

2
知识要点:

  • EditorWindow
  • EditorGUILayout.TextField
  • EditorGUILayout.ColorField
  • ColorUtility

使用版本:

  • Unity3D 5.3.3

目标:

  • 继续深入学习 EditorGUILayout 类其他功能。

整个插件的结构:

3

像上一节教程一样,我们要先创建一个 EditorWindow 面板类。 怎么样创建 Editor 目录的内容就不再这多说,有疑惑可以看回前两章的教程内容。

public class ColorPickerWindow : EditorWindow
{
    [MenuItem("Tools/ColorPicker")]
    public static void ShowWindow()
    {
        //调用GetWindow创建一个面板
        EditorWindow.GetWindow("ColorPicker");
    }
}

然后是在 ColorPickerWindow 内定义四个属性,用于记录四种颜色表示方式的数据。

/// 
/// 16进制颜色
/// 
private string _hexColor = "FFFFFFFF";

/// 
/// 归一化颜色值
/// 
private string _normalColor = "1f, 1f, 1f, 1f";

/// 
/// 32位颜色值显示
/// 
private string _color32 = "255, 255, 255, 255";

/// 
/// unity颜色值
/// 
private Color _color = new Color(1, 1, 1, 1);

接下来就是定义OnGUI方法,并且写入我们绘制面板的代码。

string tempHexColor = EditorGUILayout.TextField("HexColor:", _hexColor);

string tempNormalColor = EditorGUILayout.TextField("NormalColor:", _normalColor);

string tempColor32 = EditorGUILayout.TextField("Color32:", _color32);

Color tempColorValue = EditorGUILayout.ColorField(_color);

这里重点说一下 EditorGUILayout.TextField,因为它是比较常用的输入框组件,它显示的是字符串,返回的是用户输入的字符串结果。第一个参数为输入框的 Label(可忽略),第二个参数是输入框显示的字符串内容。

接着是 EditorGUILayout.ColorField,这是我们常用来显示颜色的 Color 组件,Color组件也可以显示 Label,不过这里忽略掉,只使用第一个参数(Color类型)。

EditorGUILayout 下的组件用法大致相同,而且基本都有几种重载方法。使用的时候,可以先看看方法的定义。如果有必要,可能会另外开一节课讲GUI的绘制原理。

上面我们把四个输入框组件绘制出来,并保存下来,为的是之后的转换。

if (tempHexColor != _hexColor)
{
    _hexColor = tempHexColor;
    _color = HexToColor(_hexColor);
    UpdateColor();

    this.Repaint();
}
else if (tempNormalColor != _normalColor)
{
    _normalColor = tempNormalColor;
    _color = NormalToColor(_normalColor);
    UpdateColor();

    this.Repaint();
}
else if (tempColor32 != _color32)
{
    _color32 = tempColor32;
    _color = Color32ToColor(_color32);
    UpdateColor();

    this.Repaint();
}
else if(tempColorValue != _color)
{
    _color = tempColorValue;
    UpdateColor();

    this.Repaint();
}

这里分别对四个属性进行判断,然后分别调用相应的转换函数,把数值转换成Color类,然后再分别格式化显示各种数值,最后调用Repaint()方法刷新界面。

注意:这里要先判断是否修改的做法,第一,是提高效率。第二,Repaint()方法会触发一次OnGUI(),这样可以防止一直刷新OnGUI()

接下来分别添加转换方法。

/// 
/// 16进制转Color类
/// 
/// 
/// 
private Color HexToColor(string value)
{
    Color color;

    value = value.Replace("0x", "");

    value = value.Replace("0X", "");

    if (value.IndexOf("#") != 0)
    {
        value = "#" + value;
    }

    ColorUtility.TryParseHtmlString(value, out color);

    return color;
}

首先是16进制转 Color,16进制颜色通常会使用“0xFFFFFFFF”、“#FFFFFFFF”、“FFFFFFFF”。由于后面用到ColorUtility.TryParseHtmlString方法要使用“#FFFFFFFF”样式,所以,先要把“0x”替换掉,然后加上“#”。

ColorUtility 是 Editor 的颜色工具类,这里的 TryParseHtmlString 方法能把16进制字符串转换成 Color 类。很方便使用。

由于第二个参数是 out,所以要加上 out 关键字,把 color 的引用传入方法。

/// 
/// 归一化转Color
/// 
/// 
/// 
private Color NormalToColor(string value)
{
    Color color = new Color();

    value = value.Replace(" ","");

    value = value.Replace("f", "");

    string[] values = value.Split(',');

    float[] numbers = new float[4];

    for (int i = 0; i < 4; i++)
    {
        if (i < values.Length)
        {
            float.TryParse(values[i], out numbers[i]);

            numbers[i] = Mathf.Clamp(numbers[i], 0.0f, 1.0f);
        }
        else
        {
            numbers[i] = 1.0f;
        }
    }

    color.r = numbers[0];
    color.g = numbers[1];
    color.b = numbers[2];
    color.a = numbers[3];

    return color;
}

归一化颜色值(0f-1f)我们可能并不少见,在着色器 shader 编写上就有用到。这里的显示我们会在数字后面加上“f”,以便我们能直接复制到代码里面使用。

当然,转换的时候要把空格和“f”替换掉,然后进行分割字符,再使用 float.TryParse字符串转变成 float 类型。这里还要使用Mathf.Clamp 方法对数值进行一个限制,限制到 0f-1f 之间。

/// 
/// Color32转Color
/// 
/// 
/// 
private Color Color32ToColor(string value)
{
    Color32 color = new Color32();

    value = value.Replace(" ", "");

    string[] values = value.Split(',');

    byte[] numbers = new byte[4];

    for (int i = 0; i < 4; i++)
    {
        if (i < values.Length)
        {
            byte.TryParse(values[i], out numbers[i]);
        }
        else
        {
            numbers[i] = 255;
        }
    }

    color.r = numbers[0];
    color.g = numbers[1];
    color.b = numbers[2];
    color.a = numbers[3];

    return color;
}

Color32ToColorNormalToColor 方法差不多,只是把 float 变成了 byte

/// 
/// 更新颜色值
/// 把color转成各种颜色表示方式
/// 
private void UpdateColor()
{
    _hexColor = ColorUtility.ToHtmlStringRGBA(_color);

    _normalColor = string.Format("{0}f, {1}f, {2}f, {3}f", _color.r, _color.g, _color.b, _color.a);

    Color32 color32 = _color;

    _color32 = string.Format("{0}, {1}, {2}, {3}", color32.r, color32.g, color32.b, color32.a);
}

最后,我们使用 UpdateColorColor 格式化一遍,变成各种字符串,这就大功告成了。ColorUtility.ToHtmlStringRGBA 方法可以直接把 Color 转成16进制颜色,很方便。

最后,你就可以用它看看效果了。

后记

如果大家有什么意见和建议,或者是有什么疑问,或者是有想看的知识点内容,都欢迎到评论区发上你们的评论。

最后我希望有更多人参与到插件开发的队伍里。也欢迎大家投稿。