Unity3D插件开发教程(三):制作拾色器ColorPicker

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

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

知识要点:

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

使用版本:

  • Unity3D 5.3.3

目标:

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

整个插件的结构:

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

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

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

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

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

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

/// <summary>
/// unity颜色值
/// </summary>
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()

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

/// <summary>
/// 16进制转Color类
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
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的引用传入方法。

/// <summary>
/// 归一化转Color
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
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之间。

/// <summary>
/// Color32转Color
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
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

/// <summary>
/// 更新颜色值
/// 把color转成各种颜色表示方式
/// </summary>
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进制颜色,很方便。

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