Unity高级开发(一)-编辑器开发:2020更新

正所谓:人靠衣装,佛靠金装。学会插件开发,成就大神人生。

  • 欢迎关注公众号:雷潮课堂


    Unity高级开发(一)-编辑器开发:2020更新_第1张图片
    公众号二维码.jpg

编辑器开发

一、课程内容

1-1本课程目标
1-2插件开发的起因
1-3插件的作用

二、菜单项制作

2-1菜单项(MenuItem)
2-2组件菜单(AddComponentMenu)
2-3上下文菜单(ContextMenu)
2-4必要组件菜单(RequireComponent)

三、自定义InsPector界面

3-1属性相关标识(HideInInspector,SerializeField,NonSerialized,Serializable)
3-2自定义界面属性 (CustomEditor)
3-3自定序列化属性字段 (PropertyField)

四、 自定义操作界面(Window)

4-1界面的生命周期(事件)
4-2文本颜色字段,标签字段,数字输入字段,滑动条,位置大小输入字段,选择字段,标签、层、对象选择字段,单选字段,分组字段,其他字段

1-1本课程目标

学会自定义编辑器,开发一款属于自己的编辑器插件

1-2插件开发的起因

如果一个模型师想要在Unity中查看效果,但是她又是程序小白,作为公司一员应该给到她非常好帮助,比如制作一套工具集合(插件),让她根本离不开你。

1-3插件的作用

帮助企业建立技术护城河,提高开发效率,减少沟通成本,减少工作。

2-1菜单项

Asset目录下新建一个Editor文件夹,新建MyEditor脚本

using UnityEngine;
using UnityEditor; // 引用命名空间

public class MyEditor : Editor   // 继承Editor类
{
    // 添加工具栏并设置创建方块方法 (false)显示出来
    [MenuItem("工具/创建方块, &_f",false)]  // % Ctrl  & Alt # Shift
    public static void CreatCube()
    {   
        GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.name = "方块";
    }
  
    // 用来处理编辑器的问题(Update)  
    private void OnSceneGUI()
    {     
        if (Input.GetKeyDown(KeyCode.F) && Input.GetKeyDown(KeyCode.LeftAlt))
        {
            CreatCube();
        }
    }
  • 效果图:


    Unity高级开发(一)-编辑器开发:2020更新_第2张图片
    创建方块

    Unity高级开发(一)-编辑器开发:2020更新_第3张图片
    详细图
  • 注意

OnSceneGUI方法中主要使用Handles系列来绘制可视化调试控件,比如线、盒子、球体、文本等(可以自行操作)

private void OnSceneGUI()
{
  Handles.color = Color.green;
}
  • 2-1-1多级菜单:


    多级菜单

    详细图
using UnityEngine;
using UnityEditor; // 引用命名空间

public class MyEditor : Editor   // 继承Editor类
{
    public static GameObject cube;
    // 添加工具栏并设置创建方块方法 (false)显示出来
    [MenuItem("工具/创建方块, &_f",false)]  // # Ctrl  & Alt
    public static void CreatCube()
    {   
        cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
        cube.name = "方块";
    }

    // 添加工具栏并设置创建方块方法 (false)显示出来
    [MenuItem("工具/销毁方块, &_G", false)]  // # 表示Ctrl  & 表示Alt
    public static void DestroyCube()
    {
        if (cube == null)
        {
            cube = GameObject.Find("方块");
        }
        Editor.Destroy(cube);
    }

    // 用来处理编辑器的问题(Scene绘制图形方法类似Update)
    private void OnSceneGUI()
    {
        Handles.color = Color.green;
        if (Input.GetKeyDown(KeyCode.F) && Input.GetKeyDown(KeyCode.LeftAlt))
        {
            CreatCube();
        }
        if (Input.GetKeyDown(KeyCode.G) && Input.GetKeyDown(KeyCode.LeftAlt))
        {
            DestroyCube();
        }
    }
}
2-2组件菜单(AddComponentMenu)
using UnityEngine;
//给Component菜单下增加One子菜单,并将TestOne类添加到对象上
[AddComponentMenu("One",1)]  
public class TestOne : MonoBehaviour
{
}
Unity高级开发(一)-编辑器开发:2020更新_第4张图片
one子菜单
Unity高级开发(一)-编辑器开发:2020更新_第5张图片
选中物体后,点击one子菜单即可添加Test one脚本
2-3上下文菜单(ContextMenu)

在面板中右键出现的菜单


Unity高级开发(一)-编辑器开发:2020更新_第6张图片
Inspector面板中右键出现
public class TestOne : MonoBehaviour
{
    [ContextMenu("测试")]
    public void Test()
    {
        Debug.Log("123");
    }
}
2-4必要组件菜单(RequireComponent)
Unity高级开发(一)-编辑器开发:2020更新_第7张图片
添加某个组件必须要有其他组件
using UnityEngine;

[RequireComponent(typeof(Rigidbody))] // 添加组件必须要加上刚体
//给Component菜单下增加One子菜单,并将TestOne类添加到对象上
[AddComponentMenu("One",1)]  
public class TestOne : MonoBehaviour
{

}
3-1属性相关标识
  • 隐藏属性显示 (HideInInspector)
  • 不显示的属性(SerializeField)
  • 关键字序列化(Serializable) (针对类,结构体,枚举,委托有效)
  • 不会被序列(NonSerialized)
using System;
using UnityEngine;

[Serializable] // 可以使类显示在视图面板
public enum MyColor
{
    red,
    green,
    blue
}
public class TestOne : MonoBehaviour
{
    [HideInInspector]
    public int age; //  将显示的属性隐藏
    [SerializeField]
    private float height; // 显示隐藏的属性
    [NonSerialized]
    public Vector3 v = new Vector3(10, 0, 0); // 防止变量序列化
    public MyColor c;
}
3-2自定义界面属性
  • 自定义显示面板(CustomEditor)

我们添加系统组件的时候,发现面板很好看,而脚本做不到这种效果。这里就需要自定义显示面板,如下图所示:


Unity高级开发(一)-编辑器开发:2020更新_第8张图片
针对BoxCollider自定义面板
using UnityEngine;
using UnityEditor;// 引用命名空间

// CustomEditor是对应标识的组件脚本
[CustomEditor(typeof(BoxCollider))] // 设置自定义BoxCollider的内容
public class MyInsPectorTest : Editor // 继承Editor类
{
    private bool b;
    private string s = "";
    private string m;

    // 重写Editor 绘制面板图形界面方法
    public override void OnInspectorGUI() 
    {
        // 当我们使用自动布局技术的时候,就不要混合使用GUI.Lable,以免产生不必要的约束问题 
        GUILayout.Label("雷潮");
        b = GUILayout.Toggle(b,"关闭音效");
        GUILayout.Label("请输入账号");
        s = GUILayout.TextField(s);
        GUILayout.Label("请输入密码");
        m = GUILayout.PasswordField(m,'*'); // 后面是占位符,将密码字符更替为*
       
        if (GUILayout.Button("登录"))
        {
            if (s == "leichao" && m == "123456")
            {
                Debug.Log("登录成功");
            }
            else
            {
                Debug.Log("账号或者密码错误");
            }
        }
    }
}
3-3自定序列化属性字段 (PropertyField)

命名空间在UnityEditor
SerializedObject 序列化对象 请点击查看序列化对象类
SerializedProperty 序列化属性 请点击查看序列化属性类

using System;
using UnityEngine;

[Serializable] // 可以使类显示在视图面板
public enum MyColor
{
    red,
    green,
    blue
}
public class TestOne : MonoBehaviour
{
    public int age; 
    public float height;
    public Vector3 v = new Vector3(10, 0, 0);
    public MyColor c;
}
using UnityEditor;

[CustomEditor(typeof(TestOne))]
public class Test1 : Editor
{
    public SerializedObject mObj;
    public SerializedProperty mAge;
    public SerializedProperty mHeight;
    public SerializedProperty mVector;
    public SerializedProperty mColor;

    private void OnEnable()
    {
        mObj = new SerializedObject(target); // 创建一个目标,即挂载脚本物体
        mAge = this.mObj.FindProperty("age");
        mHeight = this.mObj.FindProperty("height");
        mVector = this.mObj.FindProperty("v");
        mColor = this.mObj.FindProperty("c");
    }
    public override void OnInspectorGUI()
    {
        this.mObj.Update();
        EditorGUILayout.PropertyField(this.mAge);
        EditorGUILayout.PropertyField(this.mHeight);
        EditorGUILayout.PropertyField(this.mVector);
        EditorGUILayout.PropertyField(this.mColor, true);
    }
}
4.自定义窗口菜单
4-1自定义窗口
Unity高级开发(一)-编辑器开发:2020更新_第9张图片
自定义Window
using UnityEngine;
using UnityEditor;

public class MyWindow :EditorWindow
{
    private bool b;
    private string s;
    private string m;
    private Color c = Color.white;
    private string t;

    [MenuItem("Tools/Window")]
    public static void ShowW()
    {
        EditorWindow.GetWindow().Show();
    }

    private void OnGUI()
    {
        // 编辑MyWindow
        EditorGUILayout.LabelField("雷潮邀请你输入");
        EditorGUILayout.Space(); // 隔开一行
      
        EditorGUILayout.LabelField("请输入账号");
        s = EditorGUILayout.TextField(s);
     
        EditorGUILayout.SelectableLabel("请输入密码");
        s = EditorGUILayout.PasswordField(s);
      
        EditorGUILayout.Space(); // 隔开一行
        EditorGUILayout.LabelField("请选择颜色");
        this.c = EditorGUILayout.ColorField(c);

        EditorGUILayout.Space(); // 隔开一行
        EditorGUILayout.LabelField("请输入你要提交的信息");
        this.t = EditorGUILayout.TextArea(this.t); // 文本区域可以空格换行输入

        b = GUILayout.Toggle(b, "记住账号");
        b = GUILayout.Toggle(b, "记住密码");
    }

}
  • 另一种显示窗口的方法
[MenuItem("Tools/Window")]
public static void ShowW()
{
      // 无法关闭
      MyWindow.CreateInstance().ShowPopup();
}
  • 填充更多内容
Unity高级开发(一)-编辑器开发:2020更新_第10张图片
3.png
Unity高级开发(一)-编辑器开发:2020更新_第11张图片
4.png
4-2界面的生命周期(事件)
public class WindowEditorLife : EditorWindow
{
    [MenuItem("Window/MyWindow")]
    public static void CreatWindow()
    {
        EditorWindow.GetWindow().Show();
    }
    private void OnEnable() // 当窗口可用时
    {
        Debug.Log("OnEnable ==== 1");
    }
    private void OnFocus() // 当鼠标在窗口中,获得焦点时,调用一次
    {
        Debug.Log("OnFocus ==== 2");
    }
   private void Update()
    {
        Debug.Log("所有可见窗口上每帧调用");
    }
    private void OnLostFocus() // 失去焦点时调用
    {
        Debug.Log("OnLostFocus");
    }
    private void OnGUI() // 绘制图形
    {
        Debug.Log("绘制图形");
        if (GUILayout.Button("关闭窗口"))
        {
            this.Close();
        }
    }
    private void OnDisable() // 窗口不可用的时候调用
    {
        Debug.Log("OnDisable");
    }
    private void OnDestroy()  // 销毁的时候调用
    {
        Debug.Log("OnDestroy");
    }
    private void OnHierarchyChange() // 当场景层次面板发生改变的时候调用
    {
        Debug.Log("OnHierarchyChange");
    }
    private void OnValidate() // 当脚本被加载或者检视面板值备修改的时候调用
    {
        Debug.Log("OnValidate");
    }
    private void OnProjectChange() // 当工程目录更新时调用(有资源变动)
    {
        Debug.Log("OnProjectChange");
    }
    private void OnSelectionChange() // 当在窗口选中某个物体时
    {
        Debug.Log("OnSelectionChange"); 
    }
    private void OnInspectorUpdate()  // 窗口的更新调用,每秒10次
    {
        Debug.Log("OnInspectorUpdate");
    }
4-3界面的属性字段
  • 滚动条

EditorGUILayout.Slider(...) 浮点数滚动条
EditorGUILayout.IntSlider(...)整数滚动条
EditorGUILayout.MinMaxSlider(...) 最小最大滚动条

  • 输入框

EditorGUILayout.TextField(string) 文本输入框
EditorGUILayout.TextArea(string); 可换行的文本输入框
EditorGUILayout.PasswordField(string); 文本输入框
EditorGUILayout.ColorField(Color); 颜色输入框
EditorGUILayout.IntField(int); 整数输入
EditorGUILayout.FloatField(float); 浮点数输入
EditorGUILayout.CurveField(string,objec) // 动画曲线输入
EditorGUILayout.ObjectField(objec,typeof()) // 获取选择的物体,后面可以限制选择的物体类型
EditorGUILayout.InspectorTitlebar(bool,object) // 选择的物体放在面板


  • 向量

EditorGUILayout.RectFiled(Rect); 矩阵
EditorGUILayout.BoundsFiled();距离
EditorGUILayout.Vector2Field(string, Vector2) 二维坐标
EditorGUILayout.Vector3Field(string,Vector3); 三维坐标
EditorGuILayout.Vector4Field(string,Vector4);四维坐标

  • 下拉菜单

EditorGUILayout.Popup(int, string[]); 字符串选择,返回字符串数组下标
EditorGUILayout.IntPopup(int,int[],string[]) 字符串选择,返回字符串对应下标的整形数组值
EditorGUILayout.EnumPopup(Enum) 枚举选择,返回枚举

  • 标签、层、对象

EditorGUILayout.TagField(this.t);
EditorGUILayout.LayerField(this.layer);
EditorGUILayout.ObjectField(this.mObj, typeof(BoxCollider));

  • 布局分组
  • 水平分组
    EditorGUILayout.BeginHorizontal();
    EditorGUILayout.EndHorizontal();
  • 垂直分组
    EditorGUILayout.BeginVertical();
    EditorGUILayout.EndVertical();
  • Toggle分组
    EditorGUILayout.BeginToggleGroup("选择分组",this.mbool);
    EditorGUILayout.EndToggleGroup();
  • 滚动分组
    EditorGUILayout.BeginScrollView(this.mPos);
    EditorGUILayout.EndScrollView();
  • 展开

EditorGUILayout.Foldout(bool,string)

5总结:

顶部编辑器菜单:引用using UnityEditor; 使用[MenuItem()];
Inspector面板的处理:继承Editor,重写虚方法:OnInspectorGUI(),并调用(父类的此方法)base.OnInspectorGUI()
窗口的面板:继承:EditorWindow, 使用EditorWindow.GetWindow(); 调用窗口的Show()方法。

  • 欢迎购买本课程:

腾讯课堂


Unity高级开发(一)-编辑器开发:2020更新_第12张图片
腾讯课堂

Unity高级开发(一)-编辑器开发:2020更新_第13张图片
微信小程序

网易云课堂


Unity高级开发(一)-编辑器开发:2020更新_第14张图片
网易云课堂

你可能感兴趣的:(Unity高级开发(一)-编辑器开发:2020更新)