利用UnityEditor实现自己的代码生成器

2024-03-15 14:58

本文主要是介绍利用UnityEditor实现自己的代码生成器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在写了不少代码之后,才发现以前写的很多代码都是重复性的,虽然这样的重复劳动让程序员形成了自己的代码风格,但一直这样下去并不是十分明智的方式。

-----------------------------------------------------写在前面

本文将利用unity的编辑器扩展功能,结合开源的Rotorz列表生成器,实现一个简单但有意义的代码模板生成。其中生成时使用的模板来自于本人平时的编程习惯,如果需要使用这个脚本,可以修改前面定义的字符串模板便可。

使用方式:

[第一步:定义名称]

在hierarchy面板中定义好相关控件的名称,本文仅实现了image,text,toggle,button,slider,inputfield这几个常用控件的代码生成,根据自己的编程模式可以自行扩展,以减少不必要的重复劳动,而把精力放在实现具体的业务逻辑上。

(图一)

[第二步:记录控件]

一种是手动将这些控件拖入到编辑窗口中,这样比较慢,于是本文实现了快速记录指定可交互控件的方式。由于image和文字并不一定要在脚本中获取到并进行设置信息,所以可以区别于其他控件。

如图二所示窗口的左边是控件输入框

[第三步:复制代码]

利用类内写好的代码模板,已经可以生成出指定的c#代码了,如图二所示,点击其中的复制代码,就已经将生成的代码拷贝成功,只需要在指定的脚本中去黏贴就好了。此时并没有实现直接将生成的代码写入到指定的脚本文件中。

[第四步:定向生成]

在目标对象框中拖入NewBehaviourScript的GameObject对象,点击加载脚本,就可以快速将其身上的脚本读取出来。此时,将该脚本打钩,点击保存到脚本,相关的数据就成功写入到指定的脚本文件中了,如果图三所示。但目前还需要用编辑器打开一下才能看到指定的脚本。此时正好可以做适当的微调。

(图二)


(图三)

[第五步:连接到UI]

由于生成了代码,但由于还需要将控件在Inspector面板中进行绑定,于是本文也利用反射等知识将对象快速绑定到指定的位置,如果图四所示。到此就已经完成了对这个编辑器窗口的代码生成功能的使用。想想如果去写这么多行代码至少需要三分钟,这样自己生成再绑定好,最多也就一份钟。把节约的时候用来考虑功能的具体实现多好。

(图四)


关键点说明:

[问题一:字符串生成中]

本来想就用string.Format();就可以实现将指定的名称插入到指定的字符串中,但由于方法体中也有{}这样的符号,直接报错了,于是改成了Replace,稍微有点乱的地方:

 private string GetCodeStr(){string str = "";#region 记录全局变量TraverseGraphic((gra) =>{if (gra is Image){str += string.Format(imgFormat, gra.name);}else if (gra is Text){str += string.Format(txtFormat, gra.name);}else if (gra is RawImage){str += string.Format(rawimgFormat, gra.name);}});TraverseSelectable((sele) =>{if (sele is Button){str += string.Format(btnFormat, sele.name);}else if (sele is Toggle){str += string.Format(togFormat, sele.name);}else if (sele is Slider){str += string.Format(slidFormat, sele.name);str += string.Format(sliderDataFormat, sele.name);}else if (sele is InputField){str += string.Format(inptFormat, sele.name);str += string.Format(inputDataFormat, sele.name);}});#endregion#region 记录事件注册str += "\tprivate void Awake()\n\t{\n";TraverseSelectable((sele) =>{if (sele is Button){str += string.Format(onClickFormat, sele.name);}else if (sele is Toggle || sele is Slider || sele is InputField){str += string.Format(onValueChangeFormat, sele.name);}});str += "\t}\n";#endregion#region 记录方法TraverseSelectable((sele) =>{if (sele is Button){str += btnFuncFormat.Replace("{0}", sele.name);}else if (sele is Toggle){str += togFuncFormat.Replace("{0}", sele.name);}else if (sele is Slider){str += sliderFuncFormat.Replace("{0}", sele.name);}else if (sele is InputField){str += inputFuncFormat.Replace("{0}", sele.name);}});#endregionreturn str;}

[问题二:私有字段的赋值]

本来以为反射对私有字段操作无解,没想到是我研究的够深,反射原来这么强大,参考高手的博客=》

C#反射:让私有成员无所遁形 http://www.cnblogs.com/zuozuo/archive/2011/09/29/2195309.html

type.InvokeMember("m_" + sele.name,
                                BindingFlags.SetField |
                                BindingFlags.Instance |
                                BindingFlags.NonPublic,
                                null, Selected[i], new object[] { sele }, null, null, null);

[问题三:回调加递归调用实现遍历]

一开始找控件时,本来就使用了个简单的foreach(Transform in transform),但这样没有找到子层级的对象,于是就用了下面这个回调加递归进行遍历的方法。

    public static void Recursive(Transform parent, UnityAction<Transform> Func){Func(parent);if (parent.childCount >= 0){for (int i = 0; i < parent.childCount; i++){Transform child = parent.GetChild(i);Recursive(child, Func);}}}


程序源码下载:下面这个上传到github上的程序源码,欢迎使用和指正

https://github.com/zouhunter/CodeGen_ugui

这篇关于利用UnityEditor实现自己的代码生成器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/812348

相关文章

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM