Unity---编辑器扩展



1、Unity编辑器扩展介绍

Unity为开发者们提供了很方便的扩展功能,编辑器扩展主要可以用于在Unity界面中添加属于自己的菜单、插件。有时可以大大的提高开发效率。
用于编辑器扩展的脚本都放在Editor文件夹中,此文件夹中的资源不会在项目发布时候打包。

2、具体功能

在使用扩展功能时,需要引用UnityEditor命名空间

2.1、在菜单栏中添加扩展

在菜单栏中的扩展可以自己新创,也可以加在已有的菜单里面。

using UnityEditor;                 
public class Tools 
{    
	[MenuItem("MyTools/Test1")]    //让其显示在菜单栏MyTools-Test1下,MyTest1方法表示要做的工作
	//放在其下面的方法代表调用这个。上面写的是路径名字
	private static void MyTest1()          //只有静态方法可以使用MenuItem属性
	{         
		Debug.Log("扩展1");
	}
}

[MenuItem("MyTools/Test1",false,1)]
第一个参数:显示在菜单栏的位置
第二个参数:是否为验证函数,默认为false
第三个参数:优先级,默认为1000。优先级越大越靠下面,优先级相差>10时,会出现分隔符

2.2、为扩展事件添加快捷键

[MenuItem("MyTools/Test1 %t",false,11)]
在第一个参数后面加空格然后写要加的快捷键。
此例就代表快捷键为 Ctrl+t

% == Ctrl
# == Shift
& == alt

2.3、在Hierarchy,Project视图中右键添加扩展

Hierarchy视图右键下的基本都是GameObject菜单第一层分割线之上的扩展。
那么只要把扩展放在第一层的分割线之上不就行了。
而优先级为11则刚好在第一层分割线的最后一个。
[MenuItem("GameObject/Test1",false,11)]

Project右键下的选项基本都在Assets目录下,添加方法同上。

2.4、使用Selection类选择游戏物体

Selection属于UnityEditor命名空间。

//返回选择场景中的一个游戏物体或者预制体。未选择会报错返回none,选择多个会返回第一个。
GameObject go1 = Selection.activeGameObject;

//返回选择场景中的一个游戏物体或预制体、脚本等任意物体。未选择会报错返回none,选择多个会返回第一个。
Object object1 = Selection.activeObject;

//返回选择场景中的一个游戏物体。未选择会报错返回none,选择多个会返回第一个。
Transform transform = Selection.activeTransform;


//返回GameObject类型数组,为选择场景中的多个游戏物体或者预制体。只会选择符合条件的,未选择则数组长度为0。
GameObject[] gameObjects = Selection.gameObjects;

//返回Object类型数组,为选择场景中的多个游戏物体或者任意资源。只会选择符合条件的,未选择则数组长度为0。
Object[] objects = Selection.objects;

//返回transform类型数组,为选择场景中的多个游戏物体。只会选择符合条件的,未选择则数组长度为0。
Transform[] transforms = Selection.transforms;

2.5、Menuitem第二个参数

使用第二个参数时一般配合两个方法来使用。

    [MenuItem("SelectionTest/Test1 _t", true, 1)]
    static bool Test()
    {
        if (Selection.activeTransform == null)
            return false;
        return true;
    }

    [MenuItem("SelectionTest/Test1 _t",false,1)]
    static void Test1()
    {
        Debug.Log(Selection.activeTransform.name);
    }

第二个方法在未选择物体时,本来会报错none。
当使用第二个参数设为true时,只有当此函数返回为true,才会继续执行下面的函数。
那么当未选择物体时,第一个函数返回false,就不会再进行第二个函数。就避免了报错的情况。

注意:MenuItem里的游戏路径和名称必须都相同。

2.6、ContextMenu和ContextMenuItem

第一个类用于在组件的右键中添加扩展。
别的脚本中写其他脚本的扩展需要使用静态方法
本脚本中添加扩展,不需要使用静态方法

  1. 对系统组件添加扩展
	[MenuItem("CONTEXT/Rigidbody/Clear")]
		//CONTEXT(默认写法) , 组件名 , 扩展名
	static void ClearMassGravity(MenuCommand cmd)
		//MenuCommand是当前正在操作的组件对象。只要定义就行,系统会自动赋值
	{
	    Rigidbody rgd = cmd.context as Rigidbody;
		//MenuCommand.context为正在操作的组件对象
	    rgd.mass = 0;
	}
  1. 对自定义脚本添加扩展
	//自定义脚本的话可以在别的脚本里面写,也可以在本脚本写。
	//一般都在本脚本写,因为可以更方便的访问脚本中已经存在的游戏物体
	[ContextMenu("SetColor")]
    void SetColor()
    {
        flashColour = Color.green;
    }
  1. 对脚本的属性添加扩展
	//属于MonoBehaviour,不需要引用Editor。
	//第一个参数为扩展名,第二个为方法名
    [ContextMenuItem("Add", "AddHp")]
    public int startingHealth = 100;   
	void AddHp()
    {
        startingHealth += 20;
    }  

2.7、ScriptableWizard---对话框

当参与的项目非常大时,假如LOL。如果想把所有英雄的HP都一起修改时,使用之前的方法就要一个一个的修改,工作量巨大。
那么有没有更加简单的方法呢?

  1. 静态方法---对话框的创建
    DisplayWizard<类名>(对话框名,Create按钮名,OtherButton按钮名);

  2. 事件---对话框按钮事件
    OnWizardCreate:Create按钮事件名
    OnWizardOtherButton:OtherButton按钮事件名
    OnWizardUpdate:打开对话框或改变对话框内容时调用此方法

  3. OnEnable:当对话框被创建时调用一次

using UnityEngine;
using UnityEditor;

public class EnemyChange : ScriptableWizard {

    public int changeStartHpValue = 150;
    public int ChangeSinkSpeed = 11;
    public const string changeStartHpValueKey = "changeStartHpValue";
    public const string ChangeSinkSpeedKey = "ChangeSinkSpeed";

    //创建对话框扩展
    [MenuItem("Tools/CreateWizard")]
    static void CreateWizard()
    {
        DisplayWizard<EnemyChange>("统一修改敌人","Change And Close","Change");
        //EnemyChange为类名,对话框名字,Create按钮的名字,OtherButton按钮名字
        //第2、3参数都可以省略
        //Create点击后会关闭对话框,OtherButton按钮点击后不会关闭对话框
    }

    //检测Create按钮点击的自带方法
    private void OnWizardCreate()
    {
        GameObject[] enemyPrefabs =  Selection.gameObjects;

        int count = 0;
        EditorUtility.DisplayProgressBar("进度", count + "/" + enemyPrefabs.Length, 0);

        foreach (GameObject go in enemyPrefabs)
        {
            //获取物体的EnemyHealth脚本
            CompleteProject.EnemyHealth hp = go.GetComponent<CompleteProject.EnemyHealth>();
            Undo.RecordObject(hp, "Change Health And Speed");   //开始记录对hp的更改,之后对其的更改都可以撤销

            //改变物体的属性
            hp.startingHealth = changeStartHpValue;
            hp.sinkSpeed = ChangeSinkSpeed;

            count++;
            EditorUtility.DisplayProgressBar("进度", count + "/" + enemyPrefabs.Length, (float)count/enemyPrefabs.Length);
        }
        EditorUtility.ClearProgressBar();
    }

    //检测Other Button按钮方法
    private void OnWizardOtherButton()
    {
        OnWizardCreate();
        ShowNotification(new GUIContent(Selection.gameObjects.Length + "值被修改了"));
    }

	//打开对话框或改变对话框内容时调用此方法
    private void OnWizardUpdate()
    {
        helpString = "";
        errorString = "";
        if(Selection.gameObjects.Length > 0)
        {
            helpString = "您当前选择了" + Selection.gameObjects.Length + "个敌人";
        }
        else
        {
            errorString = "请选择至少一个敌人";
        }
        EditorPrefs.SetInt("changeStartHpValue", changeStartHpValue);
        EditorPrefs.SetInt("ChangeSinkSpeed", ChangeSinkSpeed);
    }

	//当窗口被创建时调用
    private void OnEnable()
    {
        changeStartHpValue = EditorPrefs.GetInt(changeStartHpValueKey, changeStartHpValue);
        ChangeSinkSpeed = EditorPrefs.GetInt(ChangeSinkSpeedKey, ChangeSinkSpeed);
        
    }

    //打开修改选中的物体时调用此方法
    private void OnSelectionChange()
    {
        OnWizardUpdate();
    }
}
原文地址:https://www.cnblogs.com/Fflyqaq/p/10620087.html