SlideShare a Scribd company logo
1 of 23
Download to read offline
Extending the Unity Editor
                  Unity Editor の 拡張について Ex
Extending the Unity Editor EXTENDED!
 そもそも何が拡張できるのか
 ・インスペクタの拡張
    各コンポーネント(Transformなどのデフォルトコンポーネン
    トも含む)がインスペクタにどう表示されるかを変更できる。
 ・独自ウィンドウの作成
    ScriptableWizardで手軽に作ることも、EditorWindowを継
    承してがっつり作ることも。ドックにはフラグ1つで対応可!
 ・アセットインポーターの拡張
    アセットインポートの前処理・後処理を独自実装可能。
 ・各種ビューの拡張
    シーンビューやゲームビュー、プレビュー表示などなど。
 ・各種メニューの拡張
    アプリケーションメニューやコンテキストメニューなど。
                                          2/23
Extending the Unity Editor EXTENDED!
 インスペクタの拡張
 ・どんなことができるのか
    表示する内容や表示する際に使用するコンポーネントを変更し
    たり、ユーティリティ的なボタンを追加したり。

    ゲーム中でも使うGUI(Layout)
    クラスやEditorGUI(Layout)ク
    ラスに様々なパーツが用意されて
    いるので、それらを並べるだけで
    も簡単に拡張できる。




                                       3/23
Extending the Unity Editor EXTENDED!
 インスペクタの拡張
 ・どうやればできるのか(1/3)
    コンポーネント単位での拡張で、インスペクタの内容を変更し
    たいコンポーネント毎に、対応するEditorクラスを実装する。
    using UnityEngine; // 必須
    using UnityEditor; // 必須

    [CustomEditor(typeof(Hoge))] // Hogeクラス用の拡張であることを宣言
    public sealed class HogeEditor : Editor
    {
         // このメソッドをオーバーライドして処理を書いていく
         public override void OnInspectorGUI()
         {
         }
    }


    [CustomEditor(typeof(Transform))] // 既存のクラスを拡張することも可能
    public sealed class CustomTransformEditor : Editor
    {
         public override void OnInspectorGUI()
         {




                                                            4/23
Extending the Unity Editor EXTENDED!
 インスペクタの拡張
 ・どうやればできるのか(2/3)
    とりあえずOnInspectorGUI()内でDrawDefaultInspector()
    を呼んでおけばデフォルトの表示をやってくれる。
       public override void OnInspectorGUI()
       {
            DrawDefaultInspector(); // とりあえずデフォルトの表示
       }


    またserializedObjectプロパティを利用すればデフォルトで表
    示すべき要素にひと通りアクセスできる。
       public override void OnInspectorGUI()
       {
            // この書き方だと実行に支障はないのに何故かエラーが出るんだけど…
            foreach (SerializedProperty p in serializedObject.GetIterator())
            {
                 EditorGUILayout.PropertyField(p);
            }
       }




                                                                               5/23
Extending the Unity Editor EXTENDED!
 インスペクタの拡張
 ・どうやればできるのか(3/3)
    要素の表示は基本的にGUILayoutクラスとEditorGUILayout
    クラスを利用する。
       static Vector3 copyBuffer = Vector3.zero;
       public override void OnInspectorGUI()
       {
            Hoge hoge = target as Hoge;
            Vector3 v = EditorGUILayout.Vector3Field("Velocity", hoge.velocity);
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Reset", EditorStyles.miniButton))
                 v = Vector3.zero;
            GUILayout.Space(GUILayoutUtility.GetAspectRect(1).width / 3);
            if (GUILayout.Button("Copy", EditorStyles.miniButtonLeft))
                 copyBuffer = v;
            if (GUILayout.Button("Paste", EditorStyles.miniButtonRight))
                 v = copyBuffer;
            EditorGUILayout.EndHorizontal();
            if (v != hoge.velocity)
            {
                 Undo.RegisterUndo(hoge, "Velocity Change");
                 hoge.velocity = v;
                 EditorUtility.SetDirty(target);
            }
       }


                                                                                   6/23
Extending the Unity Editor EXTENDED!
 独自ウィンドウの作成
 ・どんなことができるのか
    アプリケーションの「Window」メニューから開けるような
    ウィンドウを独自に作成することができる。




                             ※画像はAPARTURE Cutscene Editorの例

    エディタにドックさせて常に表示しておくような物や、ダイア
    ログのように一時的に表示するような物など、用途に応じて。
    呼び出し方は後述するメニューの拡張でアプリケーションのメ
    ニューに独自ウィンドウを開く項目を追加したり、拡張したイ
    ンスペクタに独自ウィンドウを開くためのボタンを追加した
    り、色々考えられる。
                                                              7/23
Extending the Unity Editor EXTENDED!
 独自ウィンドウの作成
 ・どうやればできるのか(1/4)
    ごく簡単なものならScriptableWizardを継承したクラスを実
    装すれば、そのパブリックメンバ変数を適当に並べたウィンド
    ウをUnityが自動的に作ってくれる。
    using UnityEngine; // 必須
    using UnityEditor; // 必須

    public sealed class MaterialReplacer : ScriptableWizard // ScriptableWizardクラスを継承する
    {
         public Material replaceTo; // インスペクタのようにpublicメンバが自動的に列挙される

        [MenuItem("Tools/Replace Material...")] // このウィザードを開くメニュー項目を追加
        static void OpenWindow()
        {
             ScriptableWizard.DisplayWizard<MaterialReplacer>("Replace Material", "Apply");
        }

        void OnWizardCreate()
        {
        // ボタンが押された時の処理をここに書いていく
        }
    }


                                                                                              8/23
Extending the Unity Editor EXTENDED!
 独自ウィンドウの作成
 ・どうやればできるのか(2/4)
    先ほどのクラスのOnWizardCreate()を実装する。
    using System.Linq; // Linqを使うので
    ...
         void OnWizardCreate() // ボタン1つの場合のデフォルト表示が「Create」なのでこんなメソッド名らしい
         {
              if (replaceTo == null) // マテリアルが選択されていなかったら何もしない
                   return;
              var renderers = from r in Selection.gameObjects
                                  where r.renderer != null
                                  select r.renderer;
              foreach (Renderer r in renderers)
                   r.sharedMaterial = replaceTo;
         }



    Applyボタンを押すと
    選択中のオブジェクト
    のマテリアルが指定し
    たものに置き換わり、
    ウィンドウが閉じる。
                                                                        9/23
Extending the Unity Editor EXTENDED!
 独自ウィンドウの作成
 ・どうやればできるのか(3/4)
    ドックして常駐させたり、もっと凝った処理を行いたい場合は
    EditorWindowを継承したクラスを実装する。
    using UnityEngine; // 必須
    using UnityEditor; // 必須

    public sealed class MaterialReplacer : EditorWindow // EditorWindowクラスを継承する
    {
         [MenuItem("Tool/Replace Material...")] // このウィンドウを開くメニュー項目を追加
         static void OpenWindow()
         {
              EditorWindow.GetWindow<MaterialReplacer>(true, "Replace Material");
         }

        void OnGUI()
        {
        // カスタムウィンドウはOnGUI()の中に表示含め処理を書いていく(インスペクタの拡張と似ている)
        }
    }




                                                                                    10/23
Extending the Unity Editor EXTENDED!
 独自ウィンドウの作成
 ・どうやればできるのか(4/4)
    先ほどのクラスのOnGUI()を実装する。
    using System.Linq; // Linqを使うので
    ...
         static Material targetMaterial = null;
         void OnGUI() // ScriptableWizar版とまったく同じ処理を書いてみる
         {
              targetMaterial = EditorGUILayout.ObjectField(
                   "Replace To", targetMaterial, typeof(Material), false
              ) as Material;
              // マテリアルや対象のオブジェクトが選択されていなかったら決定できないようにしてみる
              GUI.enabled = (targetMaterial != null) && (Selection.gameObjects.Length > 0);
              if (GUILayout.Button("Apply"))
              {
                   var renderers = from r in Selection.gameObjects
                                       where r.renderer != null
                                       select r.renderer;
                   foreach (Renderer r in renderers)
                        r.sharedMaterial = targetMaterial;
                   Close();
              }
              GUI.enabled = true;
         }




                                                                                              11/23
Extending the Unity Editor EXTENDED!
 アセットインポーターの拡張
 ・どんなことができるのか
    モデルやテクスチャをインポートする時に独自の処理を加える
    ことができる。
    またモデルインポートの際にUnityが自動で作ってくれる(作っ
    てしまう)マテリアルを独自のものに差し替えたり、そもそも
    マテリアルの生成を抑止したりもできる。

    ただし個別に処理できるのがモデル・テクスチャ・サウンドだ
    けで、他は全てのインポートが終わった後にしかアクセスでき
    ないなど少し柔軟性に欠ける。
    しかもそのOnPostprocessAllAssetsメソッドはstaticメ
    ソッドにしておかないと機能しないというトラップ付き!


                                        12/23
Extending the Unity Editor EXTENDED!
 アセットインポーターの拡張
 ・どうやればできるのか
    AssetPostprocessorを継承したクラスを定義し、
    OnPostprocessModel()などのメソッドをオーバーライドし
    ていく。自作のポストプロセッサーが複数ある場合、処理順を
    指定することもできる。
    using UnityEngine; // 必須
    using UnityEditor; // 必須

    public sealed class CustomModelImporter : AssetPostprocessor
    {
         public override int GetPostprocessOrder()
         {
              return 0; // 全てのポストプロセッサーを通して、ここで返す値が小さい順に処理される
         }

        void OnPreprocessModel()
        {
             // アニメーションセットをインポートするときはマテリアルを生成しない、みたいな
             if (assetPath.Contains("@"))
                  (assetImporter as ModelImporter).importMaterials = false;
        }
    }

                                                                              13/23
Extending the Unity Editor EXTENDED!
 各種ビューの拡張
 ・どんなことができるのか
    Gizmosを使ってビューにラインやアイコンを描いたり、
    Handlesを使ってハンドル(マニピュレータ)を表示したり。
    上記は基本的にシーンビューへの描画だが、ゲームビューへの
    描画もできる(後述)。

    ハンドルは掴んで動かしてその結
    果を受け取る、というところまで
    面倒を見てくれるので便利。

    またEditor.OnPreviewGUI()を
    オーバーライドすればインスペク
    タ下段に表示されているプレビュ
    表示に手を加えることもできる。
                                       14/23
Extending the Unity Editor EXTENDED!
 各種ビューの拡張
 ・どうやればできるのか(1/3)
    シーンビューに対する描画は、Editorクラスを継承してインス
    ペクタを拡張すると、そのインスタンスにOnSceneGUIとい
    うメッセージが飛んでくるのでそれを捕まえるか、
    SceneViewというUndocumentedなクラスがあり、それの
    onSceneGUIDelegateというプロパティに適当なメソッドを
    投げると、先ほどのOnSceneGUI相当の処理ができる。但し
    後者は非公式。
       void OnSceneGUI()
       {
            Vector3 pos = (target as Hoge).transform.position;
            float size = HandleUtility.GetHandleSize(pos); // カメラ距離によらないサイズの計算
            Handles.DrawSolidDisc(pos, Vector3.up, size);
       }
       static HogeEditor() // デリゲートの登録は1度でいいのでstaticコンストラクタから登録してみる
       {
            SceneView.onSceneGUIDelegate += view => {
                 Handles.DrawLine(Vector3.zero, Vector3.up);
            };
       }
                                                                                 15/23
Extending the Unity Editor EXTENDED!
 各種ビューの拡張
 ・どうやればできるのか(2/3)
    ゲームビューに対する描画は少し特殊で、hideFlagsを
    HideFlags.HideAndDontSaveにしたゲームオブジェクトに
    ExecuteInEditMode属性を付けたコンポーネントを貼り付け
    るのが手っ取り早い。
    // こんなコンポーネントを作っておいて
    [ExecuteInEditMode()]
    public sealed class GameViewUpdater : MonoBehaviour
    {
         void OnGUI()
         {
              // 適当な処理
         }
    }
    ...
         // 例えばインスペクタのOnEnableで隠しゲームオブジェクトを生成し、先ほどのコンポーネントを貼り付ける
         void OnEnable()
         {
              GameObject go = new GameObject();
              go.hideFlags = HideFlags.HideAndDontSave;
              go.AddComponent<GameViewUpdater>();
         }

                                                              16/23
Extending the Unity Editor EXTENDED!
 各種ビューの拡張
 ・どうやればできるのか(3/3)
    プレビュー表示への描画は拡張インスペクタで
    HasPreviewGUIがtrueを返すようにオーバーライドし、
    OnPreviewGUIの中に処理を書いていく。
    ただし何故かレイアウトが下詰め。謎。
       public override bool HasPreviewGUI ()
       {
            return true;
       }

       public override void OnPreviewGUI(Rect r, GUIStyle bg)
       {
            GUILayout.Label("Label");
            GUILayout.Button("Button");
       }




                                                                17/23
Extending the Unity Editor EXTENDED!
 各種メニューの拡張
 ・どんなことができるのか
    既に存在するアプリケーションメニュー(例えば「Window」
    とか)に要素を追加することもできるし、新しいメニュー項目
    を増やすこともできる。




    また既存のコンテキストメニュー(インスペクタ上で右クリッ
    クするか、インスペクタの右上にあるちっちゃい歯車のアイコ
    ンを押すと出る)に要素を追加したり、独自のコンテキストメ
    ニューを作ったりすることもできる。

    日本語は正しく処理できないっぽいです…遊んでたら落ちました
                                       18/23
Extending the Unity Editor EXTENDED!
 各種メニューの拡張
 ・どうやればできるのか(1/3)
    アプリケーションメニューへの追加は、MenuItem属性を使用
    する。「<項目名>/<要素名>」のようなパス形式でどこにな
    んというメニューを追加するか指定できる。呼び出すメソッド
    はどこで宣言したものでも構わない代わりに、staticでなけれ
    ばならない。
       [MenuItem("Tools/MyMenu")] // MenuItem属性の引数でどこに追加するか指定する
       static void MyMenuItem()   // メニューが選択されるとこのメソッドが呼ばれる
       {
       }




                                                                  19/23
Extending the Unity Editor EXTENDED!
 各種メニューの拡張
 ・どうやればできるのか(2/3)
    コンテキストメニューへの追加は、MenuItem属性を使う方法
    と、コンポーネントクラスに直接ContextMenu属性を付ける
    方法がある。
    MenuItem属性を使う場合はやはりメソッドはstaticでなけれ
    ばならないが、ContextMenu属性を使う場合はその限りでは
    ない。
        [MenuItem("CONTEXT/Hoge/MyMenu")] // Hogeコンポーネントのコンテキストメニューに追加する場合
        static void MyMenu()
        {
        }
    ...
    public class Hoge : MonoBehaviour   // 上記と全く同じメニューをコンポーネントから追加する場合
    {
         [ContexMenu("MyMenu")]
         void MyMenu()
         {
         }
    }



                                                                        20/23
Extending the Unity Editor EXTENDED!
 各種メニューの拡張
 ・どうやればできるのか(3/3)
    マウスイベントをトラップして独自のコンテキストメニューを
    表示することもできる。インスペクタでも、ウィンドウでも。
       // メニューの項目が選択された時の処理をあらかじめ定義しておく(別にラムダ式でもいいけど)
       void Callback(Object obj)
       {
            (obj as Hoge).transform.position = Vector3.zero
       }
       // 例えばインスペクタのプレビュー表示上で右クリックされた場合に独自のコンテキストメニューを出す
       public override void OnPreviewGUI(Rect r, GUIStyle background)
       {
            // 飛んできたイベントをチェックして、範囲内での右クリックだったら処理する
            var evt = Event.current;
            if (evt.type == EventType.ContextClick && r.Contains(evt.mousePosition))
            {
                 var menu = new GenericMenu();
                 menu.AddItem(new GUIContent("Reset Position"), false, Callback, target);
                 menu.ShowAsContext();
                 evt.Use(); // 自前で処理したイベントは握りつぶしておく
            }
            DrawDefaultInspector();
       }




                                                                                            21/23
Extending the Unity Editor EXTENDED!
 ワークフローへの組み込み
 ・アーティスト→プログラマー
    アセット読み込み時の各種設定を自動化
    アニメーションやコリジョンなどの編集支援
 ・プログラマー→ゲームデザイナー
    ゲームデータ入力支援
    外部データの読み込み
 ・プログラマー→プログラマー
    デバッグ支援
    ビルド自動化
    アセットバンドル




                                       22/23
Extending the Unity Editor EXTENDED!
 おしまい!




           ご清聴ありがとうございました




                                       23/23

More Related Content

What's hot

UnityとnodeとMMDと
UnityとnodeとMMDとUnityとnodeとMMDと
UnityとnodeとMMDと
sters
 
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Compon...
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Compon...【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Compon...
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Compon...
Unity Technologies Japan K.K.
 

What's hot (20)

Android カスタムROMの作り方
Android カスタムROMの作り方Android カスタムROMの作り方
Android カスタムROMの作り方
 
はじめてのAndroid開発
はじめてのAndroid開発はじめてのAndroid開発
はじめてのAndroid開発
 
HoloLensハンズオン:ハンドトラッキング&音声入力編
HoloLensハンズオン:ハンドトラッキング&音声入力編HoloLensハンズオン:ハンドトラッキング&音声入力編
HoloLensハンズオン:ハンドトラッキング&音声入力編
 
Unityティーチャートレーニングデイ -認定アソシエイト編-
Unityティーチャートレーニングデイ -認定アソシエイト編-Unityティーチャートレーニングデイ -認定アソシエイト編-
Unityティーチャートレーニングデイ -認定アソシエイト編-
 
UnityとnodeとMMDと
UnityとnodeとMMDとUnityとnodeとMMDと
UnityとnodeとMMDと
 
【Unity道場 2017】PlayMakerによる初めてのUnityプログラミング
【Unity道場 2017】PlayMakerによる初めてのUnityプログラミング【Unity道場 2017】PlayMakerによる初めてのUnityプログラミング
【Unity道場 2017】PlayMakerによる初めてのUnityプログラミング
 
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Compon...
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Compon...【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Compon...
【Unite Tokyo 2018 Training Day】C#JobSystem & ECSでCPUを極限まで使い倒そう ~Entity Compon...
 
Iosched
IoschedIosched
Iosched
 
Flashup 8
Flashup 8Flashup 8
Flashup 8
 
mobylet ケータイサイト30分クッキング
mobylet ケータイサイト30分クッキングmobylet ケータイサイト30分クッキング
mobylet ケータイサイト30分クッキング
 
SPAJAMでやったこと
SPAJAMでやったことSPAJAMでやったこと
SPAJAMでやったこと
 
ゲームエンジンの文法【UE4】No.005 Gameplay Frameworkの理解
ゲームエンジンの文法【UE4】No.005 Gameplay Frameworkの理解ゲームエンジンの文法【UE4】No.005 Gameplay Frameworkの理解
ゲームエンジンの文法【UE4】No.005 Gameplay Frameworkの理解
 
【Techbuzz】titanium資料
【Techbuzz】titanium資料【Techbuzz】titanium資料
【Techbuzz】titanium資料
 
Android Lecture #01 @PRO&BSC Inc.
Android Lecture #01 @PRO&BSC Inc.Android Lecture #01 @PRO&BSC Inc.
Android Lecture #01 @PRO&BSC Inc.
 
Sencha touchのはじめかた
Sencha touchのはじめかたSencha touchのはじめかた
Sencha touchのはじめかた
 
関西Unity勉強会
関西Unity勉強会関西Unity勉強会
関西Unity勉強会
 
Titanium勉強会
Titanium勉強会Titanium勉強会
Titanium勉強会
 
テストを書こう、Unity編
テストを書こう、Unity編テストを書こう、Unity編
テストを書こう、Unity編
 
0621 ndk game
0621 ndk game0621 ndk game
0621 ndk game
 
enchant.js meetup Tokyo vol.2 Tutorial
enchant.js meetup Tokyo vol.2 Tutorialenchant.js meetup Tokyo vol.2 Tutorial
enchant.js meetup Tokyo vol.2 Tutorial
 

Viewers also liked

Shadow gunのサンプルから学べるモバイル最適化
Shadow gunのサンプルから学べるモバイル最適化Shadow gunのサンプルから学べるモバイル最適化
Shadow gunのサンプルから学べるモバイル最適化
Katsutoshi Makino
 

Viewers also liked (6)

BRDF レンダリングの方程式
BRDF レンダリングの方程式BRDF レンダリングの方程式
BRDF レンダリングの方程式
 
Shadow gunのサンプルから学べるモバイル最適化
Shadow gunのサンプルから学べるモバイル最適化Shadow gunのサンプルから学べるモバイル最適化
Shadow gunのサンプルから学べるモバイル最適化
 
Getting Git Right wrap up #GettingGitRight
Getting Git Right wrap up #GettingGitRightGetting Git Right wrap up #GettingGitRight
Getting Git Right wrap up #GettingGitRight
 
Unityのasset bundle運用実例@lordofknights
Unityのasset bundle運用実例@lordofknightsUnityのasset bundle運用実例@lordofknights
Unityのasset bundle運用実例@lordofknights
 
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移
うちではこうやっています UI構築のルールとPlaymakerを使った画面遷移
 
なぜなにリアルタイムレンダリング
なぜなにリアルタイムレンダリングなぜなにリアルタイムレンダリング
なぜなにリアルタイムレンダリング
 

Similar to Extending the Unity Editor Extended

I Log On Saa S
I Log On Saa SI Log On Saa S
I Log On Saa S
totty jp
 
App widgetでテザリング
App widgetでテザリングApp widgetでテザリング
App widgetでテザリング
Eiichi Tsuru
 

Similar to Extending the Unity Editor Extended (20)

【Unite 2018 Tokyo】エディター拡張マニアクス2018
【Unite 2018 Tokyo】エディター拡張マニアクス2018【Unite 2018 Tokyo】エディター拡張マニアクス2018
【Unite 2018 Tokyo】エディター拡張マニアクス2018
 
OSC2011 Androidハンズオン
OSC2011 AndroidハンズオンOSC2011 Androidハンズオン
OSC2011 Androidハンズオン
 
Unityの夕べ in Fukuoka
Unityの夕べ in FukuokaUnityの夕べ in Fukuoka
Unityの夕べ in Fukuoka
 
Using the Fragments(Android)
Using the Fragments(Android)Using the Fragments(Android)
Using the Fragments(Android)
 
Jetpack Library 事始め
Jetpack Library 事始めJetpack Library 事始め
Jetpack Library 事始め
 
Pin-point rebuildable and non-rebuild custom widget
Pin-point rebuildable and non-rebuild custom widgetPin-point rebuildable and non-rebuild custom widget
Pin-point rebuildable and non-rebuild custom widget
 
Unity勉強会ハンズオン
Unity勉強会ハンズオンUnity勉強会ハンズオン
Unity勉強会ハンズオン
 
Android Wear Apps
Android Wear AppsAndroid Wear Apps
Android Wear Apps
 
そうだプラグイン作ろう =Unityの巻=
そうだプラグイン作ろう =Unityの巻=そうだプラグイン作ろう =Unityの巻=
そうだプラグイン作ろう =Unityの巻=
 
Vue.jsの関連ツール・ライブラリ(Vuex, Vue-Router, Nuxt)
Vue.jsの関連ツール・ライブラリ(Vuex, Vue-Router, Nuxt)Vue.jsの関連ツール・ライブラリ(Vuex, Vue-Router, Nuxt)
Vue.jsの関連ツール・ライブラリ(Vuex, Vue-Router, Nuxt)
 
GroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hackGroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hack
 
Flutter のリアクティブ戦略 set state 〜 redux まで
Flutter のリアクティブ戦略 set state 〜 redux までFlutter のリアクティブ戦略 set state 〜 redux まで
Flutter のリアクティブ戦略 set state 〜 redux まで
 
Beginning iPhone Vol2
Beginning iPhone Vol2Beginning iPhone Vol2
Beginning iPhone Vol2
 
I Log On Saa S
I Log On Saa SI Log On Saa S
I Log On Saa S
 
Android Lecture #04 @PRO&BSC Inc.
Android Lecture #04 @PRO&BSC Inc.Android Lecture #04 @PRO&BSC Inc.
Android Lecture #04 @PRO&BSC Inc.
 
App widgetでテザリング
App widgetでテザリングApp widgetでテザリング
App widgetでテザリング
 
wxPython入門(大阪Pythonユーザの集まり2014/03)
wxPython入門(大阪Pythonユーザの集まり2014/03)wxPython入門(大阪Pythonユーザの集まり2014/03)
wxPython入門(大阪Pythonユーザの集まり2014/03)
 
UE4で作成するUIと最適化手法
UE4で作成するUIと最適化手法UE4で作成するUIと最適化手法
UE4で作成するUIと最適化手法
 
デザイナーとエンジニアが話す、iOSアプリケーション開発
デザイナーとエンジニアが話す、iOSアプリケーション開発デザイナーとエンジニアが話す、iOSアプリケーション開発
デザイナーとエンジニアが話す、iOSアプリケーション開発
 
Tokyo GTUG Bootcamp2010
Tokyo GTUG Bootcamp2010Tokyo GTUG Bootcamp2010
Tokyo GTUG Bootcamp2010
 

Extending the Unity Editor Extended

  • 1. Extending the Unity Editor Unity Editor の 拡張について Ex
  • 2. Extending the Unity Editor EXTENDED! そもそも何が拡張できるのか ・インスペクタの拡張 各コンポーネント(Transformなどのデフォルトコンポーネン トも含む)がインスペクタにどう表示されるかを変更できる。 ・独自ウィンドウの作成 ScriptableWizardで手軽に作ることも、EditorWindowを継 承してがっつり作ることも。ドックにはフラグ1つで対応可! ・アセットインポーターの拡張 アセットインポートの前処理・後処理を独自実装可能。 ・各種ビューの拡張 シーンビューやゲームビュー、プレビュー表示などなど。 ・各種メニューの拡張 アプリケーションメニューやコンテキストメニューなど。 2/23
  • 3. Extending the Unity Editor EXTENDED! インスペクタの拡張 ・どんなことができるのか 表示する内容や表示する際に使用するコンポーネントを変更し たり、ユーティリティ的なボタンを追加したり。 ゲーム中でも使うGUI(Layout) クラスやEditorGUI(Layout)ク ラスに様々なパーツが用意されて いるので、それらを並べるだけで も簡単に拡張できる。 3/23
  • 4. Extending the Unity Editor EXTENDED! インスペクタの拡張 ・どうやればできるのか(1/3) コンポーネント単位での拡張で、インスペクタの内容を変更し たいコンポーネント毎に、対応するEditorクラスを実装する。 using UnityEngine; // 必須 using UnityEditor; // 必須 [CustomEditor(typeof(Hoge))] // Hogeクラス用の拡張であることを宣言 public sealed class HogeEditor : Editor { // このメソッドをオーバーライドして処理を書いていく public override void OnInspectorGUI() { } } [CustomEditor(typeof(Transform))] // 既存のクラスを拡張することも可能 public sealed class CustomTransformEditor : Editor { public override void OnInspectorGUI() { 4/23
  • 5. Extending the Unity Editor EXTENDED! インスペクタの拡張 ・どうやればできるのか(2/3) とりあえずOnInspectorGUI()内でDrawDefaultInspector() を呼んでおけばデフォルトの表示をやってくれる。 public override void OnInspectorGUI() { DrawDefaultInspector(); // とりあえずデフォルトの表示 } またserializedObjectプロパティを利用すればデフォルトで表 示すべき要素にひと通りアクセスできる。 public override void OnInspectorGUI() { // この書き方だと実行に支障はないのに何故かエラーが出るんだけど… foreach (SerializedProperty p in serializedObject.GetIterator()) { EditorGUILayout.PropertyField(p); } } 5/23
  • 6. Extending the Unity Editor EXTENDED! インスペクタの拡張 ・どうやればできるのか(3/3) 要素の表示は基本的にGUILayoutクラスとEditorGUILayout クラスを利用する。 static Vector3 copyBuffer = Vector3.zero; public override void OnInspectorGUI() { Hoge hoge = target as Hoge; Vector3 v = EditorGUILayout.Vector3Field("Velocity", hoge.velocity); EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Reset", EditorStyles.miniButton)) v = Vector3.zero; GUILayout.Space(GUILayoutUtility.GetAspectRect(1).width / 3); if (GUILayout.Button("Copy", EditorStyles.miniButtonLeft)) copyBuffer = v; if (GUILayout.Button("Paste", EditorStyles.miniButtonRight)) v = copyBuffer; EditorGUILayout.EndHorizontal(); if (v != hoge.velocity) { Undo.RegisterUndo(hoge, "Velocity Change"); hoge.velocity = v; EditorUtility.SetDirty(target); } } 6/23
  • 7. Extending the Unity Editor EXTENDED! 独自ウィンドウの作成 ・どんなことができるのか アプリケーションの「Window」メニューから開けるような ウィンドウを独自に作成することができる。 ※画像はAPARTURE Cutscene Editorの例 エディタにドックさせて常に表示しておくような物や、ダイア ログのように一時的に表示するような物など、用途に応じて。 呼び出し方は後述するメニューの拡張でアプリケーションのメ ニューに独自ウィンドウを開く項目を追加したり、拡張したイ ンスペクタに独自ウィンドウを開くためのボタンを追加した り、色々考えられる。 7/23
  • 8. Extending the Unity Editor EXTENDED! 独自ウィンドウの作成 ・どうやればできるのか(1/4) ごく簡単なものならScriptableWizardを継承したクラスを実 装すれば、そのパブリックメンバ変数を適当に並べたウィンド ウをUnityが自動的に作ってくれる。 using UnityEngine; // 必須 using UnityEditor; // 必須 public sealed class MaterialReplacer : ScriptableWizard // ScriptableWizardクラスを継承する { public Material replaceTo; // インスペクタのようにpublicメンバが自動的に列挙される [MenuItem("Tools/Replace Material...")] // このウィザードを開くメニュー項目を追加 static void OpenWindow() { ScriptableWizard.DisplayWizard<MaterialReplacer>("Replace Material", "Apply"); } void OnWizardCreate() { // ボタンが押された時の処理をここに書いていく } } 8/23
  • 9. Extending the Unity Editor EXTENDED! 独自ウィンドウの作成 ・どうやればできるのか(2/4) 先ほどのクラスのOnWizardCreate()を実装する。 using System.Linq; // Linqを使うので ... void OnWizardCreate() // ボタン1つの場合のデフォルト表示が「Create」なのでこんなメソッド名らしい { if (replaceTo == null) // マテリアルが選択されていなかったら何もしない return; var renderers = from r in Selection.gameObjects where r.renderer != null select r.renderer; foreach (Renderer r in renderers) r.sharedMaterial = replaceTo; } Applyボタンを押すと 選択中のオブジェクト のマテリアルが指定し たものに置き換わり、 ウィンドウが閉じる。 9/23
  • 10. Extending the Unity Editor EXTENDED! 独自ウィンドウの作成 ・どうやればできるのか(3/4) ドックして常駐させたり、もっと凝った処理を行いたい場合は EditorWindowを継承したクラスを実装する。 using UnityEngine; // 必須 using UnityEditor; // 必須 public sealed class MaterialReplacer : EditorWindow // EditorWindowクラスを継承する { [MenuItem("Tool/Replace Material...")] // このウィンドウを開くメニュー項目を追加 static void OpenWindow() { EditorWindow.GetWindow<MaterialReplacer>(true, "Replace Material"); } void OnGUI() { // カスタムウィンドウはOnGUI()の中に表示含め処理を書いていく(インスペクタの拡張と似ている) } } 10/23
  • 11. Extending the Unity Editor EXTENDED! 独自ウィンドウの作成 ・どうやればできるのか(4/4) 先ほどのクラスのOnGUI()を実装する。 using System.Linq; // Linqを使うので ... static Material targetMaterial = null; void OnGUI() // ScriptableWizar版とまったく同じ処理を書いてみる { targetMaterial = EditorGUILayout.ObjectField( "Replace To", targetMaterial, typeof(Material), false ) as Material; // マテリアルや対象のオブジェクトが選択されていなかったら決定できないようにしてみる GUI.enabled = (targetMaterial != null) && (Selection.gameObjects.Length > 0); if (GUILayout.Button("Apply")) { var renderers = from r in Selection.gameObjects where r.renderer != null select r.renderer; foreach (Renderer r in renderers) r.sharedMaterial = targetMaterial; Close(); } GUI.enabled = true; } 11/23
  • 12. Extending the Unity Editor EXTENDED! アセットインポーターの拡張 ・どんなことができるのか モデルやテクスチャをインポートする時に独自の処理を加える ことができる。 またモデルインポートの際にUnityが自動で作ってくれる(作っ てしまう)マテリアルを独自のものに差し替えたり、そもそも マテリアルの生成を抑止したりもできる。 ただし個別に処理できるのがモデル・テクスチャ・サウンドだ けで、他は全てのインポートが終わった後にしかアクセスでき ないなど少し柔軟性に欠ける。 しかもそのOnPostprocessAllAssetsメソッドはstaticメ ソッドにしておかないと機能しないというトラップ付き! 12/23
  • 13. Extending the Unity Editor EXTENDED! アセットインポーターの拡張 ・どうやればできるのか AssetPostprocessorを継承したクラスを定義し、 OnPostprocessModel()などのメソッドをオーバーライドし ていく。自作のポストプロセッサーが複数ある場合、処理順を 指定することもできる。 using UnityEngine; // 必須 using UnityEditor; // 必須 public sealed class CustomModelImporter : AssetPostprocessor { public override int GetPostprocessOrder() { return 0; // 全てのポストプロセッサーを通して、ここで返す値が小さい順に処理される } void OnPreprocessModel() { // アニメーションセットをインポートするときはマテリアルを生成しない、みたいな if (assetPath.Contains("@")) (assetImporter as ModelImporter).importMaterials = false; } } 13/23
  • 14. Extending the Unity Editor EXTENDED! 各種ビューの拡張 ・どんなことができるのか Gizmosを使ってビューにラインやアイコンを描いたり、 Handlesを使ってハンドル(マニピュレータ)を表示したり。 上記は基本的にシーンビューへの描画だが、ゲームビューへの 描画もできる(後述)。 ハンドルは掴んで動かしてその結 果を受け取る、というところまで 面倒を見てくれるので便利。 またEditor.OnPreviewGUI()を オーバーライドすればインスペク タ下段に表示されているプレビュ 表示に手を加えることもできる。 14/23
  • 15. Extending the Unity Editor EXTENDED! 各種ビューの拡張 ・どうやればできるのか(1/3) シーンビューに対する描画は、Editorクラスを継承してインス ペクタを拡張すると、そのインスタンスにOnSceneGUIとい うメッセージが飛んでくるのでそれを捕まえるか、 SceneViewというUndocumentedなクラスがあり、それの onSceneGUIDelegateというプロパティに適当なメソッドを 投げると、先ほどのOnSceneGUI相当の処理ができる。但し 後者は非公式。 void OnSceneGUI() { Vector3 pos = (target as Hoge).transform.position; float size = HandleUtility.GetHandleSize(pos); // カメラ距離によらないサイズの計算 Handles.DrawSolidDisc(pos, Vector3.up, size); } static HogeEditor() // デリゲートの登録は1度でいいのでstaticコンストラクタから登録してみる { SceneView.onSceneGUIDelegate += view => { Handles.DrawLine(Vector3.zero, Vector3.up); }; } 15/23
  • 16. Extending the Unity Editor EXTENDED! 各種ビューの拡張 ・どうやればできるのか(2/3) ゲームビューに対する描画は少し特殊で、hideFlagsを HideFlags.HideAndDontSaveにしたゲームオブジェクトに ExecuteInEditMode属性を付けたコンポーネントを貼り付け るのが手っ取り早い。 // こんなコンポーネントを作っておいて [ExecuteInEditMode()] public sealed class GameViewUpdater : MonoBehaviour { void OnGUI() { // 適当な処理 } } ... // 例えばインスペクタのOnEnableで隠しゲームオブジェクトを生成し、先ほどのコンポーネントを貼り付ける void OnEnable() { GameObject go = new GameObject(); go.hideFlags = HideFlags.HideAndDontSave; go.AddComponent<GameViewUpdater>(); } 16/23
  • 17. Extending the Unity Editor EXTENDED! 各種ビューの拡張 ・どうやればできるのか(3/3) プレビュー表示への描画は拡張インスペクタで HasPreviewGUIがtrueを返すようにオーバーライドし、 OnPreviewGUIの中に処理を書いていく。 ただし何故かレイアウトが下詰め。謎。 public override bool HasPreviewGUI () { return true; } public override void OnPreviewGUI(Rect r, GUIStyle bg) { GUILayout.Label("Label"); GUILayout.Button("Button"); } 17/23
  • 18. Extending the Unity Editor EXTENDED! 各種メニューの拡張 ・どんなことができるのか 既に存在するアプリケーションメニュー(例えば「Window」 とか)に要素を追加することもできるし、新しいメニュー項目 を増やすこともできる。 また既存のコンテキストメニュー(インスペクタ上で右クリッ クするか、インスペクタの右上にあるちっちゃい歯車のアイコ ンを押すと出る)に要素を追加したり、独自のコンテキストメ ニューを作ったりすることもできる。 日本語は正しく処理できないっぽいです…遊んでたら落ちました 18/23
  • 19. Extending the Unity Editor EXTENDED! 各種メニューの拡張 ・どうやればできるのか(1/3) アプリケーションメニューへの追加は、MenuItem属性を使用 する。「<項目名>/<要素名>」のようなパス形式でどこにな んというメニューを追加するか指定できる。呼び出すメソッド はどこで宣言したものでも構わない代わりに、staticでなけれ ばならない。 [MenuItem("Tools/MyMenu")] // MenuItem属性の引数でどこに追加するか指定する static void MyMenuItem() // メニューが選択されるとこのメソッドが呼ばれる { } 19/23
  • 20. Extending the Unity Editor EXTENDED! 各種メニューの拡張 ・どうやればできるのか(2/3) コンテキストメニューへの追加は、MenuItem属性を使う方法 と、コンポーネントクラスに直接ContextMenu属性を付ける 方法がある。 MenuItem属性を使う場合はやはりメソッドはstaticでなけれ ばならないが、ContextMenu属性を使う場合はその限りでは ない。 [MenuItem("CONTEXT/Hoge/MyMenu")] // Hogeコンポーネントのコンテキストメニューに追加する場合 static void MyMenu() { } ... public class Hoge : MonoBehaviour // 上記と全く同じメニューをコンポーネントから追加する場合 { [ContexMenu("MyMenu")] void MyMenu() { } } 20/23
  • 21. Extending the Unity Editor EXTENDED! 各種メニューの拡張 ・どうやればできるのか(3/3) マウスイベントをトラップして独自のコンテキストメニューを 表示することもできる。インスペクタでも、ウィンドウでも。 // メニューの項目が選択された時の処理をあらかじめ定義しておく(別にラムダ式でもいいけど) void Callback(Object obj) { (obj as Hoge).transform.position = Vector3.zero } // 例えばインスペクタのプレビュー表示上で右クリックされた場合に独自のコンテキストメニューを出す public override void OnPreviewGUI(Rect r, GUIStyle background) { // 飛んできたイベントをチェックして、範囲内での右クリックだったら処理する var evt = Event.current; if (evt.type == EventType.ContextClick && r.Contains(evt.mousePosition)) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("Reset Position"), false, Callback, target); menu.ShowAsContext(); evt.Use(); // 自前で処理したイベントは握りつぶしておく } DrawDefaultInspector(); } 21/23
  • 22. Extending the Unity Editor EXTENDED! ワークフローへの組み込み ・アーティスト→プログラマー アセット読み込み時の各種設定を自動化 アニメーションやコリジョンなどの編集支援 ・プログラマー→ゲームデザイナー ゲームデータ入力支援 外部データの読み込み ・プログラマー→プログラマー デバッグ支援 ビルド自動化 アセットバンドル 22/23
  • 23. Extending the Unity Editor EXTENDED! おしまい! ご清聴ありがとうございました 23/23