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

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

関連記事

UnityChanLicenseLogo

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

間が空いてしまいましたが、Unite Tokyo 2018 3日目 のまとめです。 前回(2日目のまとめ)はこちら さては非同期だなオメー!async/await完全に理解しよう 【Unite Tok …

BitSummit Vol.6

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

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

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

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

確定申告

【雑記】フリーランスエンジニアの確定申告において、普段から準備しておくべきこと

自分は今現在、フリーランスエンジニアとなって初の確定申告を行おう、というタイミングなのですが、会計ソフトを使用していて、「こういうことを普段から意識しておくと良いな」と感じた点をまとめておきます。 ち …

UnityChanLicenseLogo

【Unity】Timeline 機能 Playable Track 用のスクリプトを書く際の基礎

最近 Unity の Timeline 機能について触れる機会が多く、基礎的な部分について社内 Wiki に情報を書いたりしていたので、コピペ的に再利用してまとめておきます。   試行環境: …