【Unity】実行画面で色を編集できる機能を作る

Unityでオブジェクトの色を変える場合、Inspectorで編集するかスクリプトで変更することになります。
今回はビルドした画面を触る人が色の編集をできないかと思いuGUIで機能を作りました。

# 完成した機能
![Videotogif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96676/d8cd2867-2851-b417-7e71-c228b021a32a.gif)

RGBAごとのSliderコンポーネントの値が変わったとき、またはInputFieldの文字が変わったとき、対象の色も同様に変わります。

# 実装
``` C#
using System;
using UnityEngine;
using UnityEngine.UI;

public class ColorPanel : MonoBehaviour
{
    [Serializable]
    private struct ColorSlider
    {
        public Slider slider;
        public Image fill;
        public InputField value;
    }

    [SerializeField] private Image target = default;

    [SerializeField] private ColorSlider r = default;
    [SerializeField] private ColorSlider g = default;
    [SerializeField] private ColorSlider b = default;
    [SerializeField] private ColorSlider a = default;

    public Color color
    {
        get { return target.color; }
        set
        {
            r.value.text = (value.r * COLOR_MAX_VALUE).ToString();
            g.value.text = (value.g * COLOR_MAX_VALUE).ToString();
            b.value.text = (value.b * COLOR_MAX_VALUE).ToString();
            a.value.text = (value.a * COLOR_MAX_VALUE).ToString();
        }
    }

    private const float COLOR_MIN_VALUE = 0F;
    private const float COLOR_MAX_VALUE = 255F;

    private void Awake()
    {
        // Sliderコンポーネントの値が変わったときの処理
        Action<ColorSlider> OnSliderChanged = (colorSlider) => {
            colorSlider.slider.onValueChanged.AddListener(value => {
                colorSlider.value.SetTextWithoutNotify((value * COLOR_MAX_VALUE).ToString());
                if (target != null)
                {
                    target.color = new Color(r.slider.value, g.slider.value, b.slider.value, a.slider.value);
                    r.fill.color = new Color(r.slider.value, COLOR_MIN_VALUE, COLOR_MIN_VALUE);
                    g.fill.color = new Color(COLOR_MIN_VALUE, g.slider.value, COLOR_MIN_VALUE);
                    b.fill.color = new Color(COLOR_MIN_VALUE, COLOR_MIN_VALUE, b.slider.value);
                }
            });
        };

        // InputFieldコンポーネントの文字が変わったときの処理
        Action<ColorSlider> OnValueChanged = (colorSlider) => {
            colorSlider.value.onValueChanged.AddListener(edit => {
                if (int.TryParse(edit, out var value))
                {
                    value = Mathf.Clamp(value, (int)COLOR_MIN_VALUE, (int)COLOR_MAX_VALUE);
                    colorSlider.slider.value = (float)(value / COLOR_MAX_VALUE);
                }
            });
        };

        // Sliderコンポーネントの値が変わったとき
        OnSliderChanged(r);
        OnSliderChanged(g);
        OnSliderChanged(b);
        OnSliderChanged(a);
        // InputFieldコンポーネントの文字が変わったとき
        OnValueChanged(r);
        OnValueChanged(g);
        OnValueChanged(b);
        OnValueChanged(a);
        // 開始時の色情報をuGUIに設定
        if (target != null)
        {
            this.color = target.color;
        }
    }
}
```
**InputField.onValueChanged**関数が**Slider.onValueChanged**関数を呼び、Sliderコンポーネントの値が変わったときに色情報を更新します。
InputFieldには文字列が送られてくるので整数値に変換し0~255に丸めていますが、コンポーネントの設定も[ContentType](https://docs.unity3d.com/ja/2019.2/ScriptReference/UI.InputField.ContentType.html)は**DecimalNumber**にしておきましょう。
`ColorSlider.fill`には`Slider.fillRect`のImageコンポーネントが設定されており個別の値を視覚的に確認できるようにしたかっただけなので、おおもとの機能としては外してしまっても問題ありません。