拓展編輯器 11 - 自定義腳本模板

項目中,我們可能定義了代碼框架,很多代碼文件使用的是同樣的模板,每次創建代碼,把相同的代碼敲一遍,或者從其它文件賦值,都是件麻煩的事。

解決這個問題,我們可以自定義模板文件,並添加創建菜單,這樣可以像 MonoBehaviour 一樣方便地創建我們自己的模板格式的代碼文件。

基本思想:

  1. 創建模板文件,放在 Assets/Editor/ScriptTemplates/ 目錄下,並對模板文本定義替換規則,如類名爲 #NAME# ,方便我們稍後替換。
  2. 聲明菜單:[MenuItem(“Assets/Create/C# Scripts/MyBehaviour”)]
  3. 獲取 ProjectWindow 的當前選中的路徑
  4. 派生 EndNameEditAction,響應新建文件並完成文件命名事件,執行 加載模板,替換類名,保存文件。
  5. 調用 ProjectWindowUtil.StartNameEditingIfProjectWindowExists 接口,利用派生的 EndNameEditAction 來監聽命名完成。

代碼:

public class ScriptTemplatecs
{
    // 模板文件所在的路徑
    private static string SCRIPT_TEMPLATE = "Assets/Editor/ScriptTemplates/C# Script-MyNewBehaviourScript.cs.txt";

    // 定義創建菜單項
    [MenuItem("Assets/Create/C# MyScript", false, 80)]
    static void CreateMyScript()
    {
        // 獲取當前 project 選擇的路徑
        string locationPath = GetSelectedPathOrFallback();
        ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance<MyScriptCreator>(), locationPath + "/MyNewBehaviour.cs", null, SCRIPT_TEMPLATE);
    }

    // 獲取當前 project 選擇的路徑
    // 遍歷選擇的 UnityEngine.Object,返回對象路徑。Project 下的目錄也是 UnityEngin.Object 對象。
    static string GetSelectedPathOrFallback()
    {
        string path = "Assets";
        foreach(UnityEngine.Object obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets))
        {
            // 對象路徑
            string curPath = AssetDatabase.GetAssetPath(obj);
            if (string.IsNullOrEmpty(curPath) == false && File.Exists(curPath))
            {
                // 返回路徑
                path = Path.GetDirectoryName(curPath);
                break;
            }
        }
        return path;
    }
}

class MyScriptCreator : EndNameEditAction
{
    /// <summary>
    /// 響應命名完成事件
    /// </summary>
    /// <param name="instanceId">完成命名的對象的實體ID(應該是 hierarchy window 有效?)</param>
    /// <param name="pathName">路徑</param>
    /// <param name="resourceFile">資源文件</param>
    public override void Action(int instanceId, string pathName, string resourceFile)
    {
        UnityEngine.Object o = CreateScriptAssetFromTemplate(pathName, resourceFile);
        ProjectWindowUtil.ShowCreatedAsset(o);
    }

    // 創建文件
    internal static UnityEngine.Object CreateScriptAssetFromTemplate(string pathName, string resourceFile)
    {
        // 加載文件
        string fullpath = Path.GetFullPath(pathName);
        StreamReader sr = new StreamReader(resourceFile);
        string text = sr.ReadToEnd();
        sr.Close();

        // 獲取文件名
        string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(pathName);
        // 將類名替換爲文件名
        text = Regex.Replace(text, "#NAME#", fileNameWithoutExtension);
        // 保存文件
        bool encoderShuldEmitUTF8Identifier = false;
        bool throwOnInvalidBytes = false;
        bool append = false;
        UTF8Encoding encoding = new UTF8Encoding(encoderShuldEmitUTF8Identifier, throwOnInvalidBytes);
        StreamWriter sw = new StreamWriter(fullpath, append, encoding);
        sw.Write(text);
        sw.Close();
        // 將資源導入
        AssetDatabase.ImportAsset(pathName);
        // 加載資源
        return AssetDatabase.LoadAssetAtPath(pathName, typeof(UnityEngine.Object));
    }
}

模板文件:

using System.Collections;
using UnityEngine;

public class #NAME# : MonoBehaviour
{
	void MyFunction()
	{
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章