拓展编辑器 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()
	{
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章