拓展Prooject视图
放在Editor文件夹下,比如拓展右键菜单,一个示例脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Script01 : MonoBehaviour
{
[MenuItem("Assets/My Tools/ Tools 1", false, 2)]
static void MyTools1()
{
Debug.Log(Selection.activeObject.name);
}
[MenuItem("Assets/My Tools/ Tools 2", false, 1)]
static void MyTools2()
{
Debug.Log(Selection.activeObject.name);
}
}
MenuItem
方法的第一个参数是显示的菜单路径,第二个参数为false表明该方法在点击菜单选项时才会调用,反之第三个参数表示排序,数字越小越靠前:
再比如,自定义创建物体的菜单,脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Script02 : MonoBehaviour
{
[MenuItem("Assets/Create/My Create/Cube", false, 2)]
static void CreateCube()
{
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
}
上述脚本用于创建一个创建基本体的菜单。
再比如,拓展布局,脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Script03 : MonoBehaviour
{
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod()
{
EditorApplication.projectWindowItemOnGUI = delegate (string guid, Rect selectionRect)
{
if (Selection.activeObject && guid == AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(Selection.activeObject)))
{
float width = 50.0f;
selectionRect.x += (selectionRect.width - width);
selectionRect.y += 2f;
selectionRect.width = width;
GUI.color = Color.red;
if (GUI.Button(selectionRect, "click"))
{
Debug.LogFormat("click:{0}", Selection.activeObject.name);
}
GUI.color = Color.white;
}
};
}
}
该脚本会在Project元素旁设置一个按钮,打印一些信息,InitializeOnLoadMethod
可以让该函数成为自动初始化的函数,无序用户手动操作:
Project视图中,资源要进行比较好的规划,我们可以用监听事件来实现,可以根据文件原始位置以及要移动过去的位置来判断移动是否合法。脚本类需继承UnityEditor.AssetModificationProcessor
:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.VersionControl;
public class Script04 : UnityEditor.AssetModificationProcessor
{
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod()
{
//全局监听Project视图下的资源是否发生变化
EditorApplication.projectWindowChanged = delegate () {
Debug.Log("change");
};
}
// 监听双击鼠标左键,打开资源的事件
public static bool IsOpenForEdit(string assetPath, out string message)
{
message = null;
Debug.LogFormat("assetPath:{0}", assetPath);
return true;
}
//监听资源创建事件
public static void OnWillCreateAsset(string path)
{
Debug.LogFormat("path:{0}", path);
}
//监听资源被保存事件
public static string[] OnWillSaveAssets(string[] paths)
{
if(paths!=null)
{
Debug.LogFormat("path:{0}", string.Join(",", paths));
}
return paths;
}
//监听资源被移动事件
public static AssetMoveResult OnWillMoveAsset(string oldPath, string newPath)
{
Debug.LogFormat("from:{0} to: {1}", oldPath, newPath);
return AssetMoveResult.DidMove;
}
// 监听资源被删除事件
public static AssetDeleteResult OnWillDeleteAsset(string assetPath, RemoveAssetOptions option)
{
Debug.LogFormat("delete:{0}", assetPath);
return AssetDeleteResult.DidDelete;
}
}
拓展Hierarchy视图
在Hierarchy视图中右键可以弹出一些创建物体的按钮,可以自定义一些按钮,如:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Script05 : MonoBehaviour
{
[MenuItem("GameObject/My Create/Cube", false, 0)]
static void CreateCube()
{
GameObject.CreatePrimitive(PrimitiveType.Cube);
}
}
脚本写法和之前的没区别,关键在于MenuItem
的路径。
同样,我们也可以对布局进行拓展,比如:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Script06 : MonoBehaviour
{
[InitializeOnLoadMethod]
static void InitializeOnLoadMethod()
{
EditorApplication.hierarchyWindowItemOnGUI = delegate (int instanceID, Rect selectionRect)
{
if(Selection.activeObject && instanceID == Selection.activeObject.GetInstanceID())
{
float width = 50f;
float height = 20f;
selectionRect.x += (selectionRect.width - width);
selectionRect.width = width;
selectionRect.height = height;
// 点击事件
if(GUI.Button(selectionRect, AssetDatabase.LoadAssetAtPath<Texture>("Assets/unity.png")))
{
Debug.LogFormat("click:{0}", Selection.activeObject.name);
}
}
};
}
}
该脚本会在Hierarchy视图的元素旁生成一个按钮,点击会打印一些信息。
除了修改右键菜单,我们还可以重写菜单,脚本示例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class Script07 : MonoBehaviour
{
[MenuItem("Window/Test/dragon")]
static void Test()
{
}
[MenuItem("Window/Test/dragon_boy")]
static void Test1()
{
}
[MenuItem("Window/Test/DragonBaby/dragon_baby")]
static void Test2()
{
}
[InitializeOnLoadMethod]
static void StartInitializeOnLoadMethod()
{
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 selectedGameObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if(selectedGameObject)
{
Vector2 mousePosition = Event.current.mousePosition;
EditorUtility.DisplayPopupMenu(new Rect(mousePosition.x, mousePosition.y, 0, 0), "Window/Test", null);
Event.current.Use();
}
}
}
}
这样,选中一个我们创建的物体,它的右键菜单就完全被我们创建的三个菜单项替代了。Event.current
可以获得当前事件,EditorUtility.DisplayPopupMenu
可以弹出自定义菜单,Event.current.Use()
可以不执行原有的菜单操作。
我们还可以重写系统自带菜单的行为,比如UI中的image组件,可以取消它的RaycastTarget
默认勾选:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
public class Script08 : MonoBehaviour
{
[MenuItem("GameObject/UI/Image")]
static void CreateImage()
{
if(Selection.activeTransform)
{
if(Selection.activeTransform.GetComponentInParent<Canvas>())
{
Image image = new GameObject("image").AddComponent<Image>();
image.raycastTarget = false;
image.transform.SetParent(Selection.activeTransform, false);
Selection.activeTransform = image.transform;
}
}
}
}
拓展Inspector视图
对于源生组件,可以添加按钮,只不过只能在最上面或最下面拓展,如摄像机:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(Camera))]
public class Script09 : Editor
{
public override void OnInspectorGUI()
{
if (GUILayout.Button("拓展")) { }
base.OnInspectorGUI();
}
}
不过对于继承组件,Unity内部可能已经重写了绘制方法,外部访问不了内部代码。Unity将Editor绘制方法封装在内部的DLL文件中,我们可以利用C#的反射特性来调用其中的方法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;
[CustomEditor(typeof(Transform))]
public class Script10 : Editor
{
private Editor m_Editor;
private 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();
}
}
OnEnable
中通过反射得到UnityEditor.TransformInspector
对象,然后可以调用内部的OnInspectorGUI
方法。
还可以设置组件状态,让其不可编辑,比如
Transform
组件,但不影响我们自定义的拓展按钮:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;
[CustomEditor(typeof(Transform))]
public class Script11 : Editor
{
private Editor m_Editor;
private void OnEnable()
{
m_Editor = Editor.CreateEditor(target, Assembly.GetAssembly(typeof(Editor)).GetType("UnityEditor.TransformInspector", true));
}
public override void OnInspectorGUI()
{
if (GUILayout.Button("拓展上")) { }
GUI.enabled = false;
m_Editor.OnInspectorGUI();
GUI.enabled = true;
if (GUILayout.Button("拓展下")) { }
}
}
拓展Scene视图
比如在视图中绘制辅助元素,比如Gizmo:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Script12 : MonoBehaviour
{
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawLine(transform.position, Vector3.one);
Gizmos.DrawCube(Vector3.one, Vector3.one);
}
}
上面的脚本会在选中某一物体时,添加一条红色辅助线,并在末端绘制一个立方体。
还可以绘制辅助UI,添加EditorGUI,代码在Handles.BeginGUI()
和Handles.EndGUI
:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(Camera))]
public class Script16 : Editor
{
private 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("Label");
Handles.EndGUI();
}
}
}
}
网友评论