sh1’s diary

プログラミング、読んだ本、資格試験、ゲームとか私を記録するところ

Unity エディタ拡張でスクリプトファイルのテンプレートを作成する

Unity のスクリプトファイルを標準の作り方だと「Create/C# Script」をつかうと思いますが、十分なフォーマットとは言えないですよね。ほかにも

  • 文字コードを OS にあわせたい
  • MonoBehavior を継承しないクラスでいいときがある
  • ときどきは最初から UniRx を using していたい

デフォルトは、Windows だと「Unityのインストールフォルダ\Editor\Data\Resources\ScriptTemplates」を利用します。

などなど、ひとつのテンプレートファイルでは要望を解決できない。

そんなわけで、ケースバイケースで生成するスクリプトファイルの雛形は、いくつかの選択があったほうが望ましそうです。そこで複数のスクリプトファイルを選択・生成するエディタ拡張を作成しました。

f:id:shikaku_sh:20210121190532g:plain:w600
やってみた雰囲気

わりといい感じ。最後に、アセットをパッケージ化して使い回せるようにしておきました。

スクリプトテンプレートを呼び出すエディタ拡張

まず、スクリプトファイルを保存するためのメニューを追加します。

f:id:shikaku_sh:20210121184545p:plain:w600
オリジナルのメニューを追加します

こんな感じで、「Create」メニューの中に Add Script Files というメニューを追加して、3パターンのファイルを選択できるようにしてみました。 パターンファイルは、別に用意しておいてパッケージに含めておけば、各プロジェクトで使い回せる&微調節も可能です。

使い回すことを目的にしているので、サンプルだと名前空間 (Sh1ch.Plugins) を設定しています。名前空間の指定がないと衝突が発生する恐れがあるので。(通常のプラグインは、名前空間を利用します)

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace Sh1ch.Plugins
{
    static internal class MenuItemSettings
    {
        private const string PLUGIN_PATH = "Assets/Plugins/ScriptFilesFromTemplate/";
        private const string NEW_FILENAME = "NewFile.cs";

        private const string MENU_ITEM_ROOT = "Assets/Create/Add Script Files/";

        private const string SimpleScript = "Simple Script";
        private const string MonoBehaviour = "MonoBehaviour";
        private const string MonoBehaviourWithUniRx = "MonoBehaviour (UniRx)";

        [MenuItem(MENU_ITEM_ROOT + SimpleScript)]
        private static void CreateSimpleScript() => CreateScriptFile("SimpleScript.txt", NEW_FILENAME);

        [MenuItem(MENU_ITEM_ROOT + MonoBehaviour)]
        private static void CreateMonoBehaviour() => CreateScriptFile("TemplateMonoBehaviour.txt", NEW_FILENAME);

        [MenuItem(MENU_ITEM_ROOT + MonoBehaviourWithUniRx)]
        private static void CreateMonoBehaviourWithUniRx() => CreateScriptFile("TemplateMonoBehaviourWithUniRx.txt", NEW_FILENAME);

        private static void CreateScriptFile(string templateFileName, string newFileName)
        {
            ProjectWindowUtil.CreateScriptAssetFromTemplateFile(System.IO.Path.Combine(PLUGIN_PATH, $"Templates/{templateFileName}"), newFileName);
        }
    }
}

拡張メソッドとしてのポイントは、ファイル追加を Unity の用意してくれているメソッド ProjectWindowUtil.CreateScriptAssetFromTemplateFile で済ませています。これ便利でテンプレートファイルを読み込んで、スクリプトファイルを追加してくれます。あと、既定の予約文字を使うことで自動的に変換してくれたりします。

  • #SCRIPTNAME#
  • #ROOTNAMESPACEBEGIN#
  • #ROOTNAMESPACEEND#
  • #NOTRIM#

#ROOTNAMESPACEBEGIN##ROOTNAMESPACEEND# はセットで、名前空間を作成します。名前空間のテキストは「Edit>Project Settings>Editor>Root namespace」 を参照しています。

f:id:shikaku_sh:20210126120217p:plain:w600
名前空間の設定

なお、プラグインはデフォルトの Assets\Plugins を利用しました。UniRx, Unity for Github なども同じやり方です。

Priority の設定

MenuItem 属性のパラメーターに Priority を設定することで、右クリックメニューの表示する並び順を変更することができます。

private const int SCRIPT_PRIOPRITY = 30;

[MenuItem(MENU_ITEM_ROOT_SCRIPT + SCRIPT_SIMPLE, priority = SCRIPT_PRIOPRITY)]
private static void CreateScript_SimpleScript() => CreateScriptFile("SimpleScript.txt", NEW_FILENAME);

設定変更しても反映されないことがあり、その際は Unity を再起動すると反映できました。

また、Priority の値は Unity のメニューの表示が変更されることもあって、確定させないほうが無難です。とりあえず、現状だと 30 に設定することで、「C# Script」の上に separator を挟んで表示することができるのでよい感じです。(おそらく、10 以上 priority が離れているため、separator が自動生成される)

テンプレートファイルのサンプル

こんな感じにしました。 #region の追加なんかもオススメです。

チームだと1ファイルのコード量がわからなくなる傾向があるので、region は注意が必要です。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

#ROOTNAMESPACEBEGIN#
    /// <summary>
    /// <see cref="#SCRIPTNAME#"/> is the class that inherits from <seealso cref="MonoBehaviour"/> class.
    /// <para>
    /// <see cref="MonoBehaviour"/> is the base class from which every Unity script derives.
    /// </para>
    /// <see href="https://docs.unity3d.com/ScriptReference/MonoBehaviour.html">Unity Documentation - MonoBehaviour</see>
    /// </summary>
    public class #SCRIPTNAME# : MonoBehaviour
    {
        /// <summary>
        /// <see cref="Start"/> is called on the frame when a script is enabled just before any of the <seealso cref="Update"/> methods are called the first time.
        /// </summary>
        private void Start()
        {
            #NOTRIM#
        }

        /// <summary>
        /// <see cref="Update"/> is called every frame, if the <seealso cref="MonoBehaviour"/> is enabled.
        /// </summary>
        private void Update()
        {
            #NOTRIM#
        }
    }
#ROOTNAMESPACEEND#

Unity Package の作成

メニューから「Assets>Export package」を選択して、プラグインを作成します。この際は、プラグイン以外のファイルは除外するようにします。

f:id:shikaku_sh:20210121185418p:plain
あらかじめファイル選択してからメニューを操作すること

サンプル

参考