Unity杂文——自定义创建模板脚本

2023-09-28  本文已影响0人  脸白

原文地址

前言

相信大多数Unity开发人员在创建脚本的时候,经常会修改自从生成的脚本内容,比如去掉继承的MonoBehavior,添加命名空间,或者继承固定的接口、类等。这样重复的工作看似花费不了多少时间,但是如果每次创建都需要修改,还是有点麻烦的,所以如果我们能按照我们自定一的模板脚本去创建脚本就可以了。

问题

笔者在团队开发中发现,每次创建UI的脚本的时候都需要固定修改继承,和添加一些标签等,这些重复性的工作笔者想了想可不可按照自定义的模板创建脚本。笔者发现unity自带的在unity安装目录下创建模板脚本有很大的缺点,只能创建C#脚本,并且只可以自己使用,并不可以上传到项目的库进行团队使用,于是笔者参考网上的一些文章写了下面的解决方案。

解决方法

首先我们在创建一个Editor Default Resources目录,这个目录是提供为编辑器模式使用的资源路径,加载此目录的资源文件代码如下:
EditorGUIUtility.Load(filePath)
加载后通过as转换成需要的类型就可以了
笔者模板文件存放的目录如下:
---Assets
------Editor Default Resources
---------CustomScriptTemplate
------------C# Script-NewNoMonoBehaviourScript.text

模板文件的内容如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace #NAMESPACE#
{
    public class #SCRIPTNAME#
    {
        #region 字段

        

        #endregion
        
        #region 属性

        

        #endregion
        
        #region 方法
        
        
        
        #endregion
    }
}

在选中的目录里创建模板脚本

制作的原理就是通过读取模板文件的内容,然后将内容写入新的脚本中,监听编辑结束后替换新模板中的固定字符串就可以了。
直接上代码:

using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEditor.ProjectWindowCallback;
using UnityEngine;

public static class CreatNewCShapScript
{
        /// <summary>
        /// 创建不继承MonoBehaviour脚本
        /// </summary>
        [MenuItem("Assets/Create/C# Scripts Menu/C# NoMonoBehaviourScript", false,81)]
        public static void CreatNoMonoBehaviourScript()
        {
            //参数为传递给CreateEventCSScriptAsset类action方法的参数
            ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0,
                ScriptableObject.CreateInstance<CreateNewCShapScriptAsset>(),
                GetSelectPathOrFallback() + "/NewNoMonoBehaviourScript.cs", null,
                "CustomScriptTemplate/C# Script-NewNoMonoBehaviourScript.txt");
        }

        /// <summary>
        /// 取得要创建文件的路径
        /// </summary>
        /// <returns></returns>
        public static string GetSelectPathOrFallback()
        {
            string path = "Assets";
            //遍历选中的资源以获得路径
            //Selection.GetFiltered是过滤选择文件或文件夹下的物体,assets表示只返回选择对象本身
            foreach (UnityEngine.Object obj in Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.Assets))
            {
                path = AssetDatabase.GetAssetPath(obj);
                if (!string.IsNullOrEmpty(path) && File.Exists(path))
                {
                    path = Path.GetDirectoryName(path);
                    break;
                }
            }
            return path;
        }

        /// <summary>
        /// 创建脚本文件的委托类
        /// </summary>
        class CreateNewCShapScriptAsset : EndNameEditAction
        {
            public override void Action(int instanceId, string pathName, string resourceFile)
            {
                UnityEngine.Object obj = CreateScriptAssetFromTemplate(pathName, resourceFile);                         //创建资源
                ProjectWindowUtil.ShowCreatedAsset(obj);                                                                //高亮显示资源
            }
            
            internal static UnityEngine.Object CreateScriptAssetFromTemplate(string pathName, string resourceFile)
            {
                string fullPath = Path.GetFullPath(pathName);                                                           //获取要创建资源的绝对路径
                string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(pathName);                           //获取文件名,不含扩展名
                var textAsset = EditorGUIUtility.Load(resourceFile) as TextAsset;
                string resourceFileText = textAsset.text;
                resourceFileText = Regex.Replace(resourceFileText, "#NAMESPACE#",
                    CompilationPipeline.GetAssemblyRootNamespaceFromScriptPath(pathName));
                resourceFileText = Regex.Replace(resourceFileText, "#SCRIPTNAME#", fileNameWithoutExtension);              //将模板类中的类名替换成你创建的文件名
                bool encoderShouldEmitUTF8Identifier = true;                                                            //参数指定是否提供 Unicode 字节顺序标记
                bool throwOnInvalidBytes = false;                                                                       //是否在检测到无效的编码时引发异常
                UTF8Encoding encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier, throwOnInvalidBytes);
                bool append = false;
                StreamWriter streamWriter = new StreamWriter(fullPath, append, encoding);                               //写入文件
                streamWriter.Write(resourceFileText);
                streamWriter.Close();
                AssetDatabase.ImportAsset(pathName);                                                                    //刷新资源管理器
                AssetDatabase.Refresh();
                return AssetDatabase.LoadAssetAtPath(pathName, typeof(UnityEngine.Object));
            }
        }
}

此代码有一个比较重要的一点就是获取文件所在的程序集的命名空间名字,因为要自动添加命名空间,最后找到了对应的API,通过CompilationPipeline.GetAssemblyRootNamespaceFromScriptPath(pathName)获取地址路径下的命名空间名字,然后动态替换就可以了。

上一篇下一篇

猜你喜欢

热点阅读