Unity 3D編輯器擴充套件介紹、教程(一) —— 建立選單項

weixin_34115824發表於2018-02-16

Unity編輯器擴充套件教程


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

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

(擁有更好的閱讀體驗 —— 高解析度使用者請根據需求調整網頁縮放比例)




Brief Introduction —— 簡介


我們在做工程的時候,需要對資料進行操作。

為節省時間,會使用一些快捷鍵,選單欄上的功能、或是右鍵選單

這些便捷的功能,都是Unity官方為了方便我們對所需資料進行操作。

對Unity編輯進行了一些封裝處理,簡化資料操作流程,封裝為一個按鈕/一個視窗/視窗功能。

這些諸如此類的功能就是編輯器的擴充套件,和封裝

功能鍵、Inspector皮膚、Game視窗等等都是編輯器的功能


注意:編輯器類指令碼,必須放在 Assets/Editor 資源目錄中

此資料夾下的指令碼只對編輯器進行操作。最後資源打包,Editor資料夾下的所有資源都不會被打包到工程中

如果沒有此資料夾,需自行建立:在Project視窗下,右鍵Create - - Folder

舉個例子黑白88

這裡寫圖片描述

這裡寫圖片描述


Create MenuItem —— 建立選單項


主要使用:靜態方法

MenuItem (itemName : string, isValidateFunction : bool, priority : int)


1

- - Create Level 1 Menu —— 建立一級選單


在選單欄上建立一個選單項,並建立一個一級選單按鈕

注意:編輯器類指令碼,必須放在 Assets/Editor 資源目錄中

此資料夾下的指令碼只對編輯器進行操作。最後資源打包,Editor資料夾下的所有資源都不會被打包到工程中

如果沒有此資料夾,需自行建立:在Project視窗下,右鍵Create - - Folder

舉個例子黑白88

using UnityEditor; //引用Unity編輯器名稱空間
using UnityEngine; //引用Unity引擎名稱空間


/// <summary>
/// 建立一個指令碼工具類
/// </summary>
public class Tools//指令碼無需繼承自MonoBehaviour
{
    /// <summary>
    /// 建立新的選單項
    /// </summary>
    /// //在選單欄中建立一個 我的工具 選單專案,並生成一個 “一級選項” 的按鈕:需要對應一個靜態方法(名字最好保持一致,不一致也可),方法體自由定義
    [MenuItem("我的工具/一級選項")] //選單項(“選單欄名稱/子類名稱”)—— 經過測試可為中文
    static void 一級選項()      //必須設定成靜態方法 —— 經過測試,亦可為中文
    {
        Debug.Log(111);
    }
}

會有生成一個 一級選項 的按鈕,點選後列印“111”
這裡寫圖片描述


2

- - Create Level 2 Menu —— 建立二級選單


在選單欄上建立一個選單項,並建立一個二級選單按鈕

舉個例子黑白88

using UnityEditor; //引用Unity編輯器名稱空間
using UnityEngine; //引用Unity引擎名稱空間


/// <summary>
/// 建立一個指令碼工具類
/// </summary>
public class Tools//指令碼無需繼承自MonoBehaviour
{
    /// <summary>
    /// 建立二級選單項
    /// </summary>
    /// //在選單欄中建立一個 我的工具 選單專案,並生成一個 “二級選項” 的按鈕:需要對應一個靜態方法(名字最好保持一致,不一致也可),方法體自由定義
    [MenuItem("我的工具/一級選項/二級選項")]    //選單項(“選單欄名稱/子類名稱”)—— 經過測試可為中文
    static void 二級選項() //必須設定成靜態方法 —— 經過測試,亦可為中文
    {
        Debug.Log(222);
    }
}

會有生成一個 二級選項 的按鈕,點選後列印“222”
這裡寫圖片描述


3

- - Create Level 2 Menu in System Menu —— 在系統選單中建立二級選單


在系統選單 Edit 中建立二級選單

舉個例子黑白88

using UnityEditor; //引用Unity編輯器名稱空間
using UnityEngine; //引用Unity引擎名稱空間


/// <summary>
/// 建立一個指令碼工具類
/// </summary>
public class Tools//指令碼無需繼承自MonoBehaviour
{
    /// <summary>
    /// 在系統預設的選單項中,建立子按鈕
    /// </summary>
    /// //在系統預設選單項 Edit 中建立按鈕:(名字最好保持一致,不一致也可)
    [MenuItem("Edit/一級選項/二級選項2")]    
    static void 二級選項2() 
    {
        Debug.Log(333);
    }
}

Edit 中最下方,會有生成一個 二級選項2 的按鈕,點選後列印“333”
這裡寫圖片描述


4

- - Menu grouping —— 選單分組


完成選單的分組,例如系統中的多個選單項分組管理

靜態方法 MenuItem (itemName : string, isValidateFunction : bool, priority : int)


MenuItem (表示選單項:就是路徑名 , 驗證函式 : 同名的按鈕在選單函式呼叫之前呼叫 , 優先順序:用來管理選單項的層級關係)

注意: Priority 優先順序如果設定為:-1 ,那麼必然是在第一個

舉個例子黑白88

using UnityEditor; //引用Unity編輯器名稱空間
using UnityEngine; //引用Unity引擎名稱空間


/// <summary>
/// 建立一個指令碼工具類
/// </summary>
public class Tools//指令碼無需繼承自MonoBehaviour
{
    /// <summary>
    /// 選單分組 —— 層級10
    /// </summary>
    /// //每個選單欄的 priority 屬性:優先順序預設為1000。相差 11 可以分為另一個組。也就是大於10就另建一組
    [MenuItem("按鈕/功能1", false, 10)] 
    static void 功能1()
    {
        Debug.Log("功能1");
    }

    /// <summary>
    /// 選單分組 —— 層級:如果不填,系統預設為1000,所以排序在最後
    /// </summary>
    [MenuItem("按鈕/功能2")]
    static void 功能2()
    {
        Debug.Log("功能2");
    }


    /// <summary>
    /// 選單分組 —— 層級:21
    /// </summary>
    /// //與按鈕1的層級10,相差11,故而分到了另一組中
    [MenuItem("按鈕/功能3", false, 21)]
    static void 功能3()
    {
        Debug.Log("功能3");
    }
}

選單欄會有生成一個 功能 的選單項,其中有:功能1/3/2。點選後分別列印“1/3/2”
這裡寫圖片描述


5

- - Menu display and hide. —— 選單的顯示和隱藏


完成選單的顯示和隱藏,有些時候選單項是灰色,不可用狀態/可用狀態

靜態方法 MenuItem (itemName : string, isValidateFunction : bool, priority : int)


驗證函式 isValidateFunction 值為 true 時,此驗證函式下的函式方法,會在選單函式之前呼叫

滿足條件,則按鈕顯示/否則隱藏

注意: Hierarchy 皮膚中,右鍵選單是 選單欄裡 GameObject 的選單項。

所以在 GameObject 選單欄中建立一個按鈕,並且優先順序設定到第一組中,即可在 Hierarchy 的右鍵選單中顯示 該按鈕

注意: Priority 優先順序如果設定為:-1 ,那麼必然是在第一個
舉個例子黑白88

using UnityEditor; //引用Unity編輯器名稱空間
using UnityEngine; //引用Unity引擎名稱空間


/// <summary>
/// 建立一個指令碼工具類
/// </summary>
public class Tools//指令碼無需繼承自MonoBehaviour
{
    /// <summary>
    /// 驗證“刪除物體”按鈕的 顯示/隱藏
    /// </summary>
    [MenuItem("GameObject/刪除物體", true, -1)]
    static bool 刪除物體Alternative()
    {
        if (Selection.objects.Length > 0)//如果選擇了物體
        {
            return true;//就返回真:按鈕可用
        }
        else//否則
        {
            return false;//返回假:按鈕不可用
        }
    }


    /// <summary>
    /// 在系統預設的選單項 GameObject 中,建立 刪除物體 按鈕,優先順序第一個
    /// </summary>
    [MenuItem("GameObject/刪除物體", false, -1)]
    static void 刪除物體()
    {
        //Selection.objects 返回值是一個 Object陣列,就是選中的所有物體
        foreach (var o in Selection.objects) //遍歷選中的所有物體
        {
            //GameObject.DestroyImmediate(o);//直接刪除,但是無法撤銷
            Undo.DestroyObjectImmediate(o); //直接刪除,但是可以撤銷(用Ctrl+z)//Immediate:直接的,立即的
        }
    }
}

選單欄 GameObject 會有生成一個 刪除物體 的選單項

如果選了物體,按鈕可用

否則不可用
這裡寫圖片描述


6

- - Shortcuts —— 快捷鍵


完成對選單專案的快捷鍵設定

靜態方法 MenuItem (itemName : string)


引數 itemName 為字串,表示選單項。+ 空格 + _O)就表示快捷鍵設為 O 鍵,不區分大小寫
引數 itemName 為字串,表示選單項。+ 空格 + %l)就表示組合鍵設為 Ctrl+L 鍵,不區分大小寫

注意:名字和快捷鍵中間必須要有空格

組合鍵: % : Ctrl
組合鍵: # : Shift
組合鍵: & : Altl
舉個例子黑白88

using UnityEditor; //引用Unity編輯器名稱空間
using UnityEngine; //引用Unity引擎名稱空間


/// <summary>
/// 建立一個指令碼工具類
/// </summary>
public class Tools//指令碼無需繼承自MonoBehaviour
{
       /// <summary>
    /// 快捷鍵測試
    /// </summary>
    [MenuItem("我的工具/快捷鍵測試 _o")]//_o 是指定快捷鍵 O ,並不區分大小寫 (名字和快捷鍵中間必須要有空格)
    static void 選中物體個數()
    {
        Debug.Log("快捷鍵"+Selection.objects.Length);//列印選中物體的個數
    }


    /// <summary>
    /// 在系統預設的選單項中,建立子按鈕
    /// </summary>
    /// % : Ctrl
    /// # : Shift
    /// & : Alt
    [MenuItem("我的工具/組合鍵測試 %l")] //%l 是指定組合鍵:Ctrl+L,並不區分大小寫 (名字和快捷鍵中間必須要有空格)
    static void 快捷鍵測試()
    {
        Debug.Log("組合鍵"+ Selection.activeGameObject.name); //列印物體名/—— 預設列印第一個選中的物體,無論選中了幾個
    }
}

點選鍵盤按鈕 O ,即可列印 “選擇物體的個數”

點選鍵盤按鈕 Ctrl + L ,即可列印 “所選物體的名字”:
如果選擇多個,預設列印第一個(根據自己程式碼來判定,如有需要可自己寫)
這裡寫圖片描述


Create MenuItem for the Component —— 建立元件上的選單項


主要使用:靜態方法

MenuCommand : Context —— 選單命令的目標物件


1

- - Script Component —— 在指令碼元件上新增選單項


靜態方法 MenuItem (itemName : string)


引數 itemName 為字串,表示選單項。

引數 “CONTEXT/ PlayerHealth” 為 元件 路徑

若想對某個(元件/指令碼)進行操作,必須寫上 “CONTEXT/ (元件/指令碼)名

Undo.RecordObject (物件,鍵) 此函式用於記錄物件之後的資料變化,沒有則不能回退操作
舉個例子黑白88

using UnityEditor; //引用Unity編輯器名稱空間
using UnityEngine; //引用Unity引擎名稱空間


/// <summary>
/// 玩家指令碼上的工具 —— 測試指令碼
/// </summary>
public class PlayerTools
{
    /// <summary>
    /// 給玩家指令碼元件上新增按鈕:初始化人物
    /// </summary>
    /// //[選單項函式(“環境(元件:想要給元件上加必須要用這個來表示路徑)/所需控制元件(指令碼名)/需要執行的方法名(就是按鈕名)”)]
    [MenuItem("CONTEXT/PlayerHealth/初始化人物")]
    static void 初始化人物(MenuCommand command) //MenuCommand 正在操作的元件物件類
    {
        CompleteProject.PlayerHealth player = (CompleteProject.PlayerHealth) command.context; //宣告一個PlayerHealt物件 th  —— 需要強轉為 PlayerHealth型別
        Undo.RecordObject(player, "PlayerTools_player");                                      //記錄物件 player 之後的資料變化,用於回退 —— 記錄物件(物件,鍵);//鍵的名字隨意,不能重複//如果沒有這句話,是不能退會之前的修改的
        player.startingHealth = 100;                                                          //血量初始化到100
    }
}

右鍵點選元件 ,選擇 初始化人物 : 即可完成對血量的初始化 —— Ctrl+z,回退操作

這裡寫圖片描述


2

- - Syetem Component —— 在系統元件上新增選單項


靜態方法 MenuItem (itemName : string)


引數 itemName 為字串,表示選單項。

引數 “CONTEXT/ Rigidbody” 為 元件 路徑

若想對某個(元件/指令碼)進行操作,必須寫上 “CONTEXT/ (元件/指令碼)名

Undo.RecordObject (物件,鍵) 此函式用於記錄物件之後的資料變化,沒有則不能回退操作

舉個例子黑白88

using UnityEditor; //引用Unity編輯器名稱空間
using UnityEngine; //引用Unity引擎名稱空間


/// <summary>
/// 玩家指令碼上的工具 —— 測試指令碼
/// </summary>
public class PlayerTools
{
    /// <summary>
    /// 給系統元件 Rigidbody 上新增按鈕:取消重力
    /// </summary>
    /// <param name="command"></param>
    [MenuItem("CONTEXT/Rigidbody/取消重力")]
    static void 取消重力(MenuCommand command)
    {
        Rigidbody rig = (Rigidbody) command.context; //context是一個 (正操作/滑鼠下) 的元件:返回值為Object —— 強轉為需要的型別
        Undo.RecordObject(rig, "PlayerTools_rig");   //記錄 rig 之後的資料變化,用於回退 —— 記錄物件(物件,鍵);//鍵的名字隨意,不能重複//沒有這句話,是不能回退,因為系統沒記錄
        rig.mass       = 0;                          //質量為0
        rig.useGravity = false;                      //關閉重力
    }
}

右鍵點選剛體元件 ,選擇 取消重力: 即可完成對重力的取消 —— Ctrl+z,完成回退

這裡寫圖片描述


3

- - ContextMenu —— 元件選單的用法


ContextMenu ContextMenuItem 均繼承自: MonoBehaviour

所以可以直接在 自義定指令碼中使用,也就是工程指令碼中直接用



[ContextMenuItem(按鈕名,方法名)] 需要寫在所需控制變數之上

[ContextMenu(按鈕名)] 需要直接寫在方法上

Undo.RecordObject (物件,鍵) 此函式用於記錄物件之後的資料變化,沒有則不能回退操作

舉個例子黑白88

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;


/// <summary>
/// 玩家健康屬性指令碼
/// </summary>
public class PlayerHealth : MonoBehaviour
{
    [ContextMenuItem("增加血量50", "增加血量")]                    //按鈕名,方法//需要寫在所需控制變數之上
    public int startingHealth = 100;                            // 初始血量
       /// <summary>
        /// 直接在指令碼中設定選單項,即可在 皮膚中右鍵顯示 該按鈕
        /// </summary>
        [ContextMenu("設定屬性")]//可以直接在指令碼方法裡寫,需要直接寫在方法上
        void 設定屬性()
        {
            Debug.Log("設定屬性");
        }


        /// <summary>
        /// 為變數 startingHealth 提供方法,每點選一次加 50
        /// </summary>
        void 增加血量()
        {
            Undo.RecordObject(this, "PlayerHealth_startingHealth");//記錄值的改變,用於回退//(物件,鍵)
            startingHealth += 50;
        }
}

右鍵點選 PlayerHealth 指令碼元件 ,即可看到按鈕“設定屬性”

點選 PlayerHealth 指令碼元件 ,選擇 startingHealth 屬性,右鍵即可看到按鈕“增加血量50”

這裡寫圖片描述


END

本部落格為非營利性個人原創,除部分有明確署名的作品外,所刊登的所有作品的著作權均為本人所擁有,本人保留所有法定權利。違者必究

對於需要複製、轉載、連結和傳播部落格文章或內容的,請及時和本博主進行聯絡,留言,Email: ichinar@icloud.com

對於經本博主明確授權和許可使用文章及內容的,使用時請註明文章或內容出處並註明網址

相關文章