スクリプトをテンプレートを元に作るようにエディタ拡張してみた

# この記事について
実装した事のアウトプットを兼ねて記事を作成しています。
間違った使い方や実装をしている可能性もありますのでご容赦ください。
コメント欄にてご指摘頂けると幸いです。

# 参考にさせて頂いた記事

https://shikaku-sh.hatenablog.com/entry/unity-create-script-file-from-template-with-extending-editor

# 実装した画像

・項目を選ぶとスクリプトがファイル内に作成される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/d1fa02c3-d81c-d1e1-1b8a-4bc0e473b612.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/25b2c143-a581-0629-8b97-c3fbec49a475.png)

・作成したスクリプトを開くとinterfaceクラスが既に作成されている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/9666ffe4-150d-0cb3-4166-1a42d5fc97f8.png)

(動画が動かなかったので画像にしました。ごめんなさい！)

# 実装したコード
調べながら作ったのでコメントを沢山書いています。
良かったら読んでみてください。

```C#
using System.IO;
using UnityEditor;

namespace Hamster.Editor
{
    static internal class MenuItemSettings
    {
        // テンプレートのファイルパス
        private const string templateFilePath = "Assets/ScriptFilesFromTemplate";

        // テンプレートが保存されている場所のファイルパス
        private const string templateDirectoryPath = "Templates";

        // インターフェースのテンプレートファイル名
        private const string interfaceTemplateFileName = "InterfaceTemplate.txt";

        // 作成するスクリプトの名前
        private const string interfaceScriptName = "NewInterfaceScript.cs";

        // エディタ上の表示させる項目の名前
        private const string menuRoot = "Assets/Create/Add New Script/";

        // エディタに表示される項目の場所と表示名を設定する
        [MenuItem(menuRoot + "Interface")]
        private static void CreateInterfaceScript() => CreateScriptFile(interfaceTemplateFileName, interfaceScriptName);

        /// <summary>
        /// テンプレートファイルを元に新しいスクリプトを作成する
        /// </summary>
        /// <param name="templateFileName">元にするファイル名</param>
        /// <param name="newScriptName">作成するスクリプト名</param>
        private static void CreateScriptFile(string templateFileName, string newScriptName)
        {
            // Path.Combineに関して、第一引き数と第二引き数を書くと結合される Combine("A","B") => "A/B" スラッシュは書いても書かなくてもいい
            // 第三引き数を書くと絶対パスになるらしく、第一、第二引き数が無視され、第三引き数の確定パスしか使われなくなる
            ProjectWindowUtil.CreateScriptAssetFromTemplateFile(Path.Combine(templateFilePath, $"{templateDirectoryPath}/{templateFileName}"), newScriptName);
        }
    }
}
```
コードの実装はこれだけで、あとはテンプレートのtxtを用意します。
InterfaceTemplate.txtの中身
```
// Interface Template

#ROOTNAMESPACEBEGIN#
public interface #SCRIPTNAME#
{
    void SampleMethod();
}
#ROOTNAMESPACEEND#
```

この部分ですがUnity既定の予約文字というものらしく、
Unityでこのtxtを利用できるように変換してくれる物らしいです。
正直この辺りがあまり分かってないです。

・#ROOTNAMESPACEBEGIN#と#ROOTNAMESPACEEND#

ただの操作ミスでした。
~~これでクラスを囲わないと今回の方法でスクリプトを作成した時にInterfaceTemplate.txtを毎回開くという事があったので囲んだ方が良いです。~~


~~namespaceに関するとかあったけど...?~~
AssemblyDifinitionで名前空間を指定した時に置換するらしいです！


・#SCRIPTNAME#
この部分にはクラス名が入ります。
例えばですが、I#SCRIPTNAME#とするクラスの初めにIがつくようになります。
ただ、VisualStudioのコードだけにIが反映されてUnity上では反映されないので。
Unity上でISampleという名前にするとIISampleといった名前になるので気をつけてください。

・その他
本当はコメント部分を消してもいいかなと思っていますが、コメントを消すと空白の改行が追加されてしまうのが嫌でコメントを入れてます。解決方法があれば有識者の方教えてください！

# 利用手順
右クリックもしくは＋ボタンをクリックして、クリエイトメニューを開くと下側の項目に`Add New Script`という項目が追加されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/70a6b8c6-86d9-011a-6612-50c453711dab.png)

クリックしてみるとInterfaceという項目が更に出てくるのでクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/d1fa02c3-d81c-d1e1-1b8a-4bc0e473b612.png)

クリックするとNewInterfaceScriptというスクリプトが作成されるので名前を変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/25b2c143-a581-0629-8b97-c3fbec49a475.png)
スクリプトの作成先ですが、MonoBehaviourスクリプトと同じように作成されます。
（ファイルを選択してればファイル内に作成。何も選択していなければAssets内に作成）

作成したスクリプトを開くと初めからinterfaceクラスが作成されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/158d3855-4c6b-8107-9518-11e07282a550.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/9666ffe4-150d-0cb3-4166-1a42d5fc97f8.png)

書き直しをしなくてもいいからとても便利。
ステートが増えるステートマシンとも相性良さそう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3588406/96d9f5b8-cf04-5d1f-ff7c-d10bc0afbdf4.png)