obsidian/笔记文件/2.笔记/Unity 编辑器扩展精粹_第二章.md
2025-03-26 00:02:56 +08:00

6.9 KiB
Raw Blame History

先创建一个空文件夹

!Pasted image 20230604133331.png

编辑器类,子文件夹

!Pasted image 20230604133359.png

创建代码相关的类

!Pasted image 20230604133508.png

用到的命名空间和归属

!Pasted image 20230604133601.png

跟编辑器文件夹同级创建一个Bind绑定脚本

!Pasted image 20230604133744.png

添加到组件菜单其中会Get获取组件名称这里测试的只是加了MeshRenderer和SpriteRenderer否则都判定为Transform即可

!Pasted image 20240319154216.png

也可以右键添加对应逻辑调用Selection.objects.First接口选中文件队列的第一个添加Bind组件即可

!Pasted image 20240319155900.png

入口

!Pasted image 20240319160009.png

编辑器文件夹,创建一个绑定脚本的信息类

!Pasted image 20230604134125.png

会声明,实体之间的,父子相对路径,组件名,实体名称

!Pasted image 20240319154347.png

创建一个生成代码的模板类

!Pasted image 20230604134307.png

生成的代码有两种: 1、根据实际脚本架构去动态生成 2、固定的样式

所以,需要两个代码模板类

用到的模板类,对应两种类型的代码

!Pasted image 20230604134604.png

命名空间也应该可以自定义,新建一个数据类,用来自定义命名空间

!Pasted image 20230604134717.png

用到的命名空间和业务逻辑: 保存的key是readonly只读的 整一个获取器和设置器,其中获取器设置好,字符串的默认值 三元运算符,判空,如果为空,就将它设置成默认值

再整一个布尔判断接口,判断是否为默认值

!Pasted image 20230604134755.png

先完成固定样式的写入逻辑 脚本名字和所在文件夹是传递进来的如果脚本已存在就return返回就好如果命名空间是默认值就写入中文提示

然后就是写入代码行数了先是命名空间然后是partial类 参考partial分部类和方法 其中\t是Tab退格的意思

!Pasted image 20230604135152.png

然后,是动态生成的写入方法 动态生成的逻辑,代码名字需要在固定样式的名字基础上,加.后缀,在这里是.Designer 传参里有Bind绑定的bindInfos列表容器遍历写入新的脚本文件

!Pasted image 20240319153726.png

其中也使用了Guid.NewGuid函数整出来一个新的guid

!Pasted image 20240319153934.png

测试生成的脚本里面,有这个注释

!Pasted image 20240319154026.png

回到创建脚本的类在GameObject目录下创建一个选项 先是打印log

!Pasted image 20230604150651.png

整一个方法是寻找绑定了Bind脚本的递归 如果存在bind脚本并且不是根节点就构造一个BindInfo往List里加List是引用类型 继续,遍历子节点,然后递归调用 传参有一个三元运算符判断是否为根节点进而判断是否要修改父子path路径传参

!Pasted image 20240319154731.png

整一个静态Bind脚本信息相关的List列表

!Pasted image 20230604151305.png

写一个类,是用来控制,生成代码和预制体位置,还有一个布尔,判断是否要生成预制体; 其中ExecuteInEditMode标签指的是只在编辑器模式下运行; 参考ExecuteInEditMode

!Pasted image 20240319160504.png

也加一个脚本是对应CodeGenerateInfo的面板UI类主要是用来设置相关路径

!Pasted image 20240319161135.png

这是右键入口逻辑

!Pasted image 20240319161446.png

创建空物体,右键点击,选择入口

!Pasted image 20240319161512.png

表现正常

!Pasted image 20240319161529.png

!Pasted image 20240319161539.png

完善创建代码类逻辑; 这个创建逻辑是需要选中某个实体先判断选中实体列表的长度需要大于0然后拿选中实体列表的第一个 创建代码目录结构,如果不存在,就代码创建这个目录; Bind信息列表先clear清理一下然后调用前面写好的搜索绑定的bind脚本调用前面写好的两个代码模版ComponentTemplate和ComponentDesignerTemplate 然后把实体名字写入到编辑器的本地化持久GENERATE_CLASS_NAME AssetDatabase.Refresh刷新数据

!Pasted image 20240319164550.png

!Pasted image 20240319164650.png

加一个方法体,是用来检测编译结果的; DidReloadScripts标签是在脚本发生改动后会调用的函数 特别是在AssetDatabase.Refresh();之后

!Pasted image 20230604151915.png

先拿到前面本地化持久GENERATE_CLASS_NAME的字符串数据

!Pasted image 20230604152026.png

右键,点击选择:

!Pasted image 20230604152220.png

打印正常,可以看到,编译完成的时机,也正常打印了

!Pasted image 20230604152248.png

创建出来的脚本:

!Pasted image 20230604152313.png

继续完善,编译后逻辑 如果字段字符长度为空,就不继续操作,并且删除这个本地化持久,不保留数据影响后面的

!Pasted image 20230604152430.png

否则,继续操作; 获取已加载到这个应用程序域执行上下文的程序集; 拿到程序集中,第一个名字是"Assembly-CSharp"的程序集 从这个程序集中,拿到对应命名空间下的类 如果类为空,提示编译失败 如果不为空就先拿到这个实体然后往这个实体挂载同名脚本然后通过SerializedObject序列化脚本 清空bind信息列表

!Pasted image 20240319164827.png

然后重新搜索和赋值列表; 遍历信息列表对序列化文件中使用FindProperty方法拿到同名的变量进行赋值操作 然后拿到CodeGenerateInfo组件也是使用FindProperty方法获取生成的脚本和预制体路径

!Pasted image 20240319164856.png

调用serialiedScript.ApplyModifiedPropertiesWithoutUndo(); SerializedObject.ApplyModifiedPropertiesWithoutUndo 如果勾选了生成预制体就调用SaveAsPrefabAssetAndConnect接口生成即可 保存修改,然后删除本地化持久,不保留数据影响后面的

!Pasted image 20240319165134.png

再设置好,这个创建代码类,继承自编辑器 然后,添加编辑器入口; 刷新界面,是获取和修改自定义命名空间

!Pasted image 20230604153559.png

保存修改,点击入口

!Pasted image 20230604153723.png

这个是默认命名空间

!Pasted image 20230604153744.png

改一下

!Pasted image 20230604153812.png

创建一个空的子物体

!Pasted image 20240319161821.png

加Bind节点

!Pasted image 20240319161837.png

回到父物体,点击创建

!Pasted image 20240319161903.png

预制体和脚本,生成正常; 组件挂载,正常;

!Pasted image 20240319161943.png

逻辑内容正常

!Pasted image 20240319162043.png

!Pasted image 20240319162100.png