Unity3D插件开发教程
一、插件开发的起因
1.日常开发过程中会碰到许多重复且复杂的操作过程,比如数据的存储,资源文件的管理等等,我们在做这些事情的时候会浪贵很多的时间以及精力。
2.人为操作一些事情的时候,或多或少会出现一些问题。
二、插件的作用
1.提高项目开发的效率
2.增加项目开发的质里
3.增加团队合作的方便
三、菜单项相关操作
1.菜单项(MenuItem)
一般会在 Project-->Assets底下创建一个Editor文件夹,此文件夹里面主要存放编辑的关于插件相关的内容(脚本),此文件夹里面的脚本,打包项目的时候不会存放到包里面,所以一般插件都会存放到这里面。
第一步:在Editor文件夹里面创建C#脚本:如:MenuTest
第二步:编写MenuTest插件脚本
引入命名空间:using UnityEditor;
定义的方法前面,必须使用static修饰,且方法上面需要添加:[MenuItem("Menu/Test")]
注明:[MenuItem("Menu/Test")] 里面的不同参数,分别代表着使用什么方式打开
1 //[MenuItem("Menu/Test")]:这种写法意味着没有快捷键,需要鼠标点击 2 [MenuItem("Menu/Test")] 3 public static void Test() 4 { 5 Debug.Log("Test"); 6 } 7 8 //_w:表示没有组合键,直接按住键盘"w"使用 9 [MenuItem("Menu/Test1 _w")] 10 public static void Test1() 11 { 12 Debug.Log("Test1"); 13 } 14 15 //#w:表示按住 Shift + w 使用 16 [MenuItem("Menu/Test2 #w")] 17 public static void Test2() 18 { 19 Debug.Log("Test2"); 20 } 21 22 //%w:表示按住 Ctrl + w 使用 23 [MenuItem("Menu/Test3 %w")] 24 public static void Test3() 25 { 26 Debug.Log("Test3"); 27 } 28 29 //&w:表示按住 Alt + w 使用 30 [MenuItem("Menu/Test4 &w")] 31 public static void Test4() 32 { 33 Debug.Log("Test4"); 34 }
在Unity3D中效果展示:多出了一个"Menu"菜单,和"MenuTest"脚本中定义的5个方法
2.组件菜单(AddComponentMenu)
目的:方便添加组件相关的操作
第一步:组件菜单的文件存放目录不存放在Editor下面,在新建一个"Scripts"目录,并创建"ComponentDemo"脚本
第二步:在创建的脚本类名上面添加:[AddComponentMenu("Demo/Demo1")],其中"Demo/Demo1"为开发者自定义的路径
效果如下:
除此之外,自定义的组建,在菜单“Component”里面也有
3.上下文菜单(ContextMenu)
上下文菜单是定义在组件类里面的方法。
第一步:我们在上文创建的“ComponentDemo”类里面定义一个"ContextMenuDemo()"方法,注意:不能使用static修饰,并用:[ContextMenu("ContextDemo")]标注上下文菜单的名字为:“ContextDemo”
第二步:回到Unity面板中,创建一个游戏物体,并添加“Demo1”组件,然后鼠标在此组件上右击,就可以看到多了一个“ContextDemo”选项
4.必要组件菜单(RequireComponent)
比如:我们要求给游戏物体添加“Demo1”组件的时候,必须带上“Rigidbody”组件。
效果:当你给游戏物体添加“Demo1”组件的时候,会自动添加“Rigidbody”组件。
如果想要移除组件,必须先移除“Demo1”,再移除“Rigidbody”。
四、自定义Inspector界面
1.属性相关标识
a.隐藏属性显示(HideInInspector):单纯的隐藏变量
b.不显示属性(NonSerialized):不但隐藏变量,并且还会防止该变量的序列化保存,(无论在Inspector面板中设置Int3的值是多少,只要在C#中设置Int3的属性为“NonSerialized”并且假如设置的值为 3,那么Unity编译后,Inspector面板中的Int3的值就是3)
c.系列化域(SerializeField):将私有变量强制显示在Inspector面板里面
d.关键字系列化(Serializable):可以让自定义的类(不继承自:MonoBehaviour的类)显示在Inspector面板里面
2.自定义界面属性
Editor:自定义属性面板的基类
CustomEditor:类上面的标识
第一步:创建两个类,EditorDemo,Test1。EditorDemo需要放在Assets-->Editor里面,Test1类放入Scripts里面即可。
第二步:编写Test1代码,设置一些属性,并在里面引入新创建的类TypeDemo
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using UnityEngine; 5 6 public class Test1 : MonoBehaviour 7 { 8 public int mIntVal; 9 10 public float mFloatVal; 11 12 public string mStrVal; 13 14 public TypeDemo mTypeDemo; 15 } 16 17 [Serializable]//不添加序列化设置,属性值不会显示在Inspector面板里 18 public class TypeDemo 19 { 20 public int tIntVal; 21 public string tStrVal; 22 public float tFloatVal; 23 }
第三步:EditorDemo需要继承自Editor,并声明:[CustomEditor(typeof(Test1))]
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 //是一个窗口脚本,所以要放在Assets-->Editor下面 7 [CustomEditor(typeof(Test1))] 8 public class EditorDemo : Editor 9 { 10 public SerializedObject mObj;//定义序列化目标对象 11 //序列化出来几个属性,属性对应的是[CustomEditor(typeof(Test1))]中,Test1类里面的属性 12 public SerializedProperty mIntVal; 13 public SerializedProperty mFloatVal; 14 public SerializedProperty mStrVal; 15 public SerializedProperty mTypeDemo; 16 17 //选择当前游戏对象 18 private void OnEnable() 19 { 20 //初始化 21 this.mObj = new SerializedObject(target); 22 //通过字符串名字,查找Test1类里面的属性,并进行初始化 23 this.mIntVal = this.mObj.FindProperty("mIntVal"); 24 this.mFloatVal = this.mObj.FindProperty("mFloatVal"); 25 this.mStrVal = this.mObj.FindProperty("mStrVal"); 26 27 this.mTypeDemo = this.mObj.FindProperty("mTypeDemo"); 28 } 29 30 //绘制 31 public override void OnInspectorGUI() 32 { 33 this.mObj.Update(); 34 35 EditorGUILayout.PropertyField(this.mIntVal); 36 EditorGUILayout.PropertyField(this.mFloatVal); 37 EditorGUILayout.PropertyField(this.mStrVal); 38 39 EditorGUILayout.PropertyField(this.mTypeDemo, true);//true属性意思是设置显示子节点,也就是显示TypeDemo里面的属性 40 41 this.mObj.ApplyModifiedProperties(); 42 } 43 }
效果展示:
3.自定义序列化属性字段
创建一个类Test2
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using UnityEngine; 5 6 public class Test2 : MonoBehaviour 7 { 8 public EnumDemo mEnumDemo; 9 public bool mBool; 10 public int mInt; 11 public float mFloat; 12 public string mStr; 13 public Color mColor; 14 } 15 16 [Serializable] 17 public enum EnumDemo 18 { 19 None, 20 BoolVal, 21 IntVal, 22 FloatVal, 23 StrVal, 24 Color 25 }
创建一个类EditorInspectorDemo,放在Assets-->Editor下面
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 [CustomEditor(typeof(Test2))] 7 public class EditorInspectorDemo : Editor 8 { 9 public SerializedObject mObj; 10 public SerializedProperty mEnumDemo; 11 public SerializedProperty mBool; 12 public SerializedProperty mInt; 13 public SerializedProperty mFloat; 14 public SerializedProperty mStr; 15 public SerializedProperty mColor; 16 private void OnEnable() 17 { 18 this.mObj = new SerializedObject(target); 19 this.mEnumDemo = this.mObj.FindProperty("mEnumDemo"); 20 this.mBool = this.mObj.FindProperty("mBool"); 21 this.mInt = this.mObj.FindProperty("mInt"); 22 this.mFloat = this.mObj.FindProperty("mFloat"); 23 this.mStr = this.mObj.FindProperty("mStr"); 24 this.mColor = this.mObj.FindProperty("mColor"); 25 } 26 27 public override void OnInspectorGUI() 28 { 29 this.mObj.Update(); 30 EditorGUILayout.PropertyField(this.mEnumDemo); 31 //使用switch做条件筛选,this.mEnumDemo.enumValueIndex作为筛选条件,index从0开始,由于我设置枚举类型的第一个属性为None,所以case的值从1开始。 32 switch (this.mEnumDemo.enumValueIndex) 33 { 34 case 1: 35 EditorGUILayout.PropertyField(this.mBool); 36 break; 37 case 2: 38 EditorGUILayout.PropertyField(this.mInt); 39 break; 40 case 3: 41 EditorGUILayout.PropertyField(this.mFloat); 42 break; 43 case 4: 44 EditorGUILayout.PropertyField(this.mStr); 45 break; 46 case 5: 47 EditorGUILayout.PropertyField(this.mColor); 48 break; 49 50 } 51 52 this.mObj.ApplyModifiedProperties(); 53 } 54 }
可以实现:选择不同的下拉框属性,下面会出现相对应的设置,步骤和上面“自定义界面属性”一样,代码类似,实现效果如下:
五、自定义操作界面
1.界面的启动关闭
创建一个ShowWindow类,存放在Assets-->Editor里面,并继承自EditorWindow
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class WindowDemo : EditorWindow 7 { 8 [MenuItem("Menu/ShowWindow")] 9 public static void ShowWindow() 10 { 11 //使用官方提供的实例化窗口方法调用 12 WindowDemo.CreateInstance<WindowDemo>().Show(); 13 14 //浮动型的窗口,跟点击Building Setting出现的窗口效果一样 15 WindowDemo.CreateInstance<WindowDemo>().ShowUtility(); 16 17 //弹出窗口时的效果 18 WindowDemo.CreateInstance<WindowDemo>().ShowPopup();//此方Y法和下面的OnGUI配合着使用,否则会出现页面关不掉的情况 19 } 20 public void OnGUI() 21 { 22 if (GUILayout.Button("关闭")) 23 { 24 this.Close(); 25 } 26 } 27 }
效果展示:
2.页面的相关事件机制
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class EditorDemo2 : EditorWindow 7 { 8 [MenuItem("Menu/NewWindow")] 9 public static void ShowWindow() 10 { 11 //使用系统提供的单例模式,在unity面板中打开窗口时,只会出现一个 12 EditorWindow.GetWindow<EditorDemo2>().Show(); 13 } 14 15 //绘制操作面板 16 public void OnGUI() 17 { 18 if (GUILayout.Button("关闭")) 19 { 20 this.Close(); 21 } 22 } 23 24 public int index_1 = 0; 25 //刷新方法,每秒钟100次 26 public void Update() 27 { 28 index_1++; 29 Debug.Log("index_1:" + index_1); 30 } 31 32 public int index_2 = 0; 33 //刷新方法,刷新周期比Update小 34 public void OnInspectorUpdate() 35 { 36 index_2++; 37 Debug.Log("index_2:" + index_2); 38 } 39 //视图被删除的时候触发 40 public void OnDestroy() 41 { 42 Debug.Log("OnDestroy:触发"); 43 } 44 //选择一个对象的时候触发 45 public void OnSelectionChange() 46 { 47 //获取选择Hierarchy里面游戏物体的时候的名字 48 for (int i = 0; i < Selection.gameObjects.Length; i++) 49 { 50 Debug.Log("OnSelectionChange:触发" + Selection.gameObjects[i].name); 51 } 52 53 //获取选择Project里面的文件的名字 54 for (int i = 0; i < Selection.objects.Length; i++) 55 { 56 Debug.Log("OnSelectionChange:触发" + Selection.objects[i].name); 57 } 58 } 59 //获得焦点的时候触发 60 public void OnFocus() 61 { 62 Debug.Log("OnFocus:触发"); 63 } 64 //失去焦点的时候触发 65 public void OnLostFocus() 66 { 67 Debug.Log("OnLostFocus:触发"); 68 } 69 //Hierarchy更改的时候触发 70 public void OnHierarchyChange() 71 { 72 Debug.Log("OnHierarchyChange:触发"); 73 } 74 //Project更改的时候触发 75 public void OnProjectChange() 76 { 77 Debug.Log("OnProjectChange:触发"); 78 } 79 80 }
效果展示:
3.文本/颜色字段
在Assets-->Editor文件夹里面创建TextEditorWindow类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class TextEditorWindow : EditorWindow 7 { 8 [MenuItem("Menu/TextEditorWindow")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<TextEditorWindow>().Show(); 12 } 13 //为了更方便练习演示,就定义了一个字符串 14 public string mText = "默认文字"; 15 public Color mColor = Color.white; 16 public void OnGUI() 17 { 18 //一行文本,单行输入框 19 this.mText = EditorGUILayout.TextField(this.mText); 20 //多行输入框 21 this.mText = EditorGUILayout.TextArea(this.mText); 22 //密码输入框 23 this.mText = EditorGUILayout.PasswordField(this.mText); 24 //颜色选择框 25 this.mColor = EditorGUILayout.ColorField(this.mColor); 26 } 27 }
效果展示:
4.标签字段
在Assets-->Editor文件夹里面创建TagEditorWindow类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class TagEditorWindow : EditorWindow 7 { 8 [MenuItem("Menu/TagEditorWindow")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<TagEditorWindow>().Show(); 12 } 13 14 //为了更方便练习演示,就定义了一个字符串 15 public string mText = "默认文字"; 16 public void OnGUI() 17 { 18 //标签 19 EditorGUILayout.PrefixLabel(this.mText);//只写这么一行代码,窗口里面不出现任何内容 20 EditorGUILayout.Space();//换行 21 22 //标签(下拉框) 23 this.mText = EditorGUILayout.TagField(this.mText); 24 EditorGUILayout.Space(); 25 26 //标签(非可选择标签提示) 27 EditorGUILayout.LabelField(this.mText); 28 EditorGUILayout.Space(); 29 30 //标签(可选择标签提示) 31 EditorGUILayout.SelectableLabel(this.mText); 32 EditorGUILayout.Space(); 33 } 34 }
效果展示:
5.数字输入字段
在Assets-->Editor文件夹里面创建NumberEditorWindow类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class NumberEditorWindow : EditorWindow 7 { 8 [MenuItem("Menu/NumberEditorWindow")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<NumberEditorWindow>().Show(); 12 } 13 14 public int mInt; 15 public float mFloat; 16 public void OnGUI() 17 { 18 EditorGUILayout.LabelField("输入整形数字"); 19 this.mInt = EditorGUILayout.IntField(this.mInt); 20 EditorGUILayout.LabelField("输入浮点型数字"); 21 this.mFloat = EditorGUILayout.FloatField(this.mFloat); 22 } 23 }
效果展示:
6.滑动条
在Assets-->Editor文件夹里面创建NumberEditorWindow类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class SliderEditorWindow : EditorWindow 7 { 8 [MenuItem("Menu/SliderEditorWindow")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<SliderEditorWindow>().Show(); 12 } 13 14 public float mFloat; 15 16 public int mInt; 17 18 public float mMinVal; 19 public float mMaxVal; 20 public void OnGUI() 21 { 22 //滑动条 参数1:默认值,参数2:最小值,参数3:最大值 23 this.mFloat = EditorGUILayout.Slider(this.mFloat, 0, 100);//取值区间有小数 24 25 this.mInt = EditorGUILayout.IntSlider(this.mInt, 0, 100);//取值区间为整数 26 27 //最小值到最大值的取值范围,为0-100 28 EditorGUILayout.MinMaxSlider(ref mMinVal, ref mMaxVal, 0, 100); 29 } 30 }
效果展示:
7.位置/大小输入字段
在Assets-->Editor文件夹里面创建VectorEditorWindow类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class VectorEditorWindow : EditorWindow 7 { 8 [MenuItem("Menu/VectorEditorWindow")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<VectorEditorWindow>().Show(); 12 } 13 14 public Vector2 mPos2; 15 public Vector3 mPos3; 16 public Vector4 mPos4; 17 public Rect mRect; 18 public Bounds mBounds; 19 public void OnGUI() 20 { 21 this.mPos2 = EditorGUILayout.Vector2Field("二维坐标", this.mPos2); 22 this.mPos3 = EditorGUILayout.Vector3Field("三维坐标", this.mPos3); 23 this.mPos4 = EditorGUILayout.Vector4Field("四维坐标", this.mPos4); 24 25 EditorGUILayout.Space(); 26 EditorGUILayout.LabelField("矩阵"); 27 this.mRect = EditorGUILayout.RectField(this.mRect); 28 EditorGUILayout.Space(); 29 EditorGUILayout.LabelField("间距"); 30 this.mBounds = EditorGUILayout.BoundsField(this.mBounds); 31 } 32 }
效果展示:
8.选择字段
在Assets-->Editor文件夹里面创建ChooseEditorWindow类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class ChooseEditorWindow : EditorWindow 7 { 8 [MenuItem("Menu/ChooseEditorWindow")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<ChooseEditorWindow>().Show(); 12 } 13 public int mIndex; 14 public int mIndex2; 15 public EnumDemo mEnumDemo; 16 public void OnGUI() 17 { 18 string[] strs = new string[] { "aaa", "bbb", "ccc", "ddd", "eee" }; 19 int[] ints = new int[] { 111, 222, 333, 444, 555 }; 20 21 //选择 22 this.mIndex = EditorGUILayout.Popup(this.mIndex, strs); 23 //和上面的方法类似 24 this.mIndex2 = EditorGUILayout.IntPopup(this.mIndex2, strs, ints); 25 //枚举 26 this.mEnumDemo = (EnumDemo)EditorGUILayout.EnumPopup(this.mEnumDemo); 27 } 28 29 public enum EnumDemo 30 { 31 mString, mInt, mFloat, mDouble, mColor 32 } 33 }
效果展示:
9.标签层对象选择字段
在Assets-->Editor文件夹里面创建ObjectChooseEditor类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class ObjectChooseEditor : EditorWindow 7 { 8 [MenuItem("Menu/ObjectChooseEditor")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<ObjectChooseEditor>().Show(); 12 } 13 14 public string mTag; 15 public int mLayer; 16 public Object mObject; 17 public void OnGUI() 18 { 19 //标签,下面两种写法,哪个都可以 20 //this.mTag = EditorGUILayout.TagField(this.mTag); 21 this.mTag = EditorGUILayout.TagField("Tag"); 22 EditorGUILayout.Space(); 23 //层 24 this.mLayer = EditorGUILayout.LayerField(this.mLayer); 25 EditorGUILayout.Space(); 26 //对象选择,如果想要存放所有的元素,那么参数就写为Object: typeof(Object) 27 this.mObject = EditorGUILayout.ObjectField("对象选择器", this.mObject, typeof(Camera), true); 28 } 29 }
效果展示:
10.单选字段
在Assets-->Editor文件夹里面创建SingleChoiceEditor类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class SingleChoiceEditor : EditorWindow 7 { 8 [MenuItem("Menu/SingleChoiceEditor")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<SingleChoiceEditor>().Show(); 12 } 13 14 public bool mBool; 15 public bool mFoldout; 16 public void OnGUI() 17 { 18 //单选字段 19 this.mBool = EditorGUILayout.Toggle(this.mBool); 20 //单选字段,也可以在bool参数前面加个标签 21 this.mBool = EditorGUILayout.Toggle("是", this.mBool); 22 //折叠 23 this.mFoldout = EditorGUILayout.Foldout(this.mFoldout, "折叠"); 24 Debug.Log(this.mFoldout); 25 if (this.mFoldout) 26 { 27 EditorGUILayout.LabelField("A"); 28 EditorGUILayout.LabelField("B"); 29 EditorGUILayout.LabelField("C"); 30 } 31 } 32 }
效果如下:
11.字段分组
在Assets-->Editor文件夹里面创建GroupEditorWindow类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class GroupEditorWindow : EditorWindow 7 { 8 [MenuItem("Menu/GroupEditorWindow")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<GroupEditorWindow>().Show(); 12 } 13 14 public bool mBool; 15 16 public Vector2 mVector2; 17 18 public void OnGUI() 19 { 20 //如果窗口内容过多,可以使用滚动区域,出现滑条 21 EditorGUILayout.BeginScrollView(this.mVector2); 22 23 //分组:有开始和结束 24 this.mBool = EditorGUILayout.BeginToggleGroup("选择分组", mBool); 25 EditorGUILayout.LabelField("练习分组:ToggleGroup"); 26 EditorGUILayout.TextField("练习分组:ToggleGroup"); 27 EditorGUILayout.EndToggleGroup(); 28 EditorGUILayout.Space(); 29 30 //矩阵,水平分组 31 Rect mHorizontal = EditorGUILayout.BeginHorizontal(); 32 EditorGUILayout.LabelField("练习分组:Horizontal"); 33 EditorGUILayout.TextField("练习分组:Horizontal"); 34 EditorGUILayout.EndHorizontal(); 35 EditorGUILayout.Space(); 36 37 //矩阵,垂直分组 38 Rect mVertical = EditorGUILayout.BeginVertical(); 39 EditorGUILayout.LabelField("练习分组3"); 40 EditorGUILayout.TextField("练习分组3"); 41 EditorGUILayout.EndVertical(); 42 EditorGUILayout.Space(); 43 44 EditorGUILayout.LabelField("联系分组"); 45 EditorGUILayout.TextField("联系分组"); 46 47 //结束滚动 48 EditorGUILayout.EndScrollView(); 49 } 50 }
效果展示:
12.其他字段
在Assets-->Editor文件夹里面创建OtherEditorWindow类,并继承自EditorWindow,代码如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEditor; 4 using UnityEngine; 5 6 public class OtherEditorWindow : EditorWindow 7 { 8 [MenuItem("Menu/OtherEditorWindow")] 9 public static void ShowWindow() 10 { 11 EditorWindow.GetWindow<OtherEditorWindow>().Show(); 12 } 13 public AnimationCurve mAC = new AnimationCurve(); 14 public Object mObj; 15 public bool mSelect; 16 public void OnGUI() 17 { 18 //动画标签 19 this.mAC = EditorGUILayout.CurveField("动画片段", this.mAC); 20 EditorGUILayout.Space(); 21 22 this.mObj = EditorGUILayout.ObjectField("标题", this.mObj, typeof(Transform), true); 23 if (this.mObj != null) 24 { 25 this.mSelect = EditorGUILayout.InspectorTitlebar(this.mSelect, this.mObj); 26 } 27 } 28 }
效果展示: