Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

知って得するUnity エディタ拡張編

36,810 views

Published on

Published in: Technology

知って得するUnity エディタ拡張編

  1. 1. 知って得する Unity エディタ拡張編 株式会社ハ・ン・ド プログラマ 馬場翔太 http://baba-s.hatenablog.com/
  2. 2. スライド内容 1. PropertyDrawerでUnityエディタを拡張する 2. AssetPostprocessorでアセットを監視する 3. MenuItemでソースコードを自動生成する
  3. 3. PropertyDrawerで Unityエディタを拡張する
  4. 4. エディタ拡張は二通りの方法で行えます • CustomEditorを使用する スクリプト単位によるエディタ拡張 • PropertyDrawerを使用する プロパティ単位によるエディタ拡張 このスライドで紹介する機能 使いまわしやすい!
  5. 5. 標準で用意されているPropertyDrawer • RangeAttribute • MultilineAttribute
  6. 6. RangeAttributeを使うと… 値の入力範囲を制限できるようになります using UnityEngine; public class Character : MonoBehaviour { [Range(1, 100)] public int Level = 1; }
  7. 7. MultilineAttributeを使うと… 文字列を複数行で入力できるようになります using UnityEngine; public class Character : MonoBehaviour { [Multiline(3)] public string Comment; }
  8. 8. 独自のPropertyDrawerを作成して使用する RangeAttributeやMultilineAttributeのような PropertyDrawerは自分で作成可能です
  9. 9. 独自のPropertyDrawerを作成して使用する プロパティ名を変更できる PropertyDrawerを作成してみましょう using UnityEngine; public class Character : MonoBehaviour { [MyProperty("名前")] public string Name; }
  10. 10. using UnityEngine; public class MyPropertyAttribute : PropertyAttribute { public string Label; public MyPropertyAttribute(string label) { Label = label; } } 1.PropertyAttributeを継承したクラス作成
  11. 11. using UnityEditor; using UnityEngine; [CustomPropertyDrawer(typeof(MyPropertyAttribute))] public class MyPropertyDrawer : PropertyDrawer { } 2.PropertyDrawerを継承したクラスを作成
  12. 12. public override void OnGUI( Rect position, SerializedProperty property, GUIContent label) { var myPropertyAttribute = attribute as MyPropertyAttribute; property.stringValue = EditorGUI.TextField( position, myPropertyAttribute.Label, property.stringValue); } 3. OnGUI関数をオーバーライドして実装
  13. 13. using UnityEngine; public class Character : MonoBehaviour { [MyProperty("名前")] public string Name; } 4.作成したPropertyDrawerを使用する
  14. 14. PropertyDrawer作成時の注意 PropertyDrawerを継承したクラスは Editorフォルダに保存するか #if UNITY_EDITOR ~ #endifで囲まないと ビルド時にエラーになるので気をつけてください
  15. 15. MyPropertyAttribute.csを手に入れる 今回作成したMyPropertyAttributeは Gistで公開しているので参考にしてください 1. 下記のサイトからMyPropertyAttribute.csを取得する https://gist.github.com/baba-s/9430324 2. 下記のサイトからMyPropertyDrawer.csを取得する https://gist.github.com/baba-s/9430335 3. MyPropertyAttribute.csを Unityプロジェクトに追加する 4. MyPropertyDrawer.csを UnityプロジェクトのEditorフォルダに追加する
  16. 16. PropertyDrawerのサンプル https://github.com/anchan828/property-drawer-collection http://blogs.unity3d.com/2012/09/07/property-drawers-in-unity-4/ ネット上で公開されている PropertyDrawerを使用してみましょう • CompactAttribute • EnumLabelAttribute • PopupAttribute • SceneNameAttribute • RegexAttribute
  17. 17. using UnityEngine; public class Character : MonoBehaviour { public Vector3 Position; } Vector2やVector3の入力を楽にしたい
  18. 18. CompactAttribute.csを手に入れる 1. 下記のサイトからCompactAttribute.csを取得する https://github.com/anchan828/property-drawer-collection 2. CompactAttribute.csをUnityプロジェクトに追加する
  19. 19. using UnityEngine; public class Character : MonoBehaviour { [Compact] public Vector3 Position; } CompactAttributeを使用する
  20. 20. using UnityEngine; public class Character : MonoBehaviour { public enum JobType { SOLDIER, SORCERER, } public JobType Job; } 列挙型の表示名を変えたい
  21. 21. EnumLabelAttribute.csを手に入れる 1. 下記のサイトからEnumLabelAttribute.csを取得する https://github.com/anchan828/property-drawer-collection 2. EnumLabelAttribute.csをUnityプロジェクトに追加する
  22. 22. using UnityEngine; public class Character : MonoBehaviour { public enum JobType { [EnumLabel("王国兵士")] SOLDIER, [EnumLabel("魔法使い")] SORCERER, } [EnumLabel("ジョブ")] public JobType Job; } EnumLabelAttributeを使用する
  23. 23. using UnityEngine; public class Character : MonoBehaviour { public string Job; public int Money; } 入力できる値をポップアップで制限したい
  24. 24. PopupAttribute.csを手に入れる 1. 下記のサイトからPopupAttribute.csを取得する https://github.com/anchan828/property-drawer-collection 2. PopupAttribute.csをUnityプロジェクトに追加する
  25. 25. using UnityEngine; public class Character : MonoBehaviour { [Popup("王国兵士", "魔法使い")] public string Job; [Popup(1, 5, 10, 50, 100, 500)] public int Money; } PopupAttributeを使用する
  26. 26. using UnityEngine; public class LoadSceneButton : MonoBehaviour { public string SceneName; } ポップアップでシーン名を設定したい
  27. 27. SceneNameAttribute.csを手に入れる 1. 下記のサイトからSceneNameAttribute.csを取得する https://github.com/anchan828/property-drawer-collection 2. SceneNameAttribute.csをUnityプロジェクトに追加する
  28. 28. using UnityEngine; public class LoadSceneButton : MonoBehaviour { [SceneName] public string SceneName; } SceneNameAttributeを使用する
  29. 29. using UnityEngine; public class Config : MonoBehaviour { // IPアドレス public string ServerAddress; } 入力できる値を正規表現で制限したい
  30. 30. RegexAttribute.csを手に入れる 1. 下記のサイトからRegexAttribute.csを取得する https://gist.github.com/baba-s/9430471 2. RegexAttribute.csをUnityプロジェクトに追加する
  31. 31. using UnityEngine; public class Config : MonoBehaviour { // IPアドレス [Regex(@"^(?:¥d{1,3}¥.){3}¥d{1,3}$", "無効なIPアドレスです!例:'127.0.0.1'")] public string ServerAddress; } RegexAttributeを使用する
  32. 32. PropertyDrawerまとめ PropertyDrawerを使用すると スクリプト単位ではなく プロパティ単位でエディタ拡張が可能なので 多くのスクリプトやプロジェクトで使いまわせます
  33. 33. AssetPostprocessorで アセットを監視する
  34. 34. AssetPostprocessorを使うと… • 特定のファイルのみ Unityプロジェクトに追加不能にできる • テクスチャやAudioClipの設定を Unityプロジェクトに追加された時に変更できる
  35. 35. 独自のAssetPostprocessorを作成してみる 全角文字が含まれたファイルが プロジェクトに追加されたら自動で削除する AssetPostprocessorを作成してみましょう
  36. 36. 1.AssetPostprocessorのサブクラスを作成 using UnityEditor; using UnityEngine; public class MyAssetPostprocessor : AssetPostprocessor { }
  37. 37. 2.全角文字を含むか判定する関数を追加 // 1バイト文字で構成された文字列かどうかを判定します // 1バイト文字のみで構成された文字列の場合 true // 2バイト文字が含まれている文字列の場合 false private static bool IsOneByteStr(string str) { var bytes = System.Text.Encoding.GetEncoding(932).GetBytes(str); return bytes.Length == str.Length; } http://7ujm.net/NET%20Framework/isOneByteChar.html
  38. 38. 3. OnPostprocessAllAssets関数を定義 // すべてのアセットのインポートが終了した際に呼び出されます // importedAssets :インポートされたアセットのパス // deletedAssets :削除されたアセットのパス // movedAssets :移動したアセットの移動後のパス // movedFromPath:移動したアセットの移動前のパス private static void OnPostprocessAllAssets( string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromPath) { }
  39. 39. 4.AssetDatabase.DeleteAssetを利用 foreach (var importedAsset in importedAssets) { if (!IsOneByteStr(importedAsset)) { // 指定されたパスに存在するアセットを削除します if (AssetDatabase.DeleteAsset(importedAsset)) { Debug.Log(importedAsset + "を削除しました"); } } }
  40. 40. MyAssetPostprocessor.csを手に入れる 今回作成したMyAssetPostprocessorは Gistで公開しているので参考にしてください 1. 下記のサイトからMyAssetPostprocessor.csを取得する https://gist.github.com/baba-s/9426854 2. MyAssetPostprocessor.csを UnityプロジェクトのEditorフォルダに追加する
  41. 41. MenuItemで ソースコードを自動生成する
  42. 42. MenuItemを使うと… Unityエディタに独自の機能を追加できます • すべてのシーンのオブジェクトから 不要なコンポーネントを削除する機能を追加したり… • 選択中のゲームオブジェクトのパラメータを 一括で設定する機能を追加したり…
  43. 43. 独自のMenuItemを作成してみる ソースコードを自動生成する MenuItemを作成してみましょう
  44. 44. using UnityEditor; public static class MyClassCreator { // Unityエディタのメニューに // ソースコード自動生成用のコマンドを追加します [MenuItem("Tools/Create My Class")] private static void Create() { } } 1.MenuItemが適用された静的関数を作成
  45. 45. // ソースコードを表す文字列を作成します var builder = new System.Text.StringBuilder(); builder.AppendLine("public class MyClass"); builder.AppendLine("{"); builder.AppendLine("}"); 2.StringBuilderで文字列を作成
  46. 46. // 新しいファイルを作成して // ソースコードを表す文字列を書き込みます System.IO.File.WriteAllText( "Assets/MyClass.cs", builder.ToString(), System.Text.Encoding.UTF8); 3.File.WriteAllTextでファイルを作成
  47. 47. // Unityのアセットデータベースをリフレッシュします AssetDatabase.Refresh( ImportAssetOptions.ImportRecursive); 4.AssetDatabase.Refreshを実行
  48. 48. 5.用意したUnityエディタのコマンドを実行 public class MyClass { }
  49. 49. MyClassCreator.csを手に入れる 今回作成したMyClassCreatorは Gistで公開しているので参考にしてください 1. 下記のサイトからMyClassCreator.csを取得する https://gist.github.com/baba-s/9446762 2. MyClassCreator.csを UnityプロジェクトのEditorフォルダに追加する
  50. 50. ソースコードの自動生成のサンプル MenuItemを使用して データを定数で管理するクラスの 自動生成を行ってみましょう • シーン名を定数で管理するクラスの自動生成 • タグ名を定数で管理するクラスの自動生成 • レイヤー名を定数で管理するクラスの自動生成
  51. 51. シーン名を定数で管理するクラスの生成
  52. 52. シーン名の一覧を取得する方法 EditorBuildSettings.scenesを使用すると シーン名の一覧を取得できます foreach (var n in EditorBuildSettings.scenes) { Debug.Log(n); }
  53. 53. シーン名を定数で管理するクラスの生成 1. 下記のサイトからSceneNameCreator.csを取得する https://gist.github.com/baba-s/9286120 2. SceneNameCreator.csをEditorフォルダに追加する 3. Unityエディタの「Tools>Create>Scene Name」を実行する 4. SceneName.csが作成される
  54. 54. シーン名を定数で管理するクラスの生成 /// <summary> /// シーン名を定数で管理するクラス /// </summary> public static class SceneName { public const string Title = "Title"; public const string MainMenu = "MainMenu"; }
  55. 55. シーン名を定数で管理するクラスの利用 // タイトル画面に遷移します Application.LoadLevel(SceneName.Title); // タイトル画面に遷移します Application.LoadLevel("Title");
  56. 56. タグ名を定数で管理するクラスの生成
  57. 57. タグ名の一覧を取得する方法 InternalEditorUtility.tagsを使用すると タグ名の一覧を取得できます foreach (var n in InternalEditorUtility.tags) { Debug.Log(n); }
  58. 58. タグ名を定数で管理するクラスの生成 1. 下記のサイトからTagNameCreator.csを取得する https://gist.github.com/baba-s/9287103 2. TagNameCreator.csをEditorフォルダに追加する 3. Unityエディタの「Tools>Create>Tag Name」を実行する 4. TagName.csが作成される
  59. 59. タグ名を定数で管理するクラスの生成 /// <summary> /// タグ名を定数で管理するクラス /// </summary> public static class TagName { public const string Untagged = "Untagged"; public const string Respawn = "Respawn"; public const string Finish = "Finish"; public const string EditorOnly = "EditorOnly"; public const string MainCamera = "MainCamera"; public const string Player = "Player"; public const string GameController = "GameController"; public const string Character = "Character"; }
  60. 60. タグ名を定数で管理するクラスの利用 // ゲームオブジェクトがキャラクターかどうか if (gameObject.CompareTag(TagName.Character)) { // ... } // ゲームオブジェクトがキャラクターかどうか if (gameObject.CompareTag("Character")) { // ... }
  61. 61. レイヤー名を定数で管理するクラスの生成
  62. 62. レイヤー名の一覧を取得する方法 InternalEditorUtility.layersを使用すると レイヤー名の一覧を取得できます foreach (var n in InternalEditorUtility.layers) { Debug.Log(n); }
  63. 63. レイヤー名を定数で管理するクラスの生成 1. 下記のサイトからLayerNameCreator.csを取得する https://gist.github.com/baba-s/9286212 2. LayerNameCreator.csをEditorフォルダに追加する 3. Unityエディタの「Tools>Create>Layer Name」を実行する 4. LayerName.csが作成される
  64. 64. レイヤー名を定数で管理するクラスの生成 /// <summary> /// レイヤー名を定数で管理するクラス /// </summary> public static class LayerName { public const int Default = 0; public const int TransparentFX = 1; public const int IgnoreRaycast = 2; public const int Water = 4; public const int Character = 8; public const int DefaultMask = 1; public const int TransparentFXMask = 2; public const int IgnoreRaycastMask = 4; public const int WaterMask = 16; public const int CharacterMask = 256; }
  65. 65. レイヤー名を定数で管理するクラスの利用 // ゲームオブジェクトのレイヤーを変更します gameObject.layer = LayerName.Character; // ゲームオブジェクトのレイヤーを変更します gameObject.layer = 8;
  66. 66. MenuItemまとめ MenuItemを使用すると Unity APIから取得したデータをもとに ソースコードの自動生成を行うこともできます シーン名やタグ名を定数で管理するクラスを 自動生成できるようにしておくことで タイプセーフなゲーム開発を行うことが可能です
  67. 67. ありがとうございました

×