Bard は楽して暮らしたい

ゲームを作って思うこと、ゲームを遊んで思うこと

Unity

【Unity】エディタ拡張の際によく使用する、基本的なクラスや関数まとめメモ

投稿日:2018年8月19日 更新日:

みんな大好き、Unityエディタ拡張の基礎。

Unity 2018 以降、エディタ拡張まわりについても UI 変革のロードマップが示されていますが、ここから数年ぐらいはまだまだ既存 UI に則ったエディタ拡張が重宝されるのではないかと思われます。

ここでは、エディタ拡張を始めるにあたって、まずおさえておきたいクラスや関数について、簡単にまとめていきます。

 

試行環境:Unity 2017.4.4f1

新規ウインドウでエディタ拡張を始める際のクラス

新しいツール等を作成する際は、基本的にこれで良いかと。


using UnityEngine;
using UnityEditor;

public class EditorWindowSample : EditorWindow
{
    [MenuItem("Tools/SomeToolWindow")] // MenuItem() の中が, Unity Editor 上部ツールバーから開くための場所になります.
    private static void Open()
    {
        GetWindow<EditorWindowSample>("タブに表示したいタイトル");
    }

    // Awake などは, Open した時に走る.
    private void Awake()
    {
        // ロードすべきファイルなどがあれば, ココで実行すると良い.
    }
}

 

↓こんな感じで選択できるようになっているので…。

エディタウインドウを開く

↓こんな感じにウインドウが開きます。

開いたエディタウインドウ

参考に、EditorWindow クラス公式ドキュメントへのリンクはこちら。
EditorWindow – Unity スクリプトリファレンス

既存クラスのインスペクタ拡張を始める際のクラス

既存クラスのインスペクタで、使い勝手にどうしても不便が出る場合に使用します。



[CustomEditor(typeof(AnyClassName), true)] // AnyClassName は, 拡張対象とするクラス. 第二引数の bool は, 子へ継承するか否か.
public class AnyClassNameInspector : Editor
{
    // 変更を加えたい元クラスの変数に, 対応させたプロパティを持たせる.
    SerializedProperty mHpProperty;
    SerializedProperty mAttackProperty;
    SerializedProperty mDefenceProperty;

    void OnEnable()
    {
        // 元クラスの変数と対応させる.
        mHpProperty= serializedObject.FindProperty("mHp");
        mAttackProperty= serializedObject.FindProperty("mAttack");
        mDefenceProperty= serializedObject.FindProperty("mDefence");
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI(); // 元々のインスペクタ内容も表示させる場合に記述.

        EditorGUILayout.Space();

        EditorGUILayout.LabelField("↓ 『HP』『攻撃力』『守備力』を, こちらで指定してください.");

        EditorGUILayout.IntField(HP, mHpProperty.intValue);
        EditorGUILayout.IntField(攻撃力, mAttackProperty.intValue);
        EditorGUILayout.IntField(守備力, mDefenceProperty.intValue);
    }
}

 

このサンプルクラスの場合、base.OnInspectorGUI() は不要そう。

普通に変数をいじる分には SerializeField を使えば良い話なので、この拡張は主に「インスペクタを編集する人が別にいて、その人に内容をもう少しわかりやすく伝えたい」場合に使用されると思います。

たとえば…

  • enum ポップアップの表示を、編集者にわかりやすいように、別のテキスト群から表示させる(enum では『ITEM_01』となっているところを『薬草』と表示させる)
  • 編集者は『攻撃力』や『守備力』の数値を直接いじらず武器と防具の組み合わせだけを選択し、その結果の『攻撃力』や『守備力』を自動計算して表示する

などの用途が考えられるかと思います。

こちらも参考の、公式ドキュメントリンク。
Editor – Unity スクリプトリファレンス

Project ビューでの右クリックにコマンドを追加する

関数に [MenuItem(“Assets/~”)] を追加すると、上部メニューバーの『Assets』にコマンドが追加されるとともに、「Project ビューでの右クリック」の一覧にも同様にコマンドが追加されます

複数選択による一括処理も可能なので、一定の規則に基づいてファイル名を一括変更したい場合や、特定の拡張子のファイルを Hierarchy に Instantiate する、さらにそれを Prefab 形式に変換して保存する、といった使い方が出来ると便利です。


[MenuItem("Assets/Convert/FbxToPrefab")]
public static void ConvertFbxToPrefab()
{
    // コマンド選択時の実行処理を書く.

    // 右クリック時に選択していたファイルの情報を得たい場合は, こんな感じ.
    foreach (Object obj in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets))
    {
        // 例えば, 拡張子 .fbx のものだけ拾ってきて, Instantiate.
        string file_path = AssetDatabase.GetAssetPath(obj);
        if (file_path.Contains(".fbx") == false)
        {
            continue;
        }
        GameObject game_object = GameObject.Instantiate(obj) as GameObject;
        
        // 頭に pre_ を付けて, Assets/Resources/Prefabs/HogeHoge 以下に Prefab として保存し直す.
        string output_path = "Assets/Resources/Prefabs/HogeHoge/pre_" + obj.name + ".prefab";
        PrefabUtility.CreatePrefab(output_path, game_object);

        // Hierarchy に Instantiate したものは消しておく.
        Editor.DestroyImmediate(game_object);
    }
}

 

Project ビューでの右クリック

内部処理をさらに追加することで、単純な Prefab への変換だけでなく、例えば「このカテゴリのモデルは、一律でこの位置に、特定のエフェクトをぶら下げている」といった流れを入れつつ変換することも可能です。

Hierarchy ビューの右クリックにコマンドを追加する

Project ビューの時と同様に、関数に [MenuItem(“GameObject/~”)] を追加すると、上部メニューバーの『GameObject』にコマンドが追加されるとともに、「Hierarchy ビューでの右クリック」の一覧にも同様にコマンドが追加されます

こちらは便利に使える機会は多くないかも知れませんが、Prefab を何度も Scene 上に呼び出したい時などに有効かも知れません。


[MenuItem("GameObject/Prefab/MapChip")]
public static void InstantiateMapChip()
{
    // ここに処理を書いていく.
}

 

Hierarchy ビューでの右クリック

ボタン生成

原則として、エディタ GUI 内容の編集を行う内容は、private void OnGUI() の中に処理を書く必要があります。



private void OnGUI()
{
    if (GUILayout.Button("ボタンタイトル", GUILayout.Width(128), GUILayout.Height(32))) // ボタンの大きさを Width と Height を指定.
    {
        Debug.Log("ボタンが押されましたよ.");
    }
}

 

WidthHeight 以外にも、オプション指定できる項目はいろいろあります。

GUILayout.Button – Unity スクリプトリファレンス

オプションで特にピクセル指定などを行わないままだと、横いっぱいにボタンが広がります

横いっぱいに広がるボタン

文字に良い感じに合わせたい場合は、GUILayout.ExpandWidth(false) などを指定しましょう。

GUILayout.ExpandWidth – Unity スクリプトリファレンス

良い感じに伸びるボタン

enum ポップアップ



public class EditorWindowSample : EditorWindow
{
    enum ENUM_SAMPLE
    {
        NONE = -1, // 無効値.

        ITEM_01,
        ITEM_02,
        ITEM_03,

        MAX
    }

    ENUM_SAMPLE mEnumSample;

    // 中略.

    private void OnGUI()
    {
        mEnumSample = (ENUM_SAMPLE)EditorGUILayout.EnumPopup("所持アイテムを選んでね", mEnumSample, GUILayout.Width(256));
    }
}

 

基本的な書き方は string や int を編集する際と同じですが、キャストが必要な点が特徴的なので、要注意です。

↓表示はこんな感じ。

enum から選択

EnumPopup の公式ドキュメントはこちら。

EditorGUILayout.EnumPopup – Unity スクリプトリファレンス

 

 

何か思いついたら追加していきます。

 

© Unity Technologies Japan/UCL

-Unity

執筆者:


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

関連記事

UnityChanLicenseLogo

【Unity】Unite Tokyo 2018 見てきた講演の簡単なまとめ 2日目

Unite Tokyo 2018 2日目と3日目へ参加してきました。 2日目に見てきた講演の、簡単な紹介や内容のまとめ、感想などを。 目次なんとっ!ユナイト!ミリシタをささえる『AKANE大作戦』とは …

【Unity】Rigidbody や Collider の設定により変化する、当たり判定の性質 後編

Unity の機能の中でも、基礎中の基礎とも言える Collision。 参考書の通りにやれば、物理演算に基づいたそれらしい挙動は作れるのですが、実際のところ『Rigidbody』や『Collider …

BitSummit Vol.6

【ゲーム雑記】BitSummit Vol.6 を経て、期待のインディーゲーム一覧 後編

少し間が空いてしまいましたが、先月、京都で開催された BitSummit Vol.6 へ行ってきました。 その中で、プレイしたタイトルの感想や、未プレイながら目を引いたタイトルの紹介をしていきたいと思 …

no image

【Unity】講演紹介:いかにして個人制作ゲームで生きていくか 〜スマホゲームレッドオーシャンの泳ぎ方〜 by いたのくまんぼう さん

Unite 2018 の開催も迫ってきているので、改めて昨年 Unite 2017 の講演の中で、おすすめのものでも紹介していこうかなと思います。 Unite 2018 公式サイトはこちら 目次講演動 …

Playmaker

【Unity】講演紹介:2017年の注目アセット100連発 by 常名 隆司 さん(ユニティ・テクノロジーズ・ジャパン合同会社)

今回は、Unite 2017 の講演紹介です。 注目アセットを紹介する講演を紹介する記事です。 目次講演動画スライド内容紹介006: Playmaker015: Behavior Designer09 …