赞
踩
最近一段时间都在搞编辑器,扩展各种功能,如添加Inspector上的Add Component回调功能,Unity Package 一键更新功能, 还有现在的Scene扩展,也算小有心得了,出来总结一下。
比较特殊的类,比如说Editor,EditorWindow,ScriptableObject,AssetPostprocessor等特殊一点的就不说了,网上一抓一大把介绍的,主要讲讲两个重要特性ExecuteInEditMode和InitializeOnLoad。
1、ExecuteInEditMode
// ExecuteInEditMode主要是让MonoBehaviour可以在不运行时,也可以执行各个生命周期的特性 // 可以配合Mono单例使用 // 需要把组件拖到GameObject上才能执行 [ExecuteInEditMode] public class PackageManager : MonoBehaviour { // 其中值得介绍的是OnEnable和OnDisable // 因为改了代码之后会将数据清零,而且不会执行Awake和Start // 但是会在编译前执行OnDisable,编译后会执行OnEnable // 可以用这一个时机,对一些委托的绑定与解绑,或者数据的初始化和销毁 // 当然正常的SetActive也会触发这两个时机 void OnEnable() { } void OnDisable() { } }
2、InitializeOnLoad
// InitializeOnLoad主要是让一个普通类可以在编辑器下初始化
// 个人认为虽然可以用Mono调用单例也可以达到相同效果,不过有些时候并不需要创建一个GameObject
// 所以直接定义一个这么的类就好了
[InitializeOnLoad]
public static class EditorTiming
{
// 构造函数可以在编辑器打开,或者编译后执行,放心地把Init或者Reset放在这里
static EditorTiming()
{
}
}
3、单例模式
单例模式没什么好说的,无论时普通的Singleton,还是MonoSingleton,都可以在网上找到,这里只说一下在Unity源码里翻出来的ScriptableObjectSingleton
这里的话,就主要讲讲我用的最多的几个委托接口:
1、编辑器Update委托——EditorApplication.update
既然InitializeOnLoad只是初始话普通类,并不能update之类的,所以需要绑定一个update委托给它,让他能自行Update,用的就是这个EditorApplication.update
2、在SceneView上面写写画画——SceneView.duringSceneGui(这个为2019版的,2019前的为SceneView.onSceneGUIDelegate)
主要是处理SceneView的一些Event、操作、只在SceneView里画出各种GUI等等,详见可以看本系列的其他文章
3、代码编译相关
在编辑器编辑状态,肯定需要知道代码是不是在编译,或者编译好之后的回调之类的,这里有几个方法
(1)DidReloadScripts特性
// 注意这个特性需要的函数时静态函数
// 就算这个类没被使用,甚至没被实例化,都会被执行到
// 所以用的时候需要注意判断执行条件
[DidReloadScripts]
private static void Reload()
{
}
(2)AssemblyReloadEvents类
这个主要两个回调:AssemblyReloadEvents.beforeAssemblyReload, AssemblyReloadEvents.afterAssemblyReload。一个在编译前执行,一个在编译后执行。
这三个的执行顺序为:AssemblyReloadEvents.beforeAssemblyReload —》 AssemblyReloadEvents.afterAssemblyReload -》 DidReloadScripts
4、资源导入相关——EditorApplication.projectChanged
既然要知道代码编译了,那么也不能缺资源被修改的回调了。
在人为操作的删除、添加、修改、编译之后,都会执行这个回调,不过坑的是,这里并没有告诉我们什么资源被修改了。
如果在代码中对资源修改之后,需要执行AssetDataBase.Refresh()
5、撤销操作——UnDo
这个暂无太多了解,只是看了这么一个例子,了解到了一些撤回的操作
https://answers.unity.com/questions/975578/undoredo-on-meshes-this-code-works-but-how.html
6、大部分都集中在EditorApplication
7、个人一些建议
个人感觉可以都把这些回调绑定在一个类里面,这样有两个好处
(1)不用每个类都关心绑定、解绑的时机
(2)可以控制每个类的执行顺序
比如说可以这样
[InitializeOnLoad] public static class EditorTiming { static EditorTiming() { EditorApplication.update += Update; } // 所有类都在这个函数里执行,顺序明显,且a、b不需要管绑定与解绑委托的事情 void Update() { a.Update(); b.Update(); } }
三、善用反射
毕竟很多时候,Unity提供的接口并不能满足我们的开发需求,虽然有时我们可以将需要用到的代码照抄过来,但若是需要处理的数据牵扯到许多地方,这个时候,用到反射是一个很不错的选择。
这个时候就推销以下我的反射框架了,详细介绍见Unity Package 一键更新功能开发之C#反射框架篇。
然后自己也建了一个对标unity开源代码UnityCsReference的UnityCsReflection,欢迎Star→_→
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。