Unity 编辑器拓展

  • Post author:
  • Post category:其他




编辑器拓展:



一、MenuItem:



1.用法:

[MenuItem("Assets/xxxx",false,1)]



2.参数

第一个参数为菜单导航路径,可以在路径最后加上自定义的快捷键。

第二个参数为false表示菜单本身,为true表示作为对应菜单的激活条件,例如:

[MenuItem("Assets/xxxx", false, 1)]
static void appPath()//这个为按钮本身要做的事情
{
	Debug.Log("xxxx");
}
[MenuItem("Assets/xxxx", true, 1)]
static bool checkOpen()//这个为判断这个按钮是否激活点击,返回false就无法点击
{
	return true;
}

第三个参数为排序数,数值越小越靠前。



二、拓展Project视图



1.右键菜单栏:

MenuItem的路径以Assets开头即可。



2.拓展布局:

选中Project视图中的某一项,为其增添一些元素,监听EditorApplication.projectWindowItemOnGUI委托即可。

例如,在选中的项后面画一个button:

[InitializeOnLoadMethod]
static void Initial()
{
	EditorApplication.projectWindowItemOnGUI = delegate (string guid, Rect selectionRect)
	{
		if (Selection.activeObject && guid == AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(Selection.activeObject)))
		//不能用 guid == Selection.assetGUIDs[0]
		{
			float width = 50f;
			selectionRect.x += (selectionRect.width - 50f);
			selectionRect.y += 2f;
			selectionRect.width = width;
			GUI.color = Color.red;
			if (GUI.Button(selectionRect, "CLICK"))
			{

			}
			GUI.color = Color.white;
		}
	};
}



3.监听事件



AssetModificationProcessor类

用于Project视图资源变动相关的事件监听

其中有5个事件可写:

IsOpenForEdit(string,string):当 Unity 检查资源以确定是否应禁用编辑器时,则会调用此方法。

OnWillCreateAsset(string):Unity 在即将创建未导入的资源(例如,.meta 文件)时调用此方法。

OnWillDeleteAsset(string,RemoveAssetOptions):当 Unity 即将从磁盘中删除资源时,则会调用此方法。

OnWillMoveAsset(string,string):Unity 即将在磁盘上移动资源时会调用此方法。

OnWillSaveAssets(string[]):Unity 即将向磁盘写入序列化资源或场景文件时会调用此方法。



使用

public class CustomAssetModificationProcessor : UnityEditor.AssetModificationProcessor
{
    static void OnWillCreateAsset(string assetName)
    {
        Debug.Log("OnWillCreateAsset is being called with the following asset: " + assetName + ".");
    }
}

继承自AssetModificationProcessor类,写对应的静态函数即可,注意参数。



三、拓展Hierarchy视图



1.右键菜单栏:

MenuItem的路径以GameObject开头即可。



2.拓展布局:

监听改为EditorApplication.hierarchyWindowItemOnGUI委托即可。



3.重写菜单栏

即在EditorApplication.hierarchyWindowItemOnGUI委托中,判断鼠标右键点击的物体,并修改EditorUtility.DisplayPopupMenu的路径为新的一个路径即可。



代码如下

[InitializeOnLoadMethod]
static void Initial2()
{
	EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyGUI;
}

static void OnHierarchyGUI(int instanceID, Rect selectionRect)
{
	if (Event.current != null && selectionRect.Contains(Event.current.mousePosition)
	   && Event.current.button == 1 && Event.current.type <= EventType.MouseUp)
	{
		GameObject selectGo = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
		if (selectGo)
		{
			Vector2 mousePos = Event.current.mousePosition;
			EditorUtility.DisplayPopupMenu(new Rect(mousePos.x, mousePos.y, 0, 0), "MyNewMenu/Test", null);
			Event.current.Use();
		}
	}
}

[MenuItem("MyNewMenu/Test/hhh", false, 1)]
static void NewMenu()
{

}

注意:一定要定义出自定义路径”MyNewMenu/Test”的子路径,如”MyNewMenu/Test/hhh”,要是没有hhh这一级,Unity会直接崩溃掉。

另外,如果想改原有菜单中已有项的点击逻辑,直接用MenuItem写同样的路径覆盖掉即可。

如:

[MenuItem(“GameObject/UI/Text”, false, 1)]

static void NewMenu()

{


//以后创建Text组件就走这里了。

}



四、拓展Inspector视图



1.拓展源生组件:

让类继承自Editor,打上要修改的组件标签,标签为[CustomEditor(typeof(XXXClass))]



例如:

[CustomEditor(typeof(Camera))]
public class InspectorTest : Editor
{
    public override void OnInspectorGUI()
    {
        if (GUILayout.Button("拓展按钮"))
        {
			//这里应用GUILayout画,GUILayout由Unity自动计算位置。
        }
		if (GUI.Button(new Rect(0, 0, 200, 200), "拓展按钮2"))
        {
			//如果用GUI画,会从Inspector面板左上角算(0,0)点,然后位置被Rect限定住,不适用
        }
        base.OnInspectorGUI();
    }
}



2.拓展继承组件:

通过反射,可以获取一些Editor程序集里的类方法,例如:

[CustomEditor(typeof(Transform))]
public class Script_03_10 :Editor
{
	private Editor m_Editor;
	void OnEnable()
	{
		m_Editor = Editor.CreateEditor(target, 
			Assembly.GetAssembly(typeof(Editor)).GetType("UnityEditor.TransformInspector",true));
	}

	public override void OnInspectorGUI(){
		if (GUILayout.Button ("拓展按钮")) {
		}
		//调用系统绘制方法
		m_Editor.OnInspectorGUI();
	}
}



3.给组件设置不可编辑状态

将组件的某一部分置灰,让它不能被编辑,只需要用GUI.enabled = false;与GUI.enabled = true;夹住要静止的部分即可,例如:

public override void OnInspectorGUI()
{
	if (GUILayout.Button("拓展按钮上"))
	{
	}
	//开始禁止
	GUI.enabled = false;
	base.OnInspectorGUI();
	//结束禁止
	GUI.enabled = true;
	if (GUILayout.Button("拓展按钮下"))
	{
	}
}

如果想要设置某个物体身上的全部组件不可编辑,只需要设置该物体的hideFlags为HideFlags.NotEditable即可。

HideFlags枚举还可以用于设置对象的某些情况下不保存,以及在某些视图中隐藏。可以用 “|”符号,同时保持多个属性。



4.拓展Context菜单

即在Inspector中右键点击组件弹出来的菜单栏。只需要MenuItem的路径以CONTEXT/XXXComponent(要改的组件)/XXXX 即可,例如:

[MenuItem("CONTEXT/Camera/New Context 1")]
public static void NewContext2(MenuCommand command)
{
	Debug.Log(command.context.name);
}

如果要加在Transform组件上,将Camera改为Transform即可,如果所有组件都要加,则改为Component即可。



五、拓展Scene视图



1.画辅助元素(仅仅编辑器模式下做辅助,不会影响游戏最终的发布)

OnDrawGizmosSelected():在选择物体的时候生效。

OnDrawGizmos():即使不选中物体也生效。



例如:

void OnDrawGizmosSelected()
{
	Gizmos.color = Color.red;
	//画线
	Gizmos.DrawLine(transform.position, Vector3.one);
	//立方体
	Gizmos.DrawCube(Vector3.one, Vector3.one);
}

void OnDrawGizmos()
{
	Gizmos.DrawSphere(transform.position, 1);
}



2.拓展对应Object的Scene视图

让类继承自Editor,并且打上标签,和拓展Inspector类似,只是重写的方法改为重写OnSceneGUI。

[CustomEditor(typeof(Camera))]
public class ExampleClass : Editor
{
    void OnSceneGUI()
    {
        Camera camera = target as Camera;
        if (camera != null)
        {
            Handles.color = Color.red;
            Handles.Label(camera.transform.position, camera.transform.position.ToString());

            Handles.BeginGUI();
            GUI.backgroundColor = Color.red;
            if (GUILayout.Button("click", GUILayout.Width(200f)))
            {
                Debug.LogFormat("click = {0}", camera.name);
            }
            GUILayout.Label("Label");
            Handles.EndGUI();
        }
    }
}



3.上面一种方式只能在选中对应类型的GameObject时绘制元素,如果要在非选中状态下绘制,在SceneView.onSceneGUIDelegate即可。



六、拓展Game视图

给继承自MonoBehaviour的脚本打上[ExecuteInEditMode]标签,可以让它在非运行模式下生效GUI。



例如:

[ExecuteInEditMode]
public class ExampleClass :MonoBehaviour
{
    void OnGUI()
    {
        if (GUILayout.Button("Click"))
        {
            Debug.Log("click!!!");
        }
        GUILayout.Label("Hello World!!!");
    }
}



七、EditorWindow,自定义窗口:



1.制作自定义窗口,以及常用的生命周期函数:



代码如下:

public class ExampleClass : EditorWindow
{
    [MenuItem("Window/Open My Window")]
    static void Init()
    {
        ExampleClass window = (ExampleClass)EditorWindow.GetWindow(typeof(ExampleClass));
        window.Show();
    }

    private Texture m_MyTexture = null;
    private float m_MyFloat = 0.5f;
    void Awake()
    {
        Debug.LogFormat("窗口初始化时调用");
        m_MyTexture = AssetDatabase.LoadAssetAtPath<Texture>("Assets/unity.png");
    }
    void OnGUI()
    {
        GUILayout.Label("Hello World!!", EditorStyles.boldLabel);
        m_MyFloat = EditorGUILayout.Slider("Slider", m_MyFloat, -5, 5);
        GUI.DrawTexture(new Rect(0, 30, 100, 100), m_MyTexture);
    }
    void OnDestroy()
    {
        Debug.LogFormat("窗口销毁时调用");
    }
    void OnFocus()
    {
        Debug.LogFormat("窗口拥有焦点时调用");
    }
    void OnHierarchyChange()
    {
        Debug.LogFormat("Hierarchy视图发生改变时调用");
    }
    void OnInspectorUpdate()
    {
        //Debug.LogFormat ("Inspector每帧更新");
    }
    void OnLostFocus()
    {
        Debug.LogFormat("失去焦点");
    }
    void OnProjectChange()
    {
        Debug.LogFormat("Project视图发生改变时调用");
    }
    void OnSelectionChange()
    {
        Debug.LogFormat("Hierarchy或者Project视图中选择一个对象时调用");
    }
    void Update()
    {
        //Debug.LogFormat ("每帧更新");
    }
}



2.拓展自定义窗口的下拉菜单:

需要继承接口IHasCustomMenu接口:

void IHasCustomMenu.AddItemsToMenu(GenericMenu menu)
{
	menu.AddDisabledItem(new GUIContent("Disable"));
	menu.AddItem(new GUIContent("Test1"), true, () => {
		Debug.Log("Test1");
	});
	menu.AddItem(new GUIContent("Test2"), true, () => {
		Debug.Log("Test2");
	});
	menu.AddSeparator("Test/");
	menu.AddItem(new GUIContent("Test/Tes3"), true, () => {
		Debug.Log("Tes3");
	});
}



UnityEditor下的一些常用类:



EditorApplication类:



静态变量



1.EditorApplication.applicationPath

返回Unity编辑器应用程序路径。



示例
[MenuItem("Examples/applicationPath")]
static void appPath()
{
	Debug.Log("EditorApplication.applicationPath: " + EditorApplication.applicationPath);
	Debug.Log("EditorApplication.applicationContentsPath: " + EditorApplication.applicationContentsPath);
}


输出:
EditorApplication.applicationPath: G:/UnityNew/Unity/Editor/Unity.exe
EditorApplication.applicationContentsPath: G:/UnityNew/Unity/Editor/Data



2.isCompiling、isPaused、isPlaying、isUpdating

编辑器当前是否处于编译脚本、暂停、播放、刷新AssetDatabase



3.projectWindowItemOnGUI、hierarchyWindowItemOnGUI

Project、 Hierarchy 窗口中每个可见列表项的 OnGUI 事件的委托。



委托



1.HierarchyWindowItemCallback、ProjectWindowItemCallback

要在每个 OnGUI 事件上为Hierarchy、Project 窗口中的每个可见列表项调用的委托。



用法:

见Project拓展布局部分。

projectWindowItemOnGUI与hierarchyWindowItemOnGUI两个静态变量分别对应这两个委托。



AssetDatabase类

用于访问资源并针对资源执行操作的接口。

静态函数(大致分类):



1.资源的增、删、复制、查找、移动等:

CreateAsset、CreateFolder、DeleteAsset、CopyAsset、FindAssets、MoveAsset



2.获取相关资源信息等:

GetAllAssetBundleNames、GetAssetBundleDependencies、GetAssetOrScenePath、GetAssetPath、GetDependencies等



3.导入导出:

ImportAsset、ImportPackage、ExportPackage等



4.加载、释放资源:

LoadAllAssetRepresentationsAtPath、LoadAllAssetsAtPath、LoadAssetAtPath、LoadMainAssetAtPath。

RemoveAssetBundleName、RemoveObjectFromAsset、RemoveUnusedAssetBundleNames



5.保存:

SaveAssets。



EditorUtility类:

Editor 实用程序函数。

InstanceIDToObject:将实例 ID 转换为对对象的引用。

DisplayPopupMenu:显示弹出菜单。



Handles类:

场景视图中的自定义 3D GUI 控件和绘制操作。

Handles 类似于 Gizmos,但在交互性和操作方面提供了更多功能。Unity 本身提供的用于在 Scene 视图中操作项目的 3D 控件是 Gizmos 和 Handles 的组合。内置的 Handle GUI 有很多,如通过变换组件定位、缩放和旋转对象等熟悉的工具。不过,您可以自行定义 Handle GUI,以与自定义组件编辑器结合使用。此类 GUI 对于编辑以程序方式生成的场景内容、“不可见”项和相关对象的组(如路径点和位置标记)非常实用。



静态变量:

color:修改颜色。



静态函数:

Handles.BeginGUI:Begin a 2D GUI block inside the 3D handle GUI. 在3D GUI处理中开始一个2D GUI快。

Handles.EndGUI:结束2D GUI编辑,返回3D GUI处理。

Label:在3D空间创建一个文本标签。

以及画各式各样的元素:

DrawLine、Button、DrawCamera等



EditorGUILayout类:

EditorGUI 的自动布局版本。



静态函数:



1.开始、结束类型

BeginScrollView、EndScrollView(开始/结束一个滚动视图)、BeginHorizontal、EndHorizontal、BeginToggleGroup、EndToggleGroup等。



2.输入框、交互框类型:

TextField、IntField、ObjectField、EnumPopup(创建一个枚举弹出选择字段)、Toggle等。



EditorPrefs类:

存储和访问 Unity 编辑器偏好设置。

Unity编辑器为开发者提供了类似PlayerPrefs的数据保存方式EditorPrefs。EditorPrefs是适用于编辑器模式,而PlayerPrefs适用于游戏运行时。

EditorPrefs提供了四种数据的保存:int,float,string,bool。

其静态函数则分为Get、Set、Delete 3类外加一个HasKey。

通过Set方法保存下数据,下次则通过Get方法来获取数据,HasKey方法可以判断是否存在该数据的保存,删除数据调用DeleteKey方法即可。



UnityEngine下的一些常用类:



Event类:

事件与用户输入(按键、鼠标操作)相对应,或者是 UnityGUI 布局或渲染事件。



静态变量

current:返回将被立即处理的当前事件(Event类型)。



变量:



1.鼠标相关:

isMouse:该事件是否是鼠标事件?(只读)

button:已按下哪个鼠标建,0左键,1右键。

clickCount:已收到了多少次连续鼠标点击。

delta:与上次事件相比该鼠标的相对移动。

mousePosition:鼠标位置。



2.键盘相关:

isKey:该事件是否是键盘事件?(只读)

capsLock、control、alt、shift、character等。



3.事件类型:

type:事件类型。枚举为(EventType)



3.公共函数:

1.Use:Event.current.Use() 的含义是不再执行原有操作。



GUI类:



静态变量:



静态函数:



1.创建GUI元素类型:

Button、Box、PasswordField、TextArea(多行文本区域)、TextField(单行文本区域)、Toggle、等

HorizontalScrollbar、VerticalScrollbar(水平/垂直滚动条)

HorizontalSlider、VerticalSlider(水平/垂直滑动条,最大最小值之间更改某值)

BeginScrollView、EndScrollView(开始/结束一个滚动视图)



GUILayout类



静态函数:

Button:创建一个按钮



Gizmos类

辅助图标用于协助在 Scene 视图中进行视觉调试或设置。

所有辅助图标绘图都必须在此脚本的 OnDrawGizmos 或 OnDrawGizmosSelected 函数中进行。每一帧都调用 OnDrawGizmos。在 OnDrawGizmos 中渲染的所有辅助图标均可选择。 仅在选择了附加此脚本的对象时才调用 OnDrawGizmosSelected。



静态变量:

color:为接下来绘制的辅助图标设置颜色。



静态函数:

绘制各种辅助图形元素:

DrawCube:使用 center 和 size 绘制一个实心盒体。

DrawGUITexture、DrawIcon、DrawLine、DrawRay…等



四大GUI系统的大致区别



编辑器中的GUI系统大致分为:

1、UnityEngine.GUI

2、UnityEngine.GUILayout

3、UnityEditor.EditorGUI

4、UnityEditor.EditorGUILayout



GUI系统:

这是运用最广泛的GUI系统,所属命名空间UnityEngine,用其绘制的所有控件不带有自动布局效果,需要手动指定每个控件的绘制位置和大小,自适应性较弱,但开发自由度较高。

GUI系统在编辑器和游戏发布后均可使用。



GUILayout系统:

带自动布局的GUI系统,所属命名空间UnityEngine,用其绘制的所有控件都带有自动布局效果,自适应性较强,但开发自由度较低。

GUILayout系统在编辑器和游戏发布后均可使用。



EditorGUI系统:

适用于编辑器的GUI系统,所属命名空间UnityEditor,用其绘制的所有控件不带有布局效果,需要手动指定每个控件的绘制位置和大小,跟GUI系统的差别是其拥有部分编辑器专用控件,且其只能运行在编辑器内,自适应性较弱,但开发自由度较高。

EditorGUI系统不可以在发布后使用,只能在编辑器中使用。



EditorGUILayout系统:

带自动布局的EditorGUI系统,所属命名空间UnityEditor,用其绘制的所有控件都带有自动布局效果,跟GUILayout系统的差别是其拥有部分编辑器专用控件,且其只能运行在编辑器内,自适应性较强,但开发自由度较低。

EditorGUILayout系统不可以在发布后使用,只能在编辑器中使用。



版权声明:本文为qq_60798700原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。