zoukankan      html  css  js  c++  java
  • Unity 3D编辑器扩展介绍、教程(二) —— 创建窗口

    Unity编辑器扩展教程(二)


    本文提供全流程,中文翻译。

    Chinar坚持将简单的生活方式,带给世人!

    (拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例)




    此教程是在教程(一)基础上进行扩展:如果不知道如何创建编辑器按钮,推荐先看教程(一)

    Unity3D编辑器扩展介绍、教程 —— 创建菜单项(一)


    Brief Introduction —— 简介


    我们在做工程的时候,需要对数据进行操作。

    为节省时间,会使用一些快捷键,菜单栏上的功能、或是右键菜单

    这些便捷的功能,都是Unity官方为了方便我们对所需数据进行操作。

    对Unity编辑进行了一些封装处理,简化数据操作流程,封装为一个按钮/一个窗口/窗口功能。

    这些诸如此类的功能就是编辑器的扩展,和封装

    功能键、Inspector面板、Game视窗等等都是编辑器的功能


    注意:编辑器类脚本,必须放在 Assets/Editor 资源目录中

    此文件夹下的脚本只对编辑器进行操作。最后资源打包,Editor文件夹下的所有资源都不会被打包到工程中

    如果没有此文件夹,需自行创建:在Project视窗下,右键Create - - Folder

    举个栗子黑白88

    这里写图片描述

    这里写图片描述


    ScriptableWizard —— 脚本化向导


    ScriptableWizard 是一个编辑器类,继承自 EditorWindow

    从这个类派生来创建一个编辑器向导


    1

    - - DisplayWizard —— 显示器向导


    创建一个显示器向导,调用静态方法

    DisplayWizard <类型>(“标题”, “第一个按钮”, “第二个按钮”);

    即可创建一个 显示器向导

    举个栗子黑白88

    using UnityEditor; //引用Unity编辑器命名空间
    using UnityEngine; //引用Unity引擎命名空间
    
    
    /// <summary>
    /// 改变所有敌人脚本
    /// </summary>
    public class ChangeAll : ScriptableWizard
    {
        public int AddHp = 10; //每次增加血量值
        public int Num = 0;//一个数字为了测试 isValue
    
        /// <summary>
        /// 菜单栏 我的工具 中,创建一个按钮
        /// </summary>
        [MenuItem("我的工具/修改所有敌人属性")]
        static void 修改所有敌人属性()
        {
            //显示器向导 <所管控的类>( 窗口的名字,窗口中按钮的名字,第二个按钮的名字 );
            DisplayWizard<ChangeAll>("修改所有敌人血量", "确认修改血量", "第二个按钮");
        }
    }

    这里写图片描述


    2

    - - ScriptableWizard Messages Sent —— 脚本化向导的信息传递


    其中内置了一些固定函数,用来传递信息

    OnEnable() —————————————————– 脚本有效时就会执行

    OnWizardCreate() ————————————— 在 创建 / 第一个 按钮上点击时调用

    OnWizardOtherButton() ————————— 在 其他 按钮上点击时调用(允许一个动作)

    OnWizardUpdate() ————————————– 在向导被打开 / 向导中数据发生变化时被调用

    OnSelectionChange() ——————————— 当选择发生改变,调用此函数
    (此函数在EditorWindow中,而ScriptableWizard继承自EditorWindow,所以可以在其中直接调用)
    举个栗子黑白88

    using UnityEditor; //引用Unity编辑器命名空间
    using UnityEngine; //引用Unity引擎命名空间
    
    
    /// <summary>
    /// 改变所有敌人脚本
    /// </summary>
    public class ChangeAll : ScriptableWizard
    {
        public int AddHp = 10; //每次增加血量值
        public int Num   = 0;  //一个数字为了测试 isValue
    
    
        /// <summary>
        /// 菜单栏 我的工具 中,创建一个按钮
        /// </summary>
        [MenuItem("我的工具/修改所有敌人属性")]
        static void 修改所有敌人属性()
        {
            //显示器向导 <所管控的类>( 窗口的名字,窗口中按钮的名字,第二个按钮的名字 );
            DisplayWizard<ChangeAll>("修改所有敌人血量", "确认修改血量", "第二个按钮");
        }
    
    
        /// <summary>
        /// 固定函数名:窗口开始时执行
        /// </summary>
        void OnEnable()
        {
            AddHp = EditorPrefs.GetInt("ChangeAll_health", AddHp); //取值,默认为初始值   并赋值给AddHp
        }
    
    
        /// <summary>
        /// 固定函数名:对应现实向导中的第一个按钮 —— 确认修改血量
        /// </summary>
        void OnWizardCreate()
        {
            //进度条
            EditorUtility.DisplayProgressBar("修改进度", "0/" + Selection.gameObjects.Length + "完成修改", 1);
            int count = 0;
    
            foreach (var gameObject in Selection.gameObjects) //遍历选中的物体
            {
                CompleteProject.EnemyHealth health = gameObject.GetComponent<CompleteProject.EnemyHealth>(); //获取其身上脚本组件
                Undo.RecordObject(health, "Change health");                                                  //记录变量 health 之后做的更改
                health.startingHealth += AddHp;                                                              //自增 设置的值   //需要修改其他属性,自己往下写
    
                count++;
                //进度条
                EditorUtility.DisplayProgressBar("修改进度", count + "/" + Selection.gameObjects.Length + "完成修改", progress: count / Selection.gameObjects.Length);
            }
            EditorUtility.ClearProgressBar();//清除进度条
        }
    
    
        /// <summary>
        /// 固定函数名:对应现实向导中的第二按钮 —— 第二个按钮
        /// </summary>
        void OnWizardOtherButton()
        {
            //弹出通知(新建一个 GUI内容(被选中物体的个数)+“字符” )
            ShowNotification(new GUIContent(Selection.gameObjects.Length + "个元素被选中"));
        }
    
    
        /// <summary>
        /// 当属性值被修改时,每帧调用。 /  当界面开启时,会调用一次
        /// </summary>
        void OnWizardUpdate()
        {
            helpString  = null; //每次调用就归零一次,否则会出现字体不消除的情况
            errorString = null;
    
            if (Selection.gameObjects.Length > 0)
            {
                helpString = "当前选择了" + Selection.gameObjects.Length + "个敌人"; //及时更新选择的数量
            }
            else
            {
                errorString = "最少选择一个啊"; //错误提示
            }
    
            EditorPrefs.SetInt("ChangeAll_health", AddHp); //修改后存入一个值,就是记录一下。
        }
    
    
        /// <summary>
        /// 当选择的物体发生改变,调用此函数
        /// </summary>
        void OnSelectionChange()
        {
            OnWizardUpdate();
        }
    }

    这里写图片描述


    3

    - - DisplayProgressBar —— 进度条


    在显示器向导中创建一个进度条

    EditorUtility.DisplayProgressBar( 进度条标题,进度信息,进度比例 )

    EditorUtility.ClearProgressBar() 调用此函数,进度条才会被删除
    举个栗子黑白88

    using UnityEditor; //引用Unity编辑器命名空间
    using UnityEngine; //引用Unity引擎命名空间
    
    
    /// <summary>
    /// 改变所有敌人脚本
    /// </summary>
    public class ChangeAll : ScriptableWizard
    {
        public int AddHp = 10; //每次增加血量值
        public int Num   = 0;  //一个数字为了测试 isValue
    
    
        /// <summary>
        /// 菜单栏 我的工具 中,创建一个按钮
        /// </summary>
        [MenuItem("我的工具/修改所有敌人属性")]
        static void 修改所有敌人属性()
        {
            //显示器向导 <所管控的类>( 窗口的名字,窗口中按钮的名字,第二个按钮的名字 );
            DisplayWizard<ChangeAll>("修改所有敌人血量", "确认修改血量", "第二个按钮");
        }
    
    
        /// <summary>
        /// 固定函数名:对应现实向导中的第二按钮 —— 第二个按钮
        /// </summary>
        void OnWizardOtherButton()
        {
            EditorUtility.DisplayProgressBar("修改进度", "0/" + Selection.gameObjects.Length + "完成修改", 1); //进度条
            int count = 0;                                                                             //计数
            foreach (var gameObject in Selection.gameObjects)                                          //遍历选中的物体
            {
                CompleteProject.EnemyHealth health = gameObject.GetComponent<CompleteProject.EnemyHealth>();                                         //获取其身上脚本组件
                Undo.RecordObject(health, "Change health");                                                                                          //记录变量 health 之后做的更改
                health.startingHealth += AddHp;                                                                                                      //自增 设置的值   //需要修改其他属性,自己往下写
                count++;                                                                                                                             //计数自增1
                EditorUtility.DisplayProgressBar("修改进度", count + "/" + Selection.gameObjects.Length + "完成修改", count / Selection.gameObjects.Length); //进度条
            }
    
            //EditorUtility.ClearProgressBar(); //清除进度条(只有调用此方法,进度条才会删除)
        }
    }

    这里写图片描述


    EditorWindow —— 编辑器窗口


    创建一个编辑器窗口,在我们的Unity编辑器中

    GetWindow(bool, 窗口名字)

    bool 值为: false 窗口可以与其他窗口合并
    bool 值为: true 窗口独立,不可合并

    以下是我写的一个简单的梨子,用于批量修改物体的名称(选择物体内数组,并没有进行内部处理)
    举个栗子黑白88

    using UnityEditor; //引用Unity编辑器命名空间
    using UnityEngine; //引用Unity引擎命名空间
    
    
    /// <summary>
    /// 创建一个窗口类
    /// </summary>
    public class ChinarWindow : EditorWindow//继承自 EditorWindow
    {
        string      CustomName = "CustomName"; //自定义名字
        private int ChinarNum  = 0;            //空物体数量
    
    
        /// <summary>
        /// 创建一个菜单项
        /// </summary>
        [MenuItem("我的工具/显示新窗口")]
        static void 显示新窗口()
        {
            ChinarWindow chinar = GetWindow<ChinarWindow>(false, "Chinar窗口"); //获取到一个窗口,赋值给当前编辑器类的对象
            chinar.Show();                                                    //显示对象的窗口
        }
    
    
        /// <summary>
        /// 此函数中实现编辑器界面的定义/绘制
        /// </summary>
        void OnGUI()
        {
            GUILayout.Label("这是Chianr窗口");                                     //标题
            CustomName = GUILayout.TextField(CustomName);                      //文本框
            ChinarNum  = int.Parse(GUILayout.TextField(ChinarNum.ToString())); //数字框
    
            //可以直接判断按钮的点击
            if (GUILayout.Button("修改所有物体名字"))
            {
                for (int i = 0; i < Selection.transforms.Length; i++) //遍历选中的元素
                {
                    Undo.RecordObjects(Selection.gameObjects as GameObject[], "ChinarWindow_GameObject[]"); //Selection.gameObjects 返回一个GameObject[] ,并记录键(用于回退)
                    Selection.transforms[i].SetSiblingIndex(i);                                             //为选择的物体设置下标
                    Selection.transforms[i].name = CustomName + i;                                          //设置名字+i
                }
            }
    
            //判断按钮的点击
            if (GUILayout.Button("创建多个空物体"))
            {
                if (ChinarNum <= 0) //如果数字 小于等于 0
                {
                    ShowNotification(new GUIContent("请写入创建空物体数量")); //提示 输入
                }
                else //不为0
                {
                    for (int i = 0; i < ChinarNum; i++) //遍历个数
                    {
                        Undo.RegisterCreatedObjectUndo(new GameObject(CustomName), "Chinar Create gameobject"); //创建一个名为 CustomName 的空物体
                    }
                }
            }
        }
    }

    仔细看


    END

    本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

    对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com

    对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址

  • 相关阅读:
    软件工程课件
    团队博客作业Week1
    IntelliJ IDEA下Git的配置与使用(命令行下)
    Java语言程序设计课程学期总结
    JDBC访问数据库的一些小技巧
    Conference-Web Search and Data Mining
    线程停止与volatile
    班会-2016-2017第2学期
    Java第11次实验(JDBC数据库编程)
    Python-Jupyter Notebook使用技巧
  • 原文地址:https://www.cnblogs.com/chinarbolg/p/9601459.html
Copyright © 2011-2022 走看看