Unity 3D編輯器擴展介紹、教程(二) —— 建立窗口

Unity編輯器擴展教程(二)


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

Chinar堅持將簡單的生活方式,帶給世人!

(擁有更好的閱讀體驗 —— 高分辨率用戶請根據需求調整網頁縮放比例)




此教程是在教程(一)基礎上進行擴展:若是不知道如何建立編輯器按鈕,推薦先看教程(一) 數組

Unity3D編輯器擴展介紹、教程 —— 建立菜單項(一)編輯器


Brief Introduction —— 簡介


咱們在作工程的時候,須要對數據進行操做。函數

爲節省時間,會使用一些快捷鍵,菜單欄上的功能、或是右鍵菜單 工具

這些便捷的功能,都是Unity官方爲了方便咱們對所需數據進行操做。測試

對Unity編輯進行了一些封裝處理,簡化數據操做流程,封裝爲一個按鈕/一個窗口/窗口功能。字體

這些諸如此類的功能就是編輯器的擴展,和封裝spa

功能鍵、Inspector面板、Game視窗等等都是編輯器的功能


注意:編輯器類腳本,必須放在 Assets/Editor 資源目錄中 .net

此文件夾下的腳本只對編輯器進行操做。最後資源打包,Editor文件夾下的全部資源都不會被打包到工程中 翻譯

若是沒有此文件夾,需自行建立:在Project視窗下,右鍵Create - - Folder 3d

舉個栗子黑白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 對於經本博主明確受權和許可以使用文章及內容的,使用時請註明文章或內容出處並註明網址

相關文章
相關標籤/搜索