Files
ichni_Creator_Studio/Assets/Editor/QuickSelector.cx

180 lines
6.7 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using UnityEngine;
using UnityEditor;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Linq;
[InitializeOnLoad]
public class QuickSelector//原生菜单
{
// 配置键名
private const string PREF_UI = "QS_EnableUI";
private const string PREF_3D = "QS_Enable3D";
private const string PREF_REVERSE = "QS_ReverseOrder";
static QuickSelector()
{
SceneView.duringSceneGui += OnSceneGUI;
}
private static void OnSceneGUI(SceneView sceneView)
{
Event e = Event.current;
// Shift + 右键触发
if (e.type == EventType.MouseDown && e.button == 1 && e.shift)
{
// 加载配置
bool enableUI = EditorPrefs.GetBool(PREF_UI, true);
bool enable3D = EditorPrefs.GetBool(PREF_3D, true);
bool reverseOrder = EditorPrefs.GetBool(PREF_REVERSE, false);
Vector2 guiPos = e.mousePosition;
guiPos.y = sceneView.camera.pixelHeight - guiPos.y;
Ray ray = HandleUtility.GUIPointToWorldRay(e.mousePosition);
HashSet<GameObject> processedObjects = new HashSet<GameObject>();
List<SelectionEntry> entries = new List<SelectionEntry>();
// 1. 智能拾取 (PickGameObject)
GameObject smartPick = HandleUtility.PickGameObject(e.mousePosition, false);
if (smartPick != null) AddEntry(entries, processedObjects, smartPick, "PICK");
// 2. UI 扫描
if (enableUI)
{
var allRects = GameObject.FindObjectsByType<RectTransform>(FindObjectsSortMode.None);
foreach (var rect in allRects)
{
if (!rect.gameObject.activeInHierarchy) continue;
if (RectTransformUtility.RectangleContainsScreenPoint(rect, guiPos, sceneView.camera))
AddEntry(entries, processedObjects, rect.gameObject, "UI");
}
}
// 3. 3D/Mesh 扫描
if (enable3D)
{
RaycastHit[] hits = Physics.RaycastAll(ray, float.MaxValue);
foreach (var hit in hits) AddEntry(entries, processedObjects, hit.collider.gameObject, "3D");
Renderer[] allRenderers = GameObject.FindObjectsByType<Renderer>(FindObjectsSortMode.None);
foreach (var r in allRenderers)
{
if (processedObjects.Contains(r.gameObject)) continue;
if (r.bounds.IntersectRay(ray, out _)) AddEntry(entries, processedObjects, r.gameObject, "Mesh");
}
}
if (entries.Count > 0 || true)
{
GenericMenu menu = new GenericMenu();
// 根节点分组UI组优先
var groups = entries.GroupBy(x => x.rootObject)
.OrderByDescending(g => g.Any(ent => ent.majorType == "UI"))
.ThenBy(g => g.Key.name);
foreach (var group in groups)
{
if (menu.GetItemCount() > 0) menu.AddSeparator("");
// 组内排序
var sortedInGroup = reverseOrder
? group.OrderByDescending(x => x.depth).ThenByDescending(x => x.siblingIndex)
: group.OrderBy(x => x.depth).ThenBy(x => x.siblingIndex);
int minDepth = group.Min(x => x.depth);
int maxDepth = group.Max(x => x.depth);
foreach (var entry in sortedInGroup)
{
// --- 修复点:缩进计算 ---
// 顺序:深度越深缩进越多 (entry.depth - minDepth)
// 逆序:深度越浅缩进越多 (maxDepth - entry.depth)
int indentLevel = reverseOrder ? (maxDepth - entry.depth) : (entry.depth - minDepth);
string indent = new string(' ', indentLevel * 2);
string label = $"{indent}[ {entry.majorType} | {entry.minorType} ]: {entry.gameObject.name}";
menu.AddItem(new GUIContent(label), false, () =>
{
Selection.activeGameObject = entry.gameObject;
EditorGUIUtility.PingObject(entry.gameObject);
});
}
}
// 设置项
menu.AddSeparator("");
menu.AddItem(new GUIContent("Settings/Detect UI"), enableUI, () => EditorPrefs.SetBool(PREF_UI, !enableUI));
menu.AddItem(new GUIContent("Settings/Detect 3D"), enable3D, () => EditorPrefs.SetBool(PREF_3D, !enable3D));
menu.AddItem(new GUIContent("Settings/Reverse Order"), reverseOrder, () => EditorPrefs.SetBool(PREF_REVERSE, !reverseOrder));
menu.ShowAsContext();
e.Use();
}
}
}
private static void AddEntry(List<SelectionEntry> list, HashSet<GameObject> set, GameObject go, string source)
{
if (go == null || !set.Add(go)) return;
string major = "3D";
string minor = "Object";
if (source == "UI" || go.GetComponent<RectTransform>() != null)
{
major = "UI"; minor = GetUIComponentType(go);
}
else if (go.GetComponent<Collider>() != null)
{
major = "3D"; minor = "Collider";
}
else if (go.GetComponent<Renderer>() != null)
{
major = "Mesh"; minor = go.GetComponent<Renderer>().GetType().Name;
}
list.Add(new SelectionEntry
{
gameObject = go,
rootObject = GetRoot(go.transform),
depth = GetDepth(go.transform),
siblingIndex = go.transform.GetSiblingIndex(),
majorType = major,
minorType = minor
});
}
private static string GetUIComponentType(GameObject go)
{
if (go.GetComponent("TextMeshProUGUI")) return "TMPro";
if (go.GetComponent<Text>()) return "Text";
if (go.GetComponent<Button>()) return "Button";
if (go.GetComponent<Image>()) return "Image";
return "Rect";
}
private static GameObject GetRoot(Transform t)
{
Transform curr = t; while (curr.parent != null) curr = curr.parent; return curr.gameObject;
}
private static int GetDepth(Transform t)
{
int d = 0; while (t.parent != null) { d++; t = t.parent; }
return d;
}
private class SelectionEntry
{
public GameObject gameObject;
public GameObject rootObject;
public int depth;
public int siblingIndex;
public string majorType;
public string minorType;
}
}