Unity Editor 基础篇(二):自定义 Inspector 面板

本文参自:http://mp.weixin.qq.com/s/Y5Rn5Y-5o-SB73z7Kc5f_Q 
本文为本人学习上连接的笔记有改动,请点击以上链接查看原文,尊重楼主知识产权。


自定义Inspector属性面板

官方连接:http://www.ceeger.com/Script/Editor/Editor.html

EditorGUILayout 编辑器界面布局 
这是一个编辑器类,如果想使用它你需要把它放到工程目录下的Assets/Editor文件夹下。编辑器类在UnityEditor命名空间下。所以当使用C#脚本时,你需要在脚本前面加上 “using UnityEditor”引用。

接下来开始制作的我们自己的 Inpector,对于自定义 Inpector 面板可参考EditorGUILayout的API:

BeginFadeGroup 开始一个可以被隐藏/显示的组,并且这个转换将会被**。
BeginHorizontal 开始一个水平的组并得到它的矩形。
BeginScrollView 启动一个自动布局的scrollview。
BeginToggleGroup 用一个开关启动一个垂直的组,使所有的控件同时启用或禁用。
BeginVertical 开始一个垂直的组并得到它的矩形。
BoundsField 使中心和区段域进入一个界域。
BoundsIntField 为进入一个有弹性的区域制造位置和大小场。
ColorField 为选择一种颜色做一个字段。
CurveField 制作一个用于编辑动画曲线的领域。
DelayedDoubleField 制作一个延迟的文本字段,用于输入双精度数。
DelayedFloatField 为进入浮动设置一个延迟的文本字段。
DelayedIntField 为输入整数制作一个延迟的文本字段。
DelayedTextField

创建一个延迟的文本字段。

DoubleField 为输入双值创建一个文本字段。
DropdownButton 制作一个按钮,对鼠标做出反应,显示你自己的下拉内容。
EndFadeGroup 关闭一个由开始组开始的组。
EndHorizontal 关闭一个以开始水平开始的小组。
EndScrollView 结束一个scrollview,开始调用BeginScrollView。
EndToggleGroup 关闭一个小组,从开始的小组开始。
EndVertical 关闭一个以开始垂直开始的小组。
EnumFlagsField 当单击时,显示一个带有枚举类型值的选项的菜单。值为0的选项“没有”,而值0(即所有位元组)的选项总是显示在菜单的顶部。值0和0的名称可以通过在enum类型中定义这些值而被过度使用
EnumPopup 创建一个enum弹出选择字段。
FloatField 为输入浮动值创建一个文本字段。
Foldout 在它的左边用一个折叠箭头做一个标签。
GetControlRect 获取一个编辑器控件的rect。
HelpBox 向用户提供一个有消息的帮助框。
InspectorTitlebar 做一个类似于检查窗口的标题栏。
IntField 为输入整数制作一个文本框。
IntPopup 创建一个整数弹出选择字段。
IntSlider 制作一个滑动条,用户可以拖动来改变一个最小值和最大值之间的整数值。
LabelField 做一个标签字段。(用于显示只读信息。)
LayerField 做一个图层选择字段。
LongField 为输入长整数创建一个文本字段。
MaskField

制作一个面具的场地。

MinMaxSlider 制作一个特殊的滑块,用户可以使用它来指定最小值和最大值之间的范围。
ObjectField 制作一个字段来接收任何对象类型。
PasswordField 创建一个文本字段,用户可以输入密码。
Popup 创建一个通用的弹出选择字段。
PrefixLabel 在一些控制的前面做一个标签。
PropertyField 为串行化的属性创建一个字段。
RectField 创建一个X、Y、W和H字段来输入一个Rect。
RectIntField 做一个X,Y,W&H场,进入一个重新着色。
SelectableLabel 创建一个可选择的标签字段。(用于显示可以复制粘贴的只读信息)。
Slider 制作一个滑动条,用户可以拖动来改变一个最小值和最大值之间的值。
Space 在前面的控件和下面的控件之间留出一个小空间。
TagField 做一个标记选择字段。
TextArea 创建一个文本区域。
TextField 创建一个文本框。
Toggle 切换。
ToggleLeft 创建一个切换区域,其中的开关在左边,标签立即在它的右边。
Vector2Field 制作一个X&Y字段,用于输入矢量2。
Vector2IntField 创建一个X&Y整数字段来输入Vector2Int。
Vector3Field 制作一个X、Y&Z字段来输入一个矢量。
Vector3IntField 输入一个X、Y&Z整数字段来输入一个Vector3Int。
Vector4Field 做一个X、Y、Z&W字段,输入一个矢量图。


最终效果: 


Unity Editor 基础篇(二):自定义 Inspector 面板

准备工作: 
在Scripts文件夹里创建一个新C#脚本,命名”Player”,然后添加代码:

public class Player : MonoBehaviour {

    public int id;

    public string playerName;
    public string backStory;
    public float health;
    public float damage;

    public float weaponDamage1, weaponDamage2;

    public string shoeName;
    public int shoeSize;
    public string shoeType;

    void Start()
    {
        health = 50;
    }
}

Player 类记录了 Player 的一些基础信息,例如:ID、名字、背景故事、生命值、伤害等等。

常用的自定义Inspector界面布局属性:

现在在Editor文件夹中创建C#脚本:

using System.Collections;
using UnityEngine;
using UnityEditor;

//CustomEditor(typeof()) 用于关联你要自定义的脚本
[CustomEditor(typeof(Player))]
//必须要让该类继承自Editor,且不需要导入UnityEditor程序集
public class PlayerInspector : Editor {

    Player player;
    bool showWeapons;

    void OnEnable()
    {
        //获取当前编辑自定义Inspector的对象
        player = (Player)target;
    }

    //执行这一个函数来一个自定义检视面板
    public override void OnInspectorGUI()
    {
        //设置整个界面是以垂直方向来布局
        EditorGUILayout.BeginVertical();

        //空两行
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        //绘制palyer的基本信息
        EditorGUILayout.LabelField("Base Info");
        player.id = EditorGUILayout.IntField("Player ID",player.id);
        player.playerName = EditorGUILayout.TextField("PlayerName",player.playerName);

        //空三行
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        //绘制Player的背景故事
        EditorGUILayout.LabelField("Back Story");
        player.backStory = EditorGUILayout.TextArea(player.backStory,GUILayout.MinHeight(100));

        //空三行
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        //使用滑块绘制 Player 生命值
        player.health = EditorGUILayout.Slider("Health",player.health,0,100);

        //根据生命值设置生命条的背景颜色
        if(player.health<20){
            GUI.color = Color.red;
        }
        else if(player.health>80){
            GUI.color = Color.green;
        }
        else
        {
            GUI.color = Color.gray;
        }

        //指定生命值的宽高
        Rect progressRect = GUILayoutUtility.GetRect(50,50);

        //绘制生命条
        EditorGUI.ProgressBar(progressRect,player.health/100.0f,"Health");

        //用此处理,以防上面的颜色变化会影响到下面的颜色变化
        GUI.color = Color.white;

        //空三行
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        //使用滑块绘制伤害值
        player.damage = EditorGUILayout.Slider("Damage",player.damage,0,20);

        //根据伤害值的大小设置显示的类型和提示语
        if(player.damage<10){
            EditorGUILayout.HelpBox("伤害太低了吧!!", MessageType.Error);
        }
        else if(player.damage>15){
            EditorGUILayout.HelpBox("伤害有点高啊!!", MessageType.Warning);
        }
        else{
            EditorGUILayout.HelpBox("伤害适中!!", MessageType.Info);
        }

         //空三行
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        //设置内容折叠
        showWeapons=EditorGUILayout.Foldout(showWeapons,"Weapons");
        if(showWeapons){
            player.weaponDamage1=EditorGUILayout.FloatField("Weapon 1 Damage",player.weaponDamage1);
             player.weaponDamage2=EditorGUILayout.FloatField("Weapon 2 Damage",player.weaponDamage2);
        }

        //空三行
        EditorGUILayout.Space();
        EditorGUILayout.Space();
        EditorGUILayout.Space();

        //绘制鞋子信息
        EditorGUILayout.LabelField("Shoe");
        //以水平方向绘制
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.LabelField("Name",GUILayout.MaxWidth(50));
        player.shoeName=EditorGUILayout.TextField(player.shoeName);
        EditorGUILayout.LabelField("Size",GUILayout.MaxWidth(50));
        player.shoeSize=EditorGUILayout.IntField(player.shoeSize);
        EditorGUILayout.LabelField("Type",GUILayout.MaxWidth(50));
        player.shoeType=EditorGUILayout.TextField(player.shoeType);
        EditorGUILayout.EndHorizontal();

        EditorGUILayout.EndVertical();
    }
}

Okey,接下来一一分析一下,虽然已经上了备注。

1.Vertical-垂直布局 
默认的界面布局就是垂直布局,但是为了节目效果,我们还是把它写上比较好,设置元素为垂直布局需使用这对兄弟来声明:

EditorGUILayout.BeginVertical(); 
EditorGUILayout.EndVertical();

在这对兄弟里面做的布局都是以垂直方向来排列的。

Unity Editor 基础篇(二):自定义 Inspector 面板

如上图所示,整个页面元素都是以垂直方向来布局的。


2.Horizontal-水平布局

设置元素为水平布局需使用这对兄弟来声明:

EditorGUILayout.BeginHorizontal(); 
EditorGUILayout.EndHorizontal();

在这对兄弟里面做的布局都是以水平方向来排列的。

Unity Editor 基础篇(二):自定义 Inspector 面板

由于我们在上图圈选的地方使用了 Horizontal 这对兄弟,因此在这对兄弟里的元素全是以水平方向排列。


3.空行 
使用 EditorGUILayout.Space() 可在两个元素之间空出一行。

Unity Editor 基础篇(二):自定义 Inspector 面板


4.绘制各种类型字段 
绘制字段用到以下几个方法:

EditorGUILayout.LabelField()标签字段 
EditorGUILayout.IntField() 整数字段 
EditorGUILayout.FloatField() 浮点数字段 
EditorGUILayout.TextField() 文本字段 
EditorGUILayout.Vector2Field() 二维向量字段 
EditorGUILayout.Vector3Field() 三维向量字段 
EditorGUILayout.Vector4Field() 四维向量字段 
EditorGUILayout.ColorField() 颜色字段

它们的规律就是方法名都是以 Field 结尾,大伙们可以根据绘制的类型选择相对应的方法。 
一般括号里面的参数,第一个为绘制该字段的名字(string 类型),第二个为绘制该字段的值,如下所示: 
Unity Editor 基础篇(二):自定义 Inspector 面板

Unity Editor 基础篇(二):自定义 Inspector 面板

1 为标签字段 
2 为整形字段 
3 为文本字段 
4.为文本区域


5.滑块、进度条 
1.滑块:EditorGUILayout.Slider() 
制作一个滑动条用户可以拖动来改变值,在最小和最大值之间

static float Slider(float value,float leftValue,float rightValue,GUILayoutOptionp[] params options)

static float Slider(string label,float value,float leftValue,float rightValue,GUILayoutOptionp[] params options)

static float Slider(GUIContent label,float value,float leftValue,float rightValue,GUILayoutOptionp[] params options)

参数: 
label: 条目前面的可选标签 
value:编辑的值 
leftValue、rightValue:滑动条最左右的值 
options:指定额外布局属性的可选列表。这里传递任意值,将覆盖样式定义的设置。

Unity Editor 基础篇(二):自定义 Inspector 面板

EditorGUILayout.Slider()用于绘制一个滑块,从上可知:

第一个参数是滑块的名字 
第二个参数是滑块要改变的值 
第三和第四个参数是滑块的范围 
效果如下图所示: 

Unity Editor 基础篇(二):自定义 Inspector 面板

2/ 进度条:EditorGUI.ProgressBar() 
制作一个进度条

static void ProgressBar(Rect position,float value,string text)

参数: 
Position:屏幕上的矩形区域,用来总的这两者控制 
value:显示的值

Unity Editor 基础篇(二):自定义 Inspector 面板

Unity Editor 基础篇(二):自定义 Inspector 面板

EditorGUI.ProgressBar()用于绘制一个进度条,从上可知:

第一个参数是设置进度条的大小,类型是一个 Rect。 
第二个参数是设置显示的值, 
第三个参数是设置进度条的名字

提示: 
1.第一个参数,我们使用了 GUILayoutUtility.GetRect() 工具类的 GetRect()方法返回一个设置好的矩形框,在案例里我们设置了一个 50*50 大小的矩形框。

2.第二个参数,我们使用 player.health / 100.0f。那是因为进度条的最大值为1,如果不除100的话,当滑块的值为1时,进度条便填满了,因此我们想让值与进度条的比例同步,那就除100吧(语文不好,不知道解释得如何)。

效果图: 

Unity Editor 基础篇(二):自定义 Inspector 面板


6.帮助框 
帮助框:EditorGUILayout.HelpBox()

Unity Editor 基础篇(二):自定义 Inspector 面板

Unity Editor 基础篇(二):自定义 Inspector 面板

EditorGUILayout.HelpBox()用于绘制一个盒子(也可以看作矩形框),然后再盒子的里面显示提示信息,从上图可知:

第一个参数是传入提示信息 
第二个参数是提示信息的类型

效果图: 

Unity Editor 基础篇(二):自定义 Inspector 面板

Unity Editor 基础篇(二):自定义 Inspector 面板

Unity Editor 基础篇(二):自定义 Inspector 面板


6.灰色地带(禁用区域) 
EditorGUI.BeginDisabledGroup创建一组可以禁用(可见不可操作 )的绘制显示,为true时禁用 
EditorGUILayout.BeginToggleGroup开始带有开关按钮的一个垂直组,在这里立即启用或禁用控件。 
如:

private SerializedProperty m_EditorResourceMode = null;
EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode);
{
                m_EditorResourceMode.boolValue = EditorGUILayout.BeginToggleGroup("Editor Resource Mode", m_EditorResourceMode.boolValue);
                {
                    EditorGUILayout.HelpBox("Editor resource mode option is only for editor mode. Game Framework will use editor resource files, which you should validate first.", MessageType.Warning);
                    //EditorGUILayout.PropertyField(m_EditorLanguage);
                    EditorGUILayout.HelpBox("Editor language option is only use for localization test in editor mode.", MessageType.Info);
                }
                EditorGUILayout.EndToggleGroup();
}

效果: 
开关组控制 

Unity Editor 基础篇(二):自定义 Inspector 面板

 
禁用组绘制控制:(使用EditorApplication.isPlayingOrWillChangePlaymode来运行时禁用操作) 

Unity Editor 基础篇(二):自定义 Inspector 面板