官方教程:链接

EditorLayout API:链接

Handles API:链接

 

1.首先来个Inspector面板Editor的实现

要实现一个组件在Inspector中的Editor功能,首先需要写一个编辑器类:

Unity如何让Sprite不打成SpriteAtlas_UI

要点

1.继承Editor

2.放在Editor文件夹中

3.在类的头部写[CustomEditor(typeof(你要实现编辑的组件的类名))]

4.复写OnInspectorGUI函数(此函数仅在Inspector刷新时自动调用),然后在函数里实现编辑器功能的拓展实现。例如GUILayout.Label("Hello World");

5.通过target as ‘你的类名’ 来实现引用你要扩展的组件的类的具体对象。

 

2.GUILayoutOption

EditorGUILayout 与 EditorGUI功能基本差不多,它是EditorGUI的自动布局版本,用它可以快速创建默认UI,若要自定义UI样式,应该使用EditorGUI并传入GUIStyle等参数

GUILayoutOption是一种GUI布局方式的设置,常在GUILayout的具体控件中看到,

例如,

Unity如何让Sprite不打成SpriteAtlas_Image_02

的最后一个参数便是一些GUILayoutOption不定参,表示可以有多个设置方案。

注意:GUILayoutOption只是表示是设置方案的意思,并不是代表有GUILayoutOption这种设置方法,GUILayoutOption其实是个空类,

具体的设置方案由具体决定。

例如:

GUILayout.Label("Hello World"), EditorStyles.helpBox); 

GUILayout.Label("Hello World")表示在面板上显示一条内容为“Hello World”的Label,(下图第一条)

而EditorStyles.helpBox则表示此Label的显示方式是以帮助框的形式显示(下图第二条)

Unity如何让Sprite不打成SpriteAtlas_UI_03

 

更多的GUILayoutOption:

EditorStyles.boldLabel 

Unity如何让Sprite不打成SpriteAtlas_UI_04

EditorStyles.centeredGreyMiniLabel

Unity如何让Sprite不打成SpriteAtlas_控件_05

EditorStyles.radioButton 

Unity如何让Sprite不打成SpriteAtlas_Image_06

EditorStyles.whiteBoldLabel 

Unity如何让Sprite不打成SpriteAtlas_控件_07

 

3.GUILayout 之 SelectionGrid

设置一个网格按钮,并返回按钮的序号。

string[] text = { "1", "2", "3", "4" };
Debug.Log(GUILayout.SelectionGrid(-1, text, 2) + " has been choose.");

按钮可以是文字(上面的1,2,3,4四个按钮),也可以是图片等。

第一参数的-1表示按钮哪个被按下,如果为0,则表示第一按钮显示为被按下,-1表示没有。

第三个参数的2表示此网格分为2列,具体如图:

Unity如何让Sprite不打成SpriteAtlas_控件_08

 

4.折页

首先用这句:

showState = EditorGUILayout.Foldout(showState, "State List"); 参数分别为是否打开,显示标签的名字

其实折页就相当于一个toggle按钮,并不做任何事,只是你按下它,它会返回一个是否折开或者合并的结果,

然后自己再根据这个结果显示对应内容来达到折页效果。

if (showState)
{
  GUILayout.Label("内容", EditorStyles.inspectorDefaultMargins);
}
// 为了模拟折页后的子层级的树状缩进结构,我门用EditorStyles.inspectorDefaultMargins这中设置来将内容向右缩进。

Unity如何让Sprite不打成SpriteAtlas_UI_09

 

5.自定义自己的GUIStyle

在2中我们知道了如何用GUIStyle扩展GUILayout的各种控件的样式,但我们用的都是EditorStyles附带的风格,

这个EditorStyles是系统用的,我们只能用里面的风格,不能修改(其实也可以改,但改后会将系统其他所以使用该风格的地方都改)。

为了定制我们自己的风格,其实我们可以自己创建一个GUIStyle。

GUIStyle topStyle = new GUIStyle(EditorStyles.centeredGreyMiniLabel);  // 这里我用EditorStyles的centeredGreyMiniLabel来初始化我的新风格
topStyle.fontStyle = FontStyle.Bold;                       // 新Style的字体为粗体
topStyle.fontSize = 20;
topStyle.richText = true;                              // 允许富文本

Unity如何让Sprite不打成SpriteAtlas_控件_10

 

6.再来个Scene面板的Editor实现

基本与Inspector面板Editor的写法一样,只不过Scene面板的更新函数是OnSceneGUI,与之对应的是

Inspector面板的更新函数OnInspectorGUI。

甚至可以在同一个脚本里同时实现Inspector与Scene面板的Editor功能。

要点:

1.在OnSceneGUI()中只能通过Handles来绘制新视图,如果你想引入GUI的元素哪么就需要使用BeginGUI()和EndGUI()组合的使用。

2.同Inspector一样,仅在持有该脚本的对象被选择时才激活。

 eg:

void OnSceneGUI() 
{
  //得到test脚本的对象
  Test test = (Test) target;
//在Scene视图中,在该对象本身的位置画一个坐标轴,但画自身坐标轴的意义不大,因为自身坐标轴在被选中时本来就会画出来。但可以用来显示其他对象的坐标轴。
  Handles.PositionHandle(fsm.test.transform.position, Quaternion.identity);
  //在场景中GameObject所在的位置绘制文本框,内容为该GO的坐标
  Handles.Label(test.transform.position + Vector3.up*2, test.transform.name +" : "+ test.transform.position.ToString() );
  //开始绘制GUI
  Handles.BeginGUI();
  //规定GUI显示区域
  GUILayout.BeginArea(new Rect(100, 100, 100, 100));
  //GUI绘制一个按钮
  if(GUILayout.Button("这是一个按钮!"))
      Debug.Log("test");
  //GUI绘制文本框
  GUILayout.Label("我在编辑Scene视图");    
  GUILayout.EndArea();
  Handles.EndGUI();
 }

 

7.利用Gizmos在Editor里绘制图形

Gizmos是常见的DebugDraw方式之一,可方便地在Editor里绘制线段,射线,方块之类的

用法:Gizmos只能用于OnDrawGizmos函数里,该函数跟Start,Update一样会自动调用

Unity如何让Sprite不打成SpriteAtlas_控件_11

但是一般情况下,绘制函数里的参数只有'center','size'之类的,绘制出来的图形是没有角度的,

如果有需要绘制旋转过的图形,例如一个跟随摄影机旋转的Cube

Unity如何让Sprite不打成SpriteAtlas_Image_12

那么就需要利用Gizmos的重要参数——matirx,

这是Gimos的绘制矩阵,绘制的图形信息在这里,要缩放,旋转Gizmos绘制出来的图形,

只需要改变矩阵即可。

void OnDrawGizmos()
    {
        Vector3 size = new Vector3(half.x * 2, half.y * 2, half.z * 2);
        // 变换矩阵
        Matrix4x4 trs = Matrix4x4.TRS(transform.position, transform.rotation, transform.localScale);
        Gizmos.matrix = trs;
        // 在该Transform的Vector3.zero处绘制一个位置、角度、缩放均与该Transform一样的方块,大小为size
        Gizmos.DrawCube(Vector3.zero, size);
        // 复位Gizmos设置
        Gizmos.matrix = Matrix4x4.identity;
    }

 

8.Editor菜单栏快捷键

Unity如何让Sprite不打成SpriteAtlas_UI_13

Unity如何让Sprite不打成SpriteAtlas_Image_14

%代表 Ctrl

#代表 Shift

 

9.手动将Scene标志为“修改过的”

有时候会动态在Editor脚本里创建对象在Scene里,但是动态创建之后Scene默认是认为场景没被修改过的,

这个时候是没法保存场景的,就算你强制Ctrl + S,重载场景后之前动态生成的对象也会丢失(除非你在生成对象后,又手动在场景里做一些修改)

那么我需要手动调用场景管理器里的一个方法,将当前所有打开的场景标志为“脏的”,即被改动过的,这个时候在就可以Ctrl + S保存了。

EditorSceneManager.MarkAllScenesDirty();

同理,如果你通过代码改过资源,那么也需要手动调用AssetDatabase.Refresh 刷新下编辑器。

 

10.GUI分类

GUI,GUILayout :

  在UnityEngine命名空间下,可以运行在任何地方,游戏场景,SceneView,Editor面板。

  GUI,GUILayout的区别是,GUI是没有布局的,需要手动指定位置,排版。

EditorGUI,EditorGUILayou:

  在UnityEditor命名空间下,只能运行在编辑器面板上,甚至编辑器里的SceneView也不行,因为有些空间,例如下拉菜单只能在编辑器面板显示。

  两种区别同上。

 

11.在SceneView里显示UI控件:

有时候需要在场景面板显示一些编辑器控件

Unity如何让Sprite不打成SpriteAtlas_Image_15

 有多种方法:

1.为某个类写Editor脚本,例如为Test类写个TestEditor继承自Editor,然后放在Editor文件夹下,这样的话,在层级列表里选择带有该脚本的物体,就会在Scene里显示对应的UI

缺点是要选中才显示

2.同上,但是把对某个类的拓展扩大到GameObject,这样就会导致不管选任何类,都会执行这个脚本

如果不选择任何物体的话,不会显示

Unity如何让Sprite不打成SpriteAtlas_Image_16

 3.Unity的SceneView类有个委托,叫duringSceneGui,每次执行OnSceneGUI时都会执行这个委托,可以手动给这个委托添加我们的函数

这样就会一直执行我们的OnSceneGUI,直到手动卸载

public class SceneGUI : EditorWindow
{
    private static bool m_sIsShow = false;
    private static Vector2 m_sScrollPos;

    [MenuItem("Window/Scene GUI/Enable")]
    public static void Enable()
    {
        if (!m_sIsShow)
        {
            SceneView.duringSceneGui += OnScene;
            Debug.Log("Scene GUI : Enabled");
            m_sIsShow = true;
        }
    }

    [MenuItem("Window/Scene GUI/Disable")]
    public static void Disable()
    {
        if (m_sIsShow)
        {
            SceneView.duringSceneGui -= OnScene;
            Debug.Log("Scene GUI : Disabled");
            m_sIsShow = false;
        }
    }

    private static void OnScene(SceneView sceneview)
    {
        Handles.BeginGUI();
        if (GUILayout.Button("Press Me"))
            Debug.Log("Got it to work.");
        Handles.EndGUI();
    }
}

 

12.Add Component回调功能

有时候需要在Inspector面板点击Add Component添加某一个组件时,调用我们的方法来修改添加的组件参数

ObjectFactory.componentWasAdded += ComponentWasAdded;

static public void ComponentWasAdded(Component com)
{
    Debug.Log(com);
}

 

13.Unity 重写Remove Component的方法

以重写Image组件的Remove Component函数为例,移除Image组件时,会顺带把Image所在的Object上的CanvasRenderer组件也给移除

[MenuItem("CONTEXT/Image/Remove Component")]
        public static void RemoveImage(MenuCommand menuCommand)
        {
            var img = menuCommand.context as Image;
            var canvasRenderer = img.GetComponent<CanvasRenderer>();
            UnityEngine.Object.DestroyImmediate(img);

            UnityEngine.Object.DestroyImmediate(canvasRenderer);
        }

 

14.EditorGUI控件输入监听

在做编辑器开放的过程中,有时候要对用户输入进行判断和限制,但EditorGUI控件却没有触发回调,而是提供了一种麻烦的办法——使用EditorGUI.BeginChangeCheck()和EditorGUI.EndChangeCheck()

代码写起来像这样:

EditorGUI.BeginChangeCheck();
{
    // EditorGUI输入控件写在这里
    // value = EditorGUILayout.IntFie(...)
}
if (EditorGUI.EndChangeCheck()) {
    //TODO...这里可以对输入结果进行处理
    // if(value>...)
    //      value = ...
}