Unity 编辑器开发实战【Editor Window】- Filter 物体筛选工具
Unity开发工作中,在Hierarchy窗口搜索栏可以通过物体名称或组件名称对场景中的物体进行搜索,但是并不能满足我们一些其它的搜索要求,例如搜索指定Tag标签的物体,或者指定Layer层级的物体,或者指定Active状态的物体,或者更为复杂的一些搜索,比如我们想找到场景中所有隐藏的、且挂有Camera组件的、且标签为MainCamera的物体,这些都无法实现。
今天分享一个作者为了解决上述搜索需求而开发的Filter物体筛选器:
其中Target是指需要进行筛选的所有物体,All是指对场景中的所有物体进行筛选,也可以指定一个根级,对这个根物体的所有子物体进行筛选:
确定好要进行筛选的物体后,下面来创建筛选条件:
1.Name 通过物体名称的关键字进行筛选
2.Component 通过组件进行筛选 -物体是否挂有指定组件
3.Layer 通过物体的Layer层级进行筛选
4.Tag 通过物体的Tag标签进行筛选
5.Active 通过物体的活跃状态进行筛选
以上是单个条件的筛选方式,我们也可以创建复合条件,即多个条件对物体进行筛选,比如文章开始提到的,我们要找到场景中所有隐藏的、且挂有Camera组件的、且标签为MainCamera的物体,需要创建3个条件:1.Active活跃状态为false条件、2.Component组件为Camera条件、3.Tag标签为MainCamera条件
最终点击Select按钮可以选中全部我们筛选出的符合条件的物体,以下是实现代码:
-
using UnityEngine;
-
using UnityEditor;
-
using UnityEngine.SceneManagement;
-
-
using System;
-
using System.Reflection;
-
using System.Collections.Generic;
-
-
namespace SK.Framework
-
{
-
/// <summary>
-
/// 过滤类型
-
/// </summary>
-
public enum FilterMode
-
{
-
Name, //根据名字筛选
-
Component, //根据组件筛选
-
Layer, //根据层级筛选
-
Tag, //根据标签筛选
-
Active, //根据是否活跃筛选
-
Missing, //丢失筛选
-
}
-
public enum MissingMode
-
{
-
Material, //材质丢失
-
Mesh, //网格丢失
-
Script //脚本丢失
-
}
-
[SerializeField]
-
public class FilterCondition
-
{
-
public FilterMode filterMode;
-
public MissingMode missingMode;
-
public string stringValue;
-
public int intValue;
-
public bool boolValue;
-
public Type typeValue;
-
-
public FilterCondition(FilterMode filterMode, string stringValue)
-
{
-
this.filterMode = filterMode;
-
this.stringValue = stringValue;
-
}
-
public FilterCondition(FilterMode filterMode, int intValue)
-
{
-
this.filterMode = filterMode;
-
this.intValue = intValue;
-
}
-
public FilterCondition(FilterMode filterMode, bool boolValue)
-
{
-
this.filterMode = filterMode;
-
this.boolValue = boolValue;
-
}
-
public FilterCondition(FilterMode filterMode, Type typeValue)
-
{
-
this.filterMode = filterMode;
-
this.typeValue = typeValue;
-
}
-
public FilterCondition(FilterMode filterMode, MissingMode missingMode)
-
{
-
this.filterMode = filterMode;
-
this.missingMode = missingMode;
-
}
-
/// <summary>
-
/// 判断物体是否符合条件
-
/// </summary>
-
/// <param name="target">物体</param>
-
/// <returns>符合条件返回true,否则返回false</returns>
-
public bool IsMatch(GameObject target)
-
{
-
switch (filterMode)
-
{
-
case FilterMode.Name: return target.name.ToLower().Contains(stringValue.ToLower());
-
case FilterMode.Component: return target.GetComponent(typeValue) != null;
-
case FilterMode.Layer: return target.layer == intValue;
-
case FilterMode.Tag: return target.CompareTag(stringValue);
-
case FilterMode.Active: return target.activeSelf == boolValue;
-
case FilterMode.Missing:
-
switch (missingMode)
-
{
-
case MissingMode.Material:
-
var mr = target.GetComponent<MeshRenderer>();
-
if (mr == null) return false;
-
Material[] materials = mr.sharedMaterials;
-
bool flag = false;
-
for (int i = 0; i < materials.Length; i++)
-
{
-
if(materials[i] == null)
-
{
-
flag = true;
-
break;
-
}
-
}
-
return flag;
-
case MissingMode.Mesh:
-
var mf = target.GetComponent<MeshFilter>();
-
if (mf == null) return false;
-
return mf.sharedMesh == null;
-
case MissingMode.Script:
-
Component[] components = target.GetComponents<Component>();
-
bool retV = false;
-
for (int i = 0; i < components.Length; i++)
-
{
-
if(components[i] == null)
-
{
-
retV = true;
-
break;
-
}
-
}
-
return retV;
-
default:
-
return false;
-
}
-
default: return false;
-
}
-
}
-
}
-
-
public sealed class Filter : EditorWindow
-
{
-
[MenuItem("SKFramework/Tools/Filter")]
-
private static void Open()
-
{
-
var window = GetWindow<Filter>();
-
window.titleContent = new GUIContent("Filter");
-
window.Show();
-
}
-
//筛选的目标
-
private enum FilterTarget
-
{
-
All, //在所有物体中筛选
-
Specified, //在指定根级物体内筛选
-
}
-
private FilterTarget filterTarget = FilterTarget.All;
-
//存储所有筛选条件
-
private readonly List<FilterCondition> filterConditions = new List<FilterCondition>();
-
//指定的筛选根级
-
private Transform specifiedTarget;
-
//存储所有组件类型
-
private List<Type> components;
-
//存储所有组件名称
-
private List<string> componentsNames;
-
private readonly List<GameObject> selectedObjects = new List<GameObject>();
-
private Vector2 scroll = Vector2.zero;
-
-
private void OnEnable()
-
{
-
components = new List<Type>();
-
componentsNames = new List<string>();
-
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
-
for (int i = 0; i < assemblies.Length; i++)
-
{
-
var types = assemblies[i].GetTypes();
-
for (int j = 0; j < types.Length; j++)
-
{
-
if (types[j].IsSubclassOf(typeof(Component)))
-
{
-
components.Add(types[j]);
-
componentsNames.Add(types[j].Name);
-
}
-
}
-
}
-
}
-
private void OnGUI()
-
{
-
OnTargetGUI();
-
scroll = EditorGUILayout.BeginScrollView(scroll);
-
OnConditionGUI();
-
OnIsMatchedGameObjectsGUI();
-
EditorGUILayout.EndScrollView();
-
OnFilterGUI();
-
}
-
private void OnTargetGUI()
-
{
-
filterTarget = (FilterTarget)EditorGUILayout.EnumPopup("Target", filterTarget);
-
switch (filterTarget)
-
{
-
case FilterTarget.Specified:
-
specifiedTarget = EditorGUILayout.ObjectField("Root", specifiedTarget, typeof(Transform), true) as Transform;
-
break;
-
}
-
EditorGUILayout.Space();
-
}
-
private void OnConditionGUI()
-
{
-
if (GUILayout.Button("Create New Condition", "DropDownButton"))
-
{
-
GenericMenu gm = new GenericMenu();
-
gm.AddItem(new GUIContent("Name"), false, () => filterConditions.Add(new FilterCondition(FilterMode.Name, "GameObject")));
-
gm.AddItem(new GUIContent("Component"), false, () => filterConditions.Add(new FilterCondition(FilterMode.Component, typeof(Transform))));
-
gm.AddItem(new GUIContent("Layer"), false, () => filterConditions.Add(new FilterCondition(FilterMode.Layer, 0)));
-
gm.AddItem(new GUIContent("Tag"), false, () => filterConditions.Add(new FilterCondition(FilterMode.Tag, "Untagged")));
-
gm.AddItem(new GUIContent("Active"), false, () => filterConditions.Add(new FilterCondition(FilterMode.Active, true)));
-
gm.AddItem(new GUIContent("Missing / Material"), false, () => filterConditions.Add(new FilterCondition(FilterMode.Missing, MissingMode.Material)));
-
gm.AddItem(new GUIContent("Missing / Mesh"), false, () => filterConditions.Add(new FilterCondition(FilterMode.Missing, MissingMode.Mesh)));
-
gm.AddItem(new GUIContent("Missing / Script"), false, () => filterConditions.Add(new FilterCondition(FilterMode.Missing, MissingMode.Script)));
-
gm.ShowAsContext();
-
}
-
EditorGUILayout.Space();
-
if(filterConditions.Count > 0)
-
{
-
GUILayout.BeginVertical("Badge");
-
for (int i = 0; i < filterConditions.Count; i++)
-
{
-
var condition = filterConditions[i];
-
GUILayout.BeginHorizontal();
-
if(filterConditions.Count > 1)
-
GUILayout.Label($"{i + 1}.", GUILayout.Width(30f));
-
switch (condition.filterMode)
-
{
-
case FilterMode.Name:
-
GUILayout.Label("Name", GUILayout.Width(80f));
-
condition.stringValue = EditorGUILayout.TextField(condition.stringValue);
-
break;
-
case FilterMode.Component:
-
var index = componentsNames.FindIndex(m => m == condition.typeValue.Name);
-
GUILayout.Label("Component", GUILayout.Width(80f));
-
var newIndex = EditorGUILayout.Popup(index, componentsNames.ToArray());
-
if (index != newIndex) condition.typeValue = components[newIndex];
-
break;
-
case FilterMode.Layer:
-
GUILayout.Label("Layer", GUILayout.Width(80f));
-
condition.intValue = EditorGUILayout.LayerField(condition.intValue);
-
break;
-
case FilterMode.Tag:
-
GUILayout.Label("Tag", GUILayout.Width(80f));
-
condition.stringValue = EditorGUILayout.TagField(condition.stringValue);
-
break;
-
case FilterMode.Active:
-
GUILayout.Label("Active", GUILayout.Width(80f));
-
condition.boolValue = EditorGUILayout.Toggle(condition.boolValue);
-
break;
-
case FilterMode.Missing:
-
GUILayout.Label("Missing", GUILayout.Width(80f));
-
condition.missingMode = (MissingMode)EditorGUILayout.EnumPopup(condition.missingMode);
-
break;
-
default:
-
break;
-
}
-
if (GUILayout.Button("×", "MiniButton", GUILayout.Width(20f)))
-
{
-
filterConditions.RemoveAt(i);
-
return;
-
}
-
GUILayout.EndHorizontal();
-
}
-
GUILayout.EndVertical();
-
}
-
EditorGUILayout.Space();
-
}
-
private void OnIsMatchedGameObjectsGUI()
-
{
-
for (int i = 0; i < selectedObjects.Count; i++)
-
{
-
GameObject obj = selectedObjects[i];
-
if(obj == null)
-
{
-
selectedObjects.RemoveAt(i);
-
i--;
-
continue;
-
}
-
GUILayout.BeginHorizontal("IN Title");
-
GUILayout.Label(obj.name);
-
GUILayout.EndHorizontal();
-
if (Event.current.type == EventType.MouseDown && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition))
-
{
-
EditorGUIUtility.PingObject(obj);
-
}
-
}
-
GUILayout.FlexibleSpace();
-
}
-
private void OnFilterGUI()
-
{
-
GUILayout.BeginHorizontal();
-
if (GUILayout.Button("Filter", "ButtonLeft"))
-
{
-
selectedObjects.Clear();
-
List<GameObject> targetGameObjects = new List<GameObject>();
-
switch (filterTarget)
-
{
-
case FilterTarget.All:
-
GameObject[] rootGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();
-
for (int i = 0; i < rootGameObjects.Length; i++)
-
{
-
var root = rootGameObjects[i];
-
var allChildren = root.GetComponentsInChildren<Transform>(true);
-
for (int j = 0; j < allChildren.Length; j++)
-
{
-
EditorUtility.DisplayProgressBar("Filter", allChildren[j].name, (float)i / rootGameObjects.Length);
-
targetGameObjects.Add(allChildren[j].gameObject);
-
}
-
}
-
EditorUtility.ClearProgressBar();
-
break;
-
case FilterTarget.Specified:
-
Transform[] children = specifiedTarget.GetComponentsInChildren<Transform>(true);
-
for (int i = 0; i < children.Length; i++)
-
{
-
EditorUtility.DisplayProgressBar("Filter", children[i].name, (float)i / children.Length);
-
targetGameObjects.Add(children[i].gameObject);
-
}
-
EditorUtility.ClearProgressBar();
-
break;
-
default:
-
break;
-
}
-
-
for (int i = 0; i < targetGameObjects.Count; i++)
-
{
-
GameObject target = targetGameObjects[i];
-
bool isMatch = true;
-
for (int j = 0; j < filterConditions.Count; j++)
-
{
-
if (!filterConditions[j].IsMatch(target))
-
{
-
isMatch = false;
-
break;
-
}
-
}
-
EditorUtility.DisplayProgressBar("Filter", $"{target.name} -> Is Matched : {isMatch}", (float)i / targetGameObjects.Count);
-
if (isMatch)
-
{
-
selectedObjects.Add(target);
-
}
-
}
-
EditorUtility.ClearProgressBar();
-
}
-
if (GUILayout.Button("Select", "ButtonMid"))
-
{
-
Selection.objects = selectedObjects.ToArray();
-
}
-
if (GUILayout.Button("Clear", "ButtonRight"))
-
{
-
selectedObjects.Clear();
-
}
-
GUILayout.EndHorizontal();
-
}
-
}
-
}
文章来源: coderz.blog.csdn.net,作者:CoderZ1010,版权归原作者所有,如需转载,请联系作者。
原文链接:coderz.blog.csdn.net/article/details/119643874
- 点赞
- 收藏
- 关注作者
评论(0)