(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

(:3[kanのメモ帳]


本ブログの運営者kan.kikuchiが個人で開発したゲームです!


テンプレメニューを自動で更新する【Unity】【エディタ拡張】


このエントリーをはてなブックマークに追加



この記事でのバージョン
Unity 4.6.3f1


はじめに

前回、既存のスクリプトからテンプレを作れるようにはなったけど、

その後にCreateメニューに表示するためにコード書くのめんどくね?

って所で終わりました。




なので今回はテンプレメニューを自動で更新するエディタ拡張のご紹介!


プログラム

何はなくともプログラムから!長いですよ!


CustomScriptCreatorが前回同様、テンプレから新たにスクリプトを作るクラス

TemplateScriptCreatorも前回同様、既存スクリプトから新たにテンプレを作るクラス

TemplatePostprocessorが今回作成した、テンプレメニューを自動で更新するクラス

AssetPostprocessorExは、以前作ったAssetPostprocessorの拡張クラス

Extensionは、拡張子の定数クラス

DirectoryPathは、ディレクトリへのパスの定数クラス

TemplateTagNameは、Templateで使うタグ名の定数クラス



CustomScriptCreatorにメニュー表示用コードを追加していくのでは無く、

各テンプレ毎にCustomScriptCreatorを継承したクラスを作りメニューを追加するようにしました。

さらに各テンプレ毎のCustomScriptCreatorはTemplatePostprocessorで自動更新をしています。


自動更新の方法はテンプレが入っているディレクトリを監視し、

テンプレが追加されれば、そのテンプレ用CustomScriptCreatorを作成

テンプレが削除されれば該当するCustomScriptCreatorを削除、

とい言った具合です。


また、前回は共通して使う定数をScriptCreatorにまとめて、それを継承していましたが、

今回は各定数クラスにまとめていますのでご注意を!


使い方

まずAssetPostprocessorEx、TemplatePostprocessor、CustomScriptCreator、TemplateScriptCreator、

を以下のような構成で、Editorディレクトリに入れます


f:id:kan_kikuchi:20150527072103p:plain


次にDirectoryPath、Extension、TemplateTagNameを

どこでもいいので、適当なディレクトリに入れます。


最後にScriptsというディレクトリを作り、

その下にさらにTemplatesというディレクトリを作り、準備完了です。


最初はCreateメニューにTemplate Scriptという項目が追加されただけですが、


f:id:kan_kikuchi:20150527072914p:plain


任意スクリプト、例えばHeroというクラスを選択しTemplate Scriptを押し、

テンプレを作成すると……


f:id:kan_kikuchi:20150527073013p:plain


Custom Scriptとその先にHeroという項目が自動で追加されます!


f:id:kan_kikuchi:20150527073044p:plain


テンプレ作成後にコードを追加する手間が無くなりました!楽!


Template Scriptの詳しい使い方は前回記事、

Custom Scriptの詳しい使い方は前々回記事を参照のこと!


コード説明

ではでは項目ごとにTemplatePostprocessorのコード説明です!

CustomScriptCreator周りの説明は前々回記事を参照のこと。

TemplateScriptCreator周りの説明は前回記事を参照のこと。


OnPostprocessAllAssets

OnPostprocessAllAssetsでテンプレが入っているディレクトリを監視し、

変更があった時にCustomScriptCreatorの更新を行っています。

詳しくは下記の記事で!



念の為、[MenuItem(COMMAND_NAME)]を更新メソッドの前に書く事で、

任意のタイミングで更新を実行する事も出来るようにしています。


テンプレに対応するCustomScriptCreatorが無ければ作成

System.IO.Directory.GetFilesでテンプレのテキストを全て取得し、そのファイル名から

該当するCustomScriptCreatorのパスを作成、そのパスにファイルが無ければ、

CreateCustomScriptCreatorでCustomScriptCreatorを作成しています。

//テンプレートフォルダ内のtextファイルへのパスを全て取得
string templateDirectoryPath = DirectoryPath.TEMPLATE_SCRIPT_DIRECTORY_PATH;
string[] templatePathArray = System.IO.Directory.GetFiles (templateDirectoryPath, "*" + Extension.TEMPLATE_SCRIPT);

foreach(string templatePath in templatePathArray){

  //拡張子を含まないファイル名を取得
  string templateName = System.IO.Path.GetFileNameWithoutExtension(templatePath);

  //書き出し先
  string exportPath = EXPORT_DIRECTORY_PATH + string.Format (EXPORT_SCRIPT_NAME_FORMAT, templateName);

  //このテンプレのCustomScriptCreatorが作成されていなければ作成
  if (!System.IO.File.Exists(exportPath)){
    CreateCustomScriptCreator (templateName, exportPath);
  }

}


なお、テンプレ以外のファイルがあっても、処理を行ってしまうため、

注意が必要です。


CreateCustomScriptCreator

CreateCustomScriptCreatorではCustomScriptCreatorを継承したクラスを作成し、

新たにcreateのCustom Scriptにメニューを追加してます。

//CustomScriptCreatorを作成、Createのメニューで対象のテンプレートを選べるようになる
private static void CreateCustomScriptCreator(string templateName, string exportPath){

  string customScriptCreatorName = System.IO.Path.GetFileNameWithoutExtension(exportPath);

  //作成するスクリプトの内容
  string scriptText = 
    "using UnityEditor;\n\n" +
    "/// <summary>\n" +
    "/// " + templateName +"のテンプレートから新しくスクリプトを作るクラス\n" +
    "/// </summary>\n" +
    "public class " + customScriptCreatorName + " : CustomScriptCreator {\n\n\t" +
    "private const string TEMPLATE_SCRIPT_NAME  = \"" + templateName + "\";\n\n\t" +
    "[MenuItem(MENU_PATH + TEMPLATE_SCRIPT_NAME)]\n\t" +
    "private static void CreateScript(){\n\t\t" +
    "ShowWindow (TEMPLATE_SCRIPT_NAME);\n\t" +
    "}\n\n" +
    "}\n";
		 
  //スクリプトを書き出し
  File.WriteAllText (exportPath, scriptText, Encoding.UTF8);
  AssetDatabase.Refresh (ImportAssetOptions.ImportRecursive);

  Debug.Log (exportPath + "を作成しました");
}


これでメニューに追加する部分を自動作成出来るように……!


該当するテンプレが無いCustomScriptCreatorを削除

テンプレを削除した場合にCustomScriptCreatorだけが残り、

createメニューに存在しないテンプレを表示し続けてしまうので、

以下のコードでCustomScriptCreatorの削除を行っています。

//テンプレートを再度取得し、テンプレートファイル名のリストを作る
templatePathArray = System.IO.Directory.GetFiles (templateDirectoryPath, "*" + Extension.TEMPLATE_SCRIPT);
List<string > templateNameList = templatePathArray.
                                 Select(path => System.IO.Path.GetFileNameWithoutExtension(path)).
                                 ToList();

//CustomScriptCreatorフォルダ内のスクリプトを全て取得
string[] customScriptCreatorPathArray = System.IO.Directory.GetFiles (EXPORT_DIRECTORY_PATH, "*" + Extension.SCRIPT);

foreach (string customScriptCreatorPath in customScriptCreatorPathArray) {

  //拡張子を含まないファイル名を取得
  string scriptName = System.IO.Path.GetFileNameWithoutExtension(customScriptCreatorPath);

  //スクリプトから元のテンプレ名を取得
  string templateName = scriptName.Remove (scriptName.Length - EXPORT_SCRIPT_NAME_END.Length, EXPORT_SCRIPT_NAME_END.Length);

  //該当するテンプレが無ければCustomScriptCreatorを削除
  if(!templateNameList.Contains(templateName)){
    System.IO.File.Delete(customScriptCreatorPath);
    AssetDatabase.Refresh (ImportAssetOptions.ImportRecursive);
    Debug.Log (customScriptCreatorPath + "を削除しました");
  }

}


これまたCustomScriptCreator以外のファイルがあっても、処理を行ってしまうため、

注意が必要です。


あと、templateNameListの作成部分はLINQを使っています。

LINQについてはこちらをどうぞ!


おわりに

テンプレメニューを自動で更新するという目標は達成できましたが、

そもそもテンプレって頻繁に追加しなくね?


( ゚ Д゚)ハッ!


という事でこのシリーズは以上です!