先创建一个空文件夹 ![[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]]