【Unity】【エディタ拡張】エディタ拡張チートシート

自分用メモ。随時更新。

Array / List型の入力フィールドを描画する(インスペクタ拡張の場合)

f:id:halya_11:20180708133714p:plain

インスペクタ拡張の場合はEditorGUILayout.PropertyField()の第二引数をtrueにするだけで、
あとは他のプロパティ描画方法と同様。

using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class SomeBehaviour : MonoBehaviour {

    [SerializeField]
    private List<int> _someList;
}

#if UNITY_EDITOR
[CustomEditor(typeof(SomeBehaviour))]
public class SomeBehaviourEditor : Editor{

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        // 第二引数をtrueにする
        EditorGUILayout.PropertyField(serializedObject.FindProperty("_someList"), true);

        serializedObject.ApplyModifiedProperties();
    }
}
#endif

Array / List型の入力フィールドを描画する(EditorWindowの場合)

f:id:halya_11:20180708133855p:plain

EditorWindowはScriptableObjectの派生クラスなのでSerializeFieldな変数を定義できる。
あとは自身のScriptableObjectを取得してEditorGUILayout.PropertyField()で描画するだけ。
第二引数はtrue。

using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

public class SomeWindow : EditorWindow {
    
    // SerializeFieldを定義
    [SerializeField]
    private List<int> _someList;

    [MenuItem("Window/Some Window")]
    private static void Open()
    {
        var window = GetWindow<SomeWindow>("Some Window");
    }
    
    private void OnGUI()
    {
        // 自身のSerializedObjectを取得
        var so = new SerializedObject(this);

        so.Update();
        
        // 第二引数をtrueにしたPropertyFieldで描画
        EditorGUILayout.PropertyField(so.FindProperty("_someList"), true);

        so.ApplyModifiedProperties();
    }
}

ウィンドウの中央にラベルを表示する

f:id:halya_11:20180708134140p:plain

using (new EditorGUILayout.VerticalScope()) {
    GUILayout.FlexibleSpace();
    using (new EditorGUILayout.HorizontalScope()) {
        GUILayout.FlexibleSpace();
        var style = new GUIStyle(GUI.skin.label);
        style.wordWrap = true;
        EditorGUILayout.LabelField(text, style);
        GUILayout.FlexibleSpace();
    }
    GUILayout.FlexibleSpace();
}

ファイル保存パネルを表示する

f:id:halya_11:20180712222155p:plain

public static void SaveSample()
{
    
    // 推奨する保存パスがあればpathに入れておく
    var path = "";
    string ext = "png";
        
    if (string.IsNullOrEmpty(path) || System.IO.Path.GetExtension(path) != "." + ext)
    {
        // 推奨する保存パスがないときはシーンのディレクトリをとってきたりする(用途次第)
        if (string.IsNullOrEmpty(path)) {
            path = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().path;
            if (!string.IsNullOrEmpty(path)) {
                path = System.IO.Path.GetDirectoryName(path);
            }
        }
        if (string.IsNullOrEmpty(path)) {
            path = "Assets";
        }
    }

    // ディレクトリがなければ作る
    else if (System.IO.Directory.Exists(path) == false) {
        System.IO.Directory.CreateDirectory(path);
    }

    // ファイル保存パネルを表示
    var fileName = "name." + ext;
    fileName = System.IO.Path.GetFileNameWithoutExtension(AssetDatabase.GenerateUniqueAssetPath(System.IO.Path.Combine(path, fileName)));
    path = EditorUtility.SaveFilePanelInProject("Save Some Asset", fileName, ext, "", path);

    if (!string.IsNullOrEmpty(path)) {
        // 保存処理
        Debug.Log(path);
    }
}

Inspectorのプロパティがクリックされたことを検知する

using UnityEngine;
using UnityEditor;

public class Sample : MonoBehaviour {
}

[CustomEditor(typeof(Sample))]
public class SampleEditor: Editor{

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        DrawClickMenu();
    }

    public void DrawClickMenu(){
        var rect = GUILayoutUtility.GetLastRect();
        if (rect.Contains(Event.current.mousePosition) && Event.current.type == EventType.MouseUp && Event.current.button == 0)
        {
            // 左クリック時の処理
        }
        if (rect.Contains(Event.current.mousePosition) && Event.current.type == EventType.MouseUp && Event.current.button == 1)
        {
            // 右クリック時の処理
        }
    }
}

GenericMenuを表示する

f:id:halya_11:20180713194015p:plain

GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent ("メニュー名1"), enabled, () => { Debug.Log("処理1"); });
menu.AddItem(new GUIContent ("メニュー名2"), enabled, () => { Debug.Log("処理2"); });
menu.AddItem(new GUIContent ("メニュー名3"), enabled, () => { Debug.Log("処理3"); });
menu.ShowAsContext();

Sceneビューがクリックされたことを検知する

MonoBehaviourのOnDrawGizmosでやる場合。

public class Sample : MonoBehaviour {

    private void OnDrawGizmos()
    {
        if (Event.current.type == EventType.MouseUp && Event.current.button == 0)
        {
            Debug.Log("clicked");
        }       
    }
}

Sceneビュー上でクリックされた位置を取る

private void OnDrawGizmos()
{
    if(Event.current != null && Event.current.type == EventType.mouseUp && Event.current.button == 0){
        // スクリーン座標が得られる
        var clickedPosition = Event.current.mousePosition;

        // 上下逆になるので補正
        clickedPosition.y = SceneView.currentDrawingSceneView.camera.pixelHeight - clickedPosition.y;

        // ちなみにこの後座標変換にカメラを使いたい場合
        // UnityEditor.SceneView.currentDrawingSceneView.cameraを使う
    }
}

関連

light11.hatenadiary.com

light11.hatenadiary.com