Unity 编辑器-创建模板脚本,并自动绑定属性,添加点击事件

2023-11-17

当使用框架开发时,Prefab挂载的很多脚本都有固定的格式。从Unity的基础模板创建cs文件,再修改到应有的模板,会浪费一些时间。尤其是有大量的不同界面时,每个都改一遍,浪费时间不说,还有可能遗漏或错改。写个脚本创建指定的模板代替C#基础模板。

注:当前脚本使用的NGUI,使用UGUI时替换对应的Component即可

代码
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;

public class MediatorScriptCreator
{
    private const string MenuItemText1 = "Assets/Create/模板脚本/创建Mediator模板脚本";
    private const string MenuItemText3 = "Assets/Create/模板脚本/添加Mediator模板脚本";
    [MenuItem(MenuItemText1, false, 25)]
    public static void CreateScript()
    {
        CreateScript(false);
    }
   
    
    [MenuItem(MenuItemText3, false, 25)]
    public static void AddScript()
    {
        AddComp();
    }
    
    private static List<GameObject> _nodeList;
    private static List<UISprite> _imgList;
    private static List<UIButton> _btnList;
    private static List<UILabel> _labelList;
    private static List<UISlider> _sliderList;

    private static void CreateScript(bool isPartial)
    {

        var assetPath = AssetDatabase.GetAssetPath(Selection.activeObject);
        var directoryPath = System.IO.Path.GetDirectoryName(assetPath);
        var folderName = System.IO.Path.GetFileName(directoryPath);
        var folderPath = $"Assets/Game/GameLogic/{folderName}";
        if (!Directory.Exists(folderPath))
        {
            if (directoryPath != null) Directory.CreateDirectory(folderPath);
        }

        var scriptPath = $"{folderPath}/{Selection.activeObject.name}Mediator.cs";
        if (File.Exists(scriptPath))
        {
            Debug.LogError($"The script \"{scriptPath}\" already exists.");
            return;
        }

        var myPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
        // 获取 Prefab 的所有子对象
        GetNodeData(myPrefab);

        var txt = $@"using UnityEngine;
namespace PD
{{
    public {(isPartial ? "partial" : "")} class {Selection.activeObject.name}Mediator : NGuiFormMasterLogic
    {{
        public override string FacadeName
        {{
            get {{ return HomeFacade.Name; }}//TODO:修改FacadeName
        }}

        public new const string NAME = {$"\"{Selection.activeObject.name}Mediator\""};

        public override void OnConstruct(object userData)
        {{
            base.OnConstruct(userData);
            MediatorName = NAME;
        }}
";
        var txtEnd = $@"
    }}
}}";
        for (var i = 0; i < _nodeList.Count; i++)
        {
            var name = _nodeList[i].name[2..];
            name = name[..1].ToUpper() + name[1..];
            var str = $@"
        [SerializeField] private GameObject {name};
";
            txt += str;
        }

        for (var i = 0; i < _imgList.Count; i++)
        {
            var name = _imgList[i].name[2..];
            name = name[..1].ToUpper() + name[1..];
            var str = $@"
        [SerializeField] private UISprite {name};
";
            txt += str;
        }

        for (var i = 0; i < _labelList.Count; i++)
        {
            var name = _labelList[i].name[2..];
            name = name[..1].ToUpper() + name[1..];
            var str = $@"
        [SerializeField] private UILabel {name};
";
            txt += str;
        }

        for (var i = 0; i < _btnList.Count; i++)
        {
            var name = _btnList[i].name[2..];
            name = name[..1].ToUpper() + name[1..];
            var str = $@"
        [SerializeField] private UIButton {name};
";
            txt += str;
        }

        for (var i = 0; i < _sliderList.Count; i++)
        {
            var name = _sliderList[i].name[2..];
            name = name[..1].ToUpper() + name[1..];
            var str = $@"
        [SerializeField] private UISlider {name};
";
            txt += str;
        }

        for (var i = 0; i < _btnList.Count; i++)
        {
            var name = _btnList[i].name[2..];
            name = name[..1].ToUpper() + name[1..];
            var str = $@"


        public void On{name}Click()
        {{
           
        }}

";
            txt += str;
        }


        txt += txtEnd;
        EditorPrefs.SetString("creatorPath", assetPath);
        EditorPrefs.SetString("creatorName", myPrefab.name);
        EditorPrefs.SetString("creatorScriptPath", scriptPath);
        File.WriteAllText(scriptPath, txt);
        AssetDatabase.Refresh();
    }

    public static void AddComp()
    {
        var scriptName = EditorPrefs.GetString("creatorName");
        string[] guids = AssetDatabase.FindAssets(scriptName);

        if (guids.Length > 0)
        {
            var assetPath = EditorPrefs.GetString("creatorPath");
            string path = AssetDatabase.GUIDToAssetPath(guids[0]);
            MonoScript monoScript = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
            System.Type type = monoScript.GetClass();
            var prefab =
                GameObject.Instantiate(
                    AssetDatabase
                        .LoadMainAssetAtPath(
                            assetPath)) as GameObject; // PrefabUtility.LoadPrefabContents(assetPath);//
            var component = prefab.AddComponent(type);
            // 获取所有字段
            var fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
            var list = prefab.GetComponentsInChildren<Transform>(true).Where(a => a.name.StartsWith("m_")).ToList();

            foreach (FieldInfo field in fields)
            {
                // 判断字段是否被序列化
                var attributes = field.GetCustomAttributes(typeof(SerializeField), false);
                if (attributes.Length > 0)
                {
                    var temp = field.Name + "";
                    var name = temp[..1].ToLower() + temp[1..];
                    var go = list.FirstOrDefault(a => a.name == $"m_{name}");
                    if (go != null)
                    {
                        list.Remove(go);
                        var btn = go.GetComponent<UIButton>();
                        var slider = go.GetComponent<UISlider>();
                        var img = go.GetComponent<UISprite>();
                        var txt = go.GetComponent<UILabel>();
                        if (btn != null)
                        {
                            var str = $"On{field.Name}Click";
                            Debug.Log(str);
                            var delegateFunc1 = new EventDelegate(component as MonoBehaviour, str);
                            btn.onClick.Add(delegateFunc1);
                            field.SetValue(component, btn);
                        }
                        else if (slider != null)
                        {
                            field.SetValue(component, slider);
                        }
                        else if (img != null)
                        {
                            field.SetValue(component, img);
                        }
                        else if (txt != null)
                        {
                            field.SetValue(component, txt);
                        }
                        else
                        {
                            field.SetValue(component, go.gameObject);
                        }
                    }
                }
            }

            // GetNodeData(prefab);
            // PrefabUtility.SaveAsPrefabAssetAndConnect(prefab, assetPath);
            PrefabUtility.SaveAsPrefabAssetAndConnect(prefab, assetPath, InteractionMode.AutomatedAction);
            Object.DestroyImmediate(prefab);
            AssetDatabase.Refresh();
        }
        else
        {
            Debug.LogError($"请先生成脚本");
        }
    }
    [MenuItem(MenuItemText1, true)]
    public static bool CreatorNormal()
    {
        if (!Selection.activeObject) return false;
        var prefabAssetType = PrefabUtility.GetPrefabAssetType(Selection.activeObject);
        return prefabAssetType != PrefabAssetType.NotAPrefab;

    }
    
    [MenuItem(MenuItemText3, true)]
    public static bool AddScript1()
    {
        if (!Selection.activeObject) return false;
        var prefabAssetType = PrefabUtility.GetPrefabAssetType(Selection.activeObject);
        return prefabAssetType != PrefabAssetType.NotAPrefab;

    }
    private static void GetNodeData(GameObject prefab)
    {
        Transform[] nodes = prefab.GetComponentsInChildren<Transform>(true);
        _nodeList = new List<GameObject>();
        _imgList = new List<UISprite>();
        _labelList = new List<UILabel>();
        _btnList = new List<UIButton>();
        _sliderList = new List<UISlider>();                                                                                              
        // 遍历所有子对象
        foreach (var node in nodes)
        {
            if (!node.gameObject.name.StartsWith("m_")) continue;
            var btn = node.GetComponent<UIButton>();
            var img = node.GetComponent<UISprite>();
            var label = node.GetComponent<UILabel>();
            var slider = node.GetComponent<UISlider>();
            if (btn != null)
            {
                _btnList.Add(btn);
            }
            else if (slider != null)
            {
                _sliderList.Add(slider);
            }
            else if (img != null)
            {
                _imgList.Add(img);
            }
            else if (label != null)
            {
                _labelList.Add(label);
            }
            else
            {
                _nodeList.Add(node.gameObject);
            }
        }
    }
}



使用方法
知识点

1.字符串使用@前缀,可以不使用\n换行。和$搭配使用时,字符串中如果有 { 需要用 {{ 两个大括号表示,第一个为转义。 字符串中有 ” 时,需要使用反斜杠 " 转义
2.判断物体是不是Prefab,PrefabUtility.GetPrefabAssetType(Selection.activeObject) != PrefabAssetType.NotAPrefab;
3.[MenuItem(MenuItemText2, true)] 第二个参数 bool值表示是否显示本扩展方法
4.获取指定脚本所有的Pulbic[SerializeField]的属性: type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity 编辑器-创建模板脚本,并自动绑定属性,添加点击事件 的相关文章

  • Unity与Android的Back键冲突解决

    Unity与Android的Back键冲突解决 上一篇的最后留下了两个问题 Unity视图下横屏闪退 Unity视图下Android无法响应back返回上一activity 对于第一个问题 应该是Unity横屏下视图的某些设置跟Androi
  • GooglePlay提审警告(com.google.android.gms:play-services-safetynet:17.0.0)

    1 Goole在今年6月份出的新政策 不在使用safetynet 而使用Play Integrity API 2 项目本身没有使用过safetynet 3 使用了firebase 查阅资料 解决方案如下 implementation pla
  • Unity学习笔记(一)—— 基础知识

    一 基础知识 1 开发团队组成 2 unity特点 图形界面 所见即所得 入门简单 支持C 比OC C 更友好 js 国内外资源丰富 因为使用的人多 跨平台性好 PC端 移动端等 对VR AR的支持最完善 3 成功案例 游戏 炉石传说 神庙
  • unity工程崩溃资源找回

    1 Unity死机未保存场景 当你在Unity中编辑场景 突然死机时 可以在项目文件目录中找到Temp文件夹 双击文件夹 找到 Backupscenes文件夹 把后缀为 backup的文件后缀改为 unity 然后拖进Unity的Proje
  • unity3d大型互动照片墙

    1 本次应客户需求 制作一个大型照片墙互动 输出分辨率为9600 4320 注 unity3d官方推荐最大分辨率为8192 3686 4 经过现场长达24小时暴力测试中途未发生问题 姑且判定可以达到正常标准 废话不多说 先上效果 unity
  • unity: C#的Action Event Delegate的异同

    目录 一 Action 二 Event 三 Action和Event区别 四 Delegate 总结 Action Event Delegate的异同 前言 Action Event和Delegate都是C 语言中的重要概念 分别用于管理函
  • VLC for unity 插件如何使用

    VLC for unity 插件如何使用 先去下载一个VLC播放器 安装完成后 然后导入插件链接https download csdn net my 这个插件我的另一个上传资源里有 或者到商店去下载 这个插件链接下载完是一个txt文档 里面
  • 【Unity】按Esc进入操作菜单

    本文章是基于如下视频的自我总结 https www youtube com watch v JivuXdrIHK0 步骤如下 1 在Canvas 界面添加一个Panel Panel中添加一个按钮 调整按钮的大小为合适大小 调整字体的大小为合
  • Unity保存图片到相册

    Unity保存图片到Android相册 Java 纯文本查看 复制代码 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
  • 必杀VI、VIM编辑器命令

    题记 VI和VIM有非常多的命令 在此分部分展示一下 第一部分 一 移动光标类 一般模式 光标移动 复制粘贴 查找替换 上下移动 h lt 光标向左移动一个字符 j 向上箭头 光标向上移动一个字符 k 向下箭头 光标向下移动一个字符 l 向
  • 修改sublime配置让其显示文件编码格式

    1 下载sublime并安装 2 点击菜单栏Preferences 然后在Preferences里面点击Setting 3 然后在跳出来的窗口添加 show enconding true 4 随便打开一个文件就可以在底部查看文件编码格式
  • unity3d image组件不显示

    需要将UI组件放到画布下面
  • 【原神游戏开发日志1】缘起

    原神游戏开发日志1 缘起 版权声明 本文为 优梦创客 原创文章 您可以自由转载 但必须加入完整的版权声明 文章内容不得删减 修改 演绎 相关学习资源见文末 大家好 最近看到原神在TGA上频频获奖 作为一个14年经验的游戏开发行业的老兵 我就
  • vscode调试mit6s081Lab

    环境 mit6 s081的实验环境 gdb multiarch 用于gdb调试 vscode调试实质上就是提供个图形化页面 底层还是这个 安装 gdb multiarch sudo apt get install gdb multiarch
  • mixamo根动画导入UE5问题:滑铲

    最近想做一个跑酷游戏 从mixamo下载滑铲动作后 出了很多动画的问题 花了两周时间 终于是把所有的问题基本上都解决了 常见问题 1 动画序列 人物不移动 2 动画序列 人物移动朝向错误 3 蒙太奇 人物移动后会被拉回 4 蒙太奇 动画移动
  • Linux_vi/vim编辑器

    3 VI 与 VIM 3 1概述 vi编辑器 是Linux和Unix上最基本的文本编辑器 工作在字符模式下 由于不需要图形界面 vi是效率很高的文本编辑器 vim是 vi的增强版 比vi更容易使用 vi的命令几乎全部都可以在vim上使用 3
  • fckeditor编辑器改造示例:增加PRE,CODE控件

    查看专栏目录 Network 灰鸽宝典专栏主要关注服务器的配置 前后端开发环境的配置 编辑器的配置 网络服务的配置 网络命令的应用与配置 windows常见问题的解决等 文章目录 修改方法 1 修改fckconfig js文件 2 修改FC
  • 【Unity】运行时创建曲线(贝塞尔的运用)

    Unity 运行时创建线 贝塞尔的运用 1 实现的目标 在运行状态下创建一条可以使用贝塞尔方法实时编辑的网格曲线 2 原理介绍 2 1 曲线的创建 unity建立网格曲线可以参考 Unity程序化网格体 的实现方法 主要分为顶点 三角面 U
  • Unity学习笔记

    一 旋转欧拉角 四元数 Vector3 rotate new Vector3 0 30 0 Quaternion quaternion Quaternion identity quaternion Quaternion Euler rota
  • 游戏开发中常见系统梳理之背包系统的实现一

    游戏中几乎都存在大大小小的背包系统 接下来我将讲述背包系统具体是如何实现的 完整源码 以下是使用unity NGUI实现 使用txt配置的方法 后续更新UGUI Json实现的背包系统敬请期待 背包中的物品我们常常将其制作成预设体 通过改变

随机推荐

  • ruoyi框架时间范围range增加今日,近7日,近30日时间选择

    原先layui时间控件是不支持今日 近7日 近30日选择的 网上的解决方法是直接在引用的js中修改代码 这是一种方法 但是对于不能修改源代码的童鞋来说是不行的 所以一下解决方法诞生了 直接添加这三个按钮并和时间控件 laydate 有友好的
  • 【数字图像处理】图像形态学算法C语言实现(图像卷积,膨胀,腐蚀,开运算,闭运算,顶帽,黑帽,雕版,锐化)

    文章目录 一 图像卷积 1 图像卷积 2 数字信号处理中的卷积 3 数字图像处理中的卷积 二 图像卷积实现各种形态学运算 腐蚀 膨胀 形态学梯度 开运算 闭运算 顶帽 黑帽 雕版 锐化 li conv c main c 三 效果展示 原图
  • SPI转can芯片CSM300详解以及Linux驱动移植调试笔记

    更多嵌入式Linux干货 请关注 一口Linux 一 CSM300概述 CSM300 A 系列是一款可以支持 SPI UART 接口的CAN模块 1 简介 CSM300 A 系列隔离 SPI UART 转 CAN 模块是集成微处理器 CAN
  • Linux常用命令合集(二)

    file命令 该命令用于判断接在file命令后的文件的基本数据 因为在Linux下文件的类型并不是以后缀为分的 所以这个命令对我们来说就很有用了 gt file rumenz txt 查看rumenz txt的文件类型 rumenz txt
  • “泰迪杯”挑战赛 - 通过聚类方法对航空客运的客户进行细分

    目 录 挖掘目标 分析方法与过程 2 1 总体流程 2 2 具体步骤 步骤一 数据预处理 步骤二 群体聚类 步骤三 行为特征聚类 2 3 结果分析 第一类 第二类 第三类 结论 参考文献 1 挖掘目标 本次建模目标是在航空公司的海量会员数据
  • 分享几个好用的WP插件,让你的网站牛逼起来

    1 WP Rocket WPRocket缓存插件是目前最高效灵活的WordPress静态缓存插件 它可以优化你的JSCSS文件结构 减少多次请求 达到优化速度的目的 它还集成了图像延迟加载 对于想要最极致加速的用户来说是一个不错的选择 通过
  • Type Script 之 类型

    Type Script 中的类型有很多 常见的类型有 undefined null boolean number bigint string symbol void object unknown never any 其中基本类型有 void
  • java内存模型 堆栈_Java内存模型分析

    一 Java内存的构成 先上一个官方java document里的图 由上图可知 整块区域分为Young Generation Tenured Generation Permanent Generation 详细解释一下Young区 You
  • Laravel 表单验证器的常用的2种使用方法

    1 使用控制器的 validate 方法进行参数验证 场景一 前后端未分离 保存一篇新的博客文章 param Request request return Response public function store Request req
  • 【csv】csv文件存储上数据精度丢失问题

    最近发现较长的id信息在csv文件中会发生精度丢失 当然python直接处理数据是没问题的 只是csv显示有问题 case1 通常在Excel中输入数值时 如果超过11位 12位及以上 Excel就会用科学计数法显示该数值 如 123456
  • 让macOS支持读写NTFS格式的移动硬盘

    第一步 获知磁盘的名称 两种方法可以知道磁盘名称 第一种 当插入移动硬盘时 桌面上会出现移动硬盘的图标还有名称 第二种 打开终端 输入diskutil list 即可知道磁盘名称 由图中可知我的移动硬盘名称是 备份 第二步 打开终端 按照以
  • 操作系统的逻辑结构

    2 1 操作系统的逻辑结构 逻辑结构 OS的设计和实现思路 逻辑结构的种类 1 整体结构 2 层次式结构 3 微内核结构 客户 服务器结构 Client Server 操作系统作为一个大型软件 它的设计逻辑实现的思路 我们叫做操作系统的逻辑
  • 壁纸网站研究:强大到没朋友的壁纸网站整理(动漫/二次元/宅男/风景/真人)

    1 wallhaven 域名 https wallhaven cc 介绍 一个强大的壁纸网站 包含人物 动漫 风景 同时有一些老司机内容 需要选择NSFW 但需要登录才能观看 隐藏功能 但是海外网站 国内网站较慢 有时候打不开 总结 语言
  • 【华为OD机试真题2023B卷 JAVA&JS】内存资源分配

    华为OD2023 B卷 机试题库全覆盖 刷题指南点这里 内存资源分配 知识点贪心编程基础 时间限制 1s 空间限制 32MB 限定语言 不限 题目描述 有一个简易内存池 内存按照大小粒度分类 每个粒度有若干个可用内存资源 用户会进行一系列内
  • Spring 中容器启动分析之refresh方法执行之前

    内容来自 自学星球 欢迎大家来了解我的星球 和星主 也就是我 一起学习 Java 深入 Java 体系中的所有技术 我给自己定的时间是一年 无论结果如何 必定能给星球中的各位带来点东西 想要了解更多 欢迎访问 自学星球 SSM系列源码文章及
  • JavaScript随机生成颜色

    function getRandomColor const letters 0123456789ABCDEF let color for let i 0 i lt 6 i color letters Math floor Math rand
  • IPv4数据报的分段与重组

    文章摘自书籍 深入理解计算机网络 王达 机械工业出版社 IPv4数据报头格式请点击此处 IPv4数据报的封装与解封装请点击此处 IPv4数据报的分段与重组 在网络层中还涉及一个分段的问题 那就是因为不同网络线路上可以传输的数据报大小是有限制
  • QT学习记录(三)通过ui和代码的方式往窗口添加组件

    写在前面 本文是b站教程的https www bilibili com video BV1g4411H78N p 5 vd source a3efe214b8a2ba185e92e79cb6d6321b的笔记 外加自己的一些其他想法 如有侵
  • mnist example for lstm in caffe

    下面给出在caffe中使用lstm的一个例子 其中数据集采用mnist 为了实现mnist数据的序列话 将mnist的每一行看成一帧 每一列则就是该帧的特征矢量 在使用lstm时 一定要注意clip markers 每个序列以0开始 后面接
  • Unity 编辑器-创建模板脚本,并自动绑定属性,添加点击事件

    当使用框架开发时 Prefab挂载的很多脚本都有固定的格式 从Unity的基础模板创建cs文件 再修改到应有的模板 会浪费一些时间 尤其是有大量的不同界面时 每个都改一遍 浪费时间不说 还有可能遗漏或错改 写个脚本创建指定的模板代替C 基础