項目中,我們可能定義了代碼框架,很多代碼文件使用的是同樣的模板,每次創建代碼,把相同的代碼敲一遍,或者從其它文件賦值,都是件麻煩的事。
解決這個問題,我們可以自定義模板文件,並添加創建菜單,這樣可以像 MonoBehaviour 一樣方便地創建我們自己的模板格式的代碼文件。
基本思想:
- 創建模板文件,放在 Assets/Editor/ScriptTemplates/ 目錄下,並對模板文本定義替換規則,如類名爲 #NAME# ,方便我們稍後替換。
- 聲明菜單:[MenuItem(“Assets/Create/C# Scripts/MyBehaviour”)]
- 獲取 ProjectWindow 的當前選中的路徑
- 派生 EndNameEditAction,響應新建文件並完成文件命名事件,執行 加載模板,替換類名,保存文件。
- 調用 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()
{
}
}