Tsuの雑記¯\_(ツ)_/¯

主に製作メモ・備忘録として使用。製作したアプリのリンクもあります。

【Unity】GUIStyle の文字列指定を1度だけ行う方法【C#】

文字列指定によるGUIStyleの代入を、OnGUI()内で1度だけ行う方法について。

(Unity 2019.4.17f1)


GUIStyle の文字列指定

Unity エディター拡張等で使用されるGUIStyleですが、特定の文字列を指定する事で幅広い表現が可能となります。

docs.unity3d.com

以下に、実例を挙げます。

// EditorWindow を使用するため
using UnityEditor;
using UnityEngine;

public class NewBehaviourScript : EditorWindow
{
    /// <summary>
    /// ウィンドウ作成
    /// </summary>
    [MenuItem("Window/Test")]
    static void Init()
    {
        // ウィンドウ作成
        var newBehaviourScript = GetWindow<NewBehaviourScript>("Test");
    }

    void OnGUI()
    {
        // Label を描画
        GUILayout.Label("a", new GUIStyle("BoldToggle"));
        // Label を描画
        GUILayout.Label("b", new GUIStyle("BoldToggle"));
    }
}

Labelの描画時に用いた"BoldToggle"が、GUIStyleを指定する文字列です。

これにより、「見た目は太字トグルボタンのLabel」を描画する事が出来ます。

見た目は太字トグルボタンの Label が縦に2つ並んでいる画像
見た目は太字トグルボタンの Label

上記のコードでは同じGUIStyleを2度も記述しているので、これをフィールドにて変数に代入してみます。

// EditorWindow を使用するため
using UnityEditor;
using UnityEngine;

public class NewBehaviourScript : EditorWindow
{
    /// <summary>
    /// ウィンドウ作成
    /// </summary>
    [MenuItem("Window/Test")]
    static void Init()
    {
        // ウィンドウ作成
        var newBehaviourScript = GetWindow<NewBehaviourScript>("Test");
    }

    // "BoldToggle" の GUIStyle
    GUIStyle boldToggleStyle = new GUIStyle("BoldToggle");

    void OnGUI()
    {
        // Label を描画
        GUILayout.Label("a", boldToggleStyle);
        // Label を描画
        GUILayout.Label("b", boldToggleStyle);
    }
}

これを実行するとLabelは表示されず、コンソールには2種類のエラーが表示されます。

Unable to use a named GUIStyle without a current skin. Most likely you need to move your GUIStyle initialization code to OnGUI
UnityException: set_rawName is not allowed to be called from a ScriptableObject constructor (or instance field initializer), call it in OnEnable instead. Called from ScriptableObject 'NewBehaviourScript'. See "Script Serialization" page in the Unity Manual for further details.

「文字列指定のGUIStyleは、OnGUI()メソッド内でのみ呼び出せる」という事ですね。

しかし変更する予定のないGUIStyleOnGUI()実行のたびに生成するのが、気になりませんか?

そこで、本題でもある「文字列指定のGUIStyleOnGUI()メソッド内で1度だけ実行する方法」について御紹介いたします。


使い捨て処理を利用する

過去記事にて取り上げた、ThrowawayMethodクラスを使います。

tsu-games.hatenablog.com

このクラスのRunOnce()メソッドを用いる事で、GUIStyleの文字列指定を使い捨てに出来ます。

throwaway-method · GitHub

// EditorWindow を使用するため
using UnityEditor;
using UnityEngine;
// ThrowawayMethod を使用するため
using TsuGames;

public class NewBehaviourScript : EditorWindow
{
    /// <summary>
    /// ウィンドウ作成
    /// </summary>
    [MenuItem("Window/Test")]
    static void Init()
    {
        // ウィンドウ作成
        var newBehaviourScript = GetWindow<NewBehaviourScript>("Test");
    }

    // 使い捨て処理を生成
    readonly ThrowawayMethod throwawayMethod = new ThrowawayMethod();
    // "BoldToggle" の GUIStyle
    GUIStyle boldToggleStyle;

    void OnGUI()
    {
        // SetGUIStyles() を1度だけ実行
        throwawayMethod.RunOnce(SetGUIStyles);
        // Label を描画
        GUILayout.Label("a", boldToggleStyle);
        // Label を描画
        GUILayout.Label("b", boldToggleStyle);
    }

    /// <summary>
    /// GUIStyle を代入
    /// </summary>
    void SetGUIStyles()
    {
        // "BoldToggle" の GUIStyleを代入
        boldToggleStyle = new GUIStyle("BoldToggle");
    }
}

文字列指定のGUIStyleを代入するSetGUIStyles()というメソッドを作り、RunOnce()メソッドで1度だけ実行させます。

RunOnce()の引数にはメソッド名だけでなくラムダ式も指定できるため、以下のように簡潔に記述する事も出来ます。

// EditorWindow を使用するため
using UnityEditor;
using UnityEngine;
// ThrowawayMethod を使用するため
using TsuGames;

public class NewBehaviourScript : EditorWindow
{
    /// <summary>
    /// ウィンドウ作成
    /// </summary>
    [MenuItem("Window/Test")]
    static void Init()
    {
        // ウィンドウ作成
        var newBehaviourScript = GetWindow<NewBehaviourScript>("Test");
    }

    // 使い捨て処理を生成
    readonly ThrowawayMethod throwawayMethod = new ThrowawayMethod();
    // "BoldToggle" の GUIStyle
    GUIStyle boldToggleStyle;

    void OnGUI()
    {
        // boldToggleStyle への代入を1度だけ実行
        throwawayMethod.RunOnce(() => boldToggleStyle = new GUIStyle("BoldToggle"));
        // Label を描画
        GUILayout.Label("a", new GUIStyle("BoldToggle"));
        // Label を描画
        GUILayout.Label("b", new GUIStyle("BoldToggle"));
    }
}

以上、GUIStyleの文字列指定を1度だけ行う方法についての記事でした。