项目中,我们可能定义了代码框架,很多代码文件使用的是同样的模板,每次创建代码,把相同的代码敲一遍,或者从其它文件赋值,都是件麻烦的事。
解决这个问题,我们可以自定义模板文件,并添加创建菜单,这样可以像 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()
{
}
}