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

32,475 views

Published on

Published in: Technology
1 Comment
90 Likes
Statistics
Notes
No Downloads
Views
Total views
32,475
On SlideShare
0
From Embeds
0
Number of Embeds
4,184
Actions
Shares
0
Downloads
147
Comments
1
Likes
90
Embeds 0
No embeds

No notes for slide

知って得する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. ありがとうございました

×