LoginSignup
6
4

More than 5 years have passed since last update.

ScriptableObjectとEditor拡張で作るButton一括設定くん

Posted at

はじめに

自分のScriptableObject活用法について定期的に書いています。
今回はScriptableObjectをEditor拡張に活用する方法について書きます。

過去記事
1 ScriptTemplateでScripableObjectのための環境構築
2 ScriptableObjectを設定ファイルとして扱う
3 ScriptableObjectをマスターデータとして扱う

4. ScriptableObjectとEditor拡張

4.1 uGUIのButton設定が面倒かもしれない問題

uGUIで新規にButtonを作成すると以下のようなButtonコンポーネントが作成されます。

スクリーンショット 2017-12-21 2.23.32.png

初期設定は以下となります。

name value
Transition Color Tint
Target Graphic (自身のオブジェクト)
Normal Color #FFFFFFFF
Highlighted Color #F5F5F5FF
Pressed Color #C8C8C8FF
Disabled Color #C8C8C880
Color Multipler 1.0
Fade Duration 0.1

上の設定はいかにもデフォルトという感じなので、
ゲームの雰囲気に合わせて変更すると思います。
しかし再度Buttonを新規作成すると、また初期設定でButtonが作成されます。

Buttonの数がどんどん増えるときちんと設定をしたコンポーネントかわからなくなる問題があります。
自分はScriptableObject+Editor拡張で、
UIの設定漏れを防いでいるのでその方法を書きます。

4.2 UI(Button)の設定を持つScriptableObject

UnityEngine.UI.ButtonのAPIリファレンスを見ると、
ボタンの上記設定は
Selectable.TransitionとColorBlockというプロパティであることがわかります。
https://docs.unity3d.com/ScriptReference/UI.Button.html

変更が必要な分を抜き出してScriptableObjectにします。

ButtonThemeConfig.cs
using UnityEngine;
using UnityEngine.UI;

[CreateAssetMenu(menuName = "Sample4/UI/ButtonThemeConfig")]
public class ButtonThemeConfig : ScriptableObject
{
    public enum Theme
    {
        Default,
        Green
    };

    public Selectable.Transition transition;

    [Header("ColorBlock")]
    public ColorBlock colorBlock;

    public static ButtonThemeConfig Load(Theme theme)
    {
        if (theme == Theme.Green) {
            return Resources.Load<ButtonThemeConfig>("ButtonThemeConfig/Green");
        }
        return Resources.Load<ButtonThemeConfig>("ButtonThemeConfig/Default");
    }
}

Default(青色)とGreen(緑色)の2つ用意しました。

スクリーンショット 2017-12-21 2.32.11.png

4.3 特定のコンポーネントを一括設定するスクリプト

以下の処理を行うEditorWindowを作成します。

  1. シーン内の特定コンポーネント(今回はButton)を全て取得する
  2. 1で取得したコンポーネントをリスト化する
  3. ボタンが押されたときにScriptableObjectの値をComponentに反映

# 作成時点ではUnity5.3を利用していたのでScrollViewを使用していますが
# Unity5.6以降はTreeViewという機能でもっとしっかりしたリストが作成できるらしいです..

Editor/ButtonConfigWindow.cs
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;

public class ButtonConfigWindow : EditorWindow
{
    //ただの幅
    static class ColumnWidth
    {
        public const int Name = 150;
        public const int Target = 150;
        public const int Interactable = 100;
        public const int Transition = 100;
        public const int Color = 25;
        public const int ColorPadding = 4; //目分量
        public const int Theme = 75;
    }

    Vector2 panel;

    [MenuItem("Window/Sample4/ButtonConfigWindow")]
    static void Open()
    {
        EditorWindow.GetWindow<ButtonConfigWindow>();
    }

    void OnGUI()
    {
        panel = EditorGUILayout.BeginScrollView(panel, GUI.skin.box);
        {
            //シーン内のButtonを全て取得
            Button[] buttons = Resources.FindObjectsOfTypeAll(typeof(Button)) as Button[];
            if (buttons == null || buttons.Length == 0) {
                return;
            }

            EditorGUILayout.BeginHorizontal(GUI.skin.box);
            GUILayout.Label("Name", GUILayout.Width(ColumnWidth.Name));
            GUILayout.Label("Target Graphic", GUILayout.Width(ColumnWidth.Target));
            GUILayout.Label("Interactable", GUILayout.Width(ColumnWidth.Interactable));
            GUILayout.Label("Transition", GUILayout.Width(ColumnWidth.Transition));
            GUILayout.Label("Colors", GUILayout.Width((ColumnWidth.Color + ColumnWidth.ColorPadding) * 4));
            GUILayout.Label("Theme", GUILayout.Width(ColumnWidth.Theme * 2));
            EditorGUILayout.EndHorizontal();

            foreach (Button button in buttons) {
                EditorGUILayout.BeginHorizontal(GUI.skin.box);

                GUILayout.Label(button.name, GUILayout.Width(ColumnWidth.Name));
                GUILayout.Label(button.targetGraphic.name, GUILayout.Width(ColumnWidth.Target));

                //Transition
                button.interactable = EditorGUILayout.Toggle(button.interactable, GUILayout.Width(ColumnWidth.Transition));
                button.transition = (Selectable.Transition) EditorGUILayout.EnumPopup(button.transition,  GUILayout.Width(ColumnWidth.Transition));

                //ColorBlock
                ColorBlock colorBlock = button.colors;
                colorBlock.normalColor = EditorGUILayout.ColorField(GUIContent.none, button.colors.normalColor, false, true, false, null, GUILayout.Width(ColumnWidth.Color));
                colorBlock.highlightedColor = EditorGUILayout.ColorField(GUIContent.none, button.colors.highlightedColor, false, true, false, null, GUILayout.Width(ColumnWidth.Color));
                colorBlock.pressedColor = EditorGUILayout.ColorField(GUIContent.none, button.colors.pressedColor, false, true, false, null, GUILayout.Width(ColumnWidth.Color));
                colorBlock.disabledColor = EditorGUILayout.ColorField(GUIContent.none, button.colors.disabledColor, false, true, false, null, GUILayout.Width(ColumnWidth.Color));

                //Theme選択
                if (GUILayout.Button("Default", GUILayout.Width(ColumnWidth.Theme))) {
                    ButtonThemeConfig config = ButtonThemeConfig.Load(ButtonThemeConfig.Theme.Default);
                    button.transition = config.transition;
                    colorBlock = config.colorBlock;
                    EditorUtility.SetDirty(button);
                }
                if (GUILayout.Button("Green", GUILayout.Width(ColumnWidth.Theme))) {
                    ButtonThemeConfig config = ButtonThemeConfig.Load(ButtonThemeConfig.Theme.Green);
                    button.transition = config.transition;
                    colorBlock = config.colorBlock;
                    EditorUtility.SetDirty(button);
                }
                button.colors = colorBlock;
                EditorGUILayout.EndHorizontal();
            }
        }
        EditorGUILayout.EndScrollView();
    }
}


4.4 使用方法

4.3のMenuItemで指定した項目を呼び出すと、シーン内のButtonコンポーネント一覧を表示します。
Window > Sample4 > ButtonConfigWindow

赤枠内(一番上のボタン)のボタンが設定漏れでデフォルト設定になっていることがわかります。

スクリーンショット 2017-12-21 2.46.41.png

Themeのボタンを押すと設定が反映されます。

スクリーンショット 2017-12-21 2.46.56.png

まとめ

ScriptableObjectの活用法をとりあえず4つ書きました。

個人的にScriptableObjectは
MonoBehaviourと同じくらいUnityの要素としては大事だと思います。
(利用範囲が多いのはもちろん、UnityのObjectについて理解が深まったり、データの効率化について考えたり云々)

興味があったら以下も合わせて読んで下さい。

1 ScriptTemplateでScripableObjectのための環境構築
2 ScriptableObjectを設定ファイルとして扱う
3 ScriptableObjectをマスターデータとして扱う
4 ScriptableObjectとEditor拡張

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4