Unity(二十):创建自定义脚本模板

本文介绍了一个Unity编辑器扩展脚本,该脚本允许用户批量创建带有模板内容的自定义脚本。支持单选或多选文件夹进行脚本创建,并提供了一个图形界面供用户输入脚本名称。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

编辑器内部自定义脚本存储位置展示

在这里插入图片描述

创建自己的自定义脚本

在这里插入图片描述

using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEditor.ProjectWindowCallback;
using UnityEngine;

internal class CustomUnityEditor : EditorWindow
{
    private static EditorWindow _window;
    private static List<Dictionary<string, string>> _paths;

    [MenuItem("Assets/Create/自定义脚本(多选)", false, 0)]
    private static void CreateCustomScripts()
    {
        _paths = GetSelectedDirPath();
        _window = GetWindow<CustomUnityEditor>("创建脚本(多选)");
        _window.Show();
    }

    [MenuItem("Assets/Create/自定义脚本(单选)", false, 1)]
    private static void CreateCustomScript()
    {
        _paths = new List<Dictionary<string, string>>();
        var paths = GetSelectedDirPath();
        if (paths.Count != 0)
        {
            _paths.Add(paths[paths.Count - 1]);
            CreateScriptFile();
        }
        else
            EditorUtility.DisplayDialog("提示", "请选择文件夹", "确定");
    }

    // 获取文件夹路径
    private static List<Dictionary<string, string>> GetSelectedDirPath()
    {
        // Object[] GetFiltered(Type type, SelectionMode mode)
        // type ---> 只会检索此类型的对象
        // mode ---> SelectionMode.Assets 仅返回 Asset 目录中的资产对象
        var selections =
            Selection.GetFiltered(typeof(Object), SelectionMode.Assets); // Object ---> UnityEngine.Object

        // 路径、文件名称 集合
        return (from obj in selections
            let path = AssetDatabase.GetAssetPath(obj)
            where Directory.Exists(path)
            select new Dictionary<string, string>
            {
                { "name", "NewScript" },
                { "path", AssetDatabase.GetAssetPath(obj) }
            }).ToList();
    }

    // 创建文件
    private static void CreateScriptFile()
    {
        foreach (var pathInfo in _paths.Where(pathInfo => pathInfo["name"] != ""))
        {
            const int instanceId = 0;
            var endAction = CreateInstance<NameByEnterOrUnfocus>();
            var pathName = $"{pathInfo["path"]}/{pathInfo["name"]}.cs";
            const string resourceFile = "Assets/Editor/ScriptTemplates/ScriptTemplate.cs.txt";

#if false
                * 参数1:instanceId       已编辑资源的实例 ID。
                * 参数2:endAction        监听编辑名称的类的实例化
                * 参数3:pathName         创建的文件路径(包括文件名)
                * 参数4:icon             图标  
                * 参数5:resourceFile     模板路径

                endAction 直接使用 new NameByEnterOrUnfocus() 出现以下警告:
                    NameByEnterOrUnfocus must be instantiated using the ScriptableObject.CreateInstance method instead of new NameByEnterOrUnfocus.
                    必须使用ScriptableObject实例化NameByEnterOrUnfocus。CreateInstance方法,而不是新的NameByEnterOrUnfocus。
#endif
            ProjectWindowUtil.StartNameEditingIfProjectWindowExists(instanceId, endAction, pathName, null,
                resourceFile);
        }
    }

    private void OnGUI()
    {
        GUILayout.Label("⚠ 不填写文件名称不会创建脚本", new GUIStyle { normal = { textColor = Color.red } });

        foreach (var pathInfo in _paths)
            pathInfo["name"] = EditorGUILayout.TextField(pathInfo["path"], pathInfo["name"]);

        if (GUILayout.Button("确定"))
        {
            CreateScriptFile();
            _window.Close();
        }
    }
}

internal class NameByEnterOrUnfocus : EndNameEditAction
{
    /// <summary>
    /// 当用户通过按下 Enter 键或失去键盘输入焦点接受编辑后的名称时,Unity 调用此函数
    /// </summary>
    /// <param name="instanceId">已编辑资源的实例 ID。</param>
    /// <param name="pathName">资源的路径。</param>
    /// <param name="resourceFile">传递给ProjectWindowUtil.StartNameEditingIfProjectWindowExists的资源文件字符串参数</param>
    public override void Action(int instanceId, string pathName, string resourceFile)
    {
        var obj = CreateScript(pathName, resourceFile);
        // 创建并展示
        ProjectWindowUtil.ShowCreatedAsset(obj);
    }

    private static Object CreateScript(string pathName, string resourceFile)
    {
        // 读取模板文件内容
        var streamReader = new StreamReader(resourceFile);
        var templateText = streamReader.ReadToEnd();
        streamReader.Close();

        // 获取创建的脚本文件名称
        var fileName = Path.GetFileNameWithoutExtension(pathName);

        // 正则替换文本内自定义的变量
        var scriptText = Regex.Replace(templateText, "#NAME#", fileName);

        // 写入脚本
        var streamWriter = new StreamWriter(pathName);
        streamWriter.Write(scriptText);
        streamWriter.Close();

        // 在路径导入资源
        AssetDatabase.ImportAsset(pathName);
        // 返回给定路径assetPath类型类型的第一个资源对象
        return AssetDatabase.LoadAssetAtPath(pathName, typeof(Object));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Prosper Lee

您的赏赐将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值