Unity动画引用查询工具
在Unity项目中查找某个动画文件(.anim)被哪些对象引用是一个常见需求。下面我将创建一个可视化工具来帮助你查找动画文件的引用情况。
使用说明
将上述脚本放在Editor文件夹中。
通过菜单栏 Tools -> Animation Reference Finder 打开窗口。
选择一个文件夹
在动画文件列表中,使用左侧的单选按钮选择您要查询的动画文件
设置搜索范围
点击"查找引用"按钮
这个改进版本应该能解决您遇到的问题,使选择动画文件更加直观和可靠。
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEditor.Animations;
public class AnimationReferenceFinder : EditorWindow
{
private DefaultAsset targetFolder;
private AnimationClip targetAnimation;
private Vector2 scrollPosition;
private List<Object> referencedBy = new List<Object>();
private bool includeScenes = true;
private bool includePrefabs = true;
private bool includeAssets = true;
private List<AnimationClip> folderAnimations = new List<AnimationClip>();
private Vector2 folderAnimationsScroll;
private int selectedAnimationIndex = -1;
[MenuItem("Tools/Animation Reference Finder")]
public static void ShowWindow()
{
GetWindow<AnimationReferenceFinder>("动画引用查询工具");
}
private void OnGUI()
{
GUILayout.Label("动画引用查询工具", EditorStyles.boldLabel);
EditorGUILayout.Space();
// 选择文件夹
EditorGUI.BeginChangeCheck();
targetFolder = (DefaultAsset)EditorGUILayout.ObjectField("目标文件夹", targetFolder, typeof(DefaultAsset), false);
if (EditorGUI.EndChangeCheck() && targetFolder != null)
{
LoadAnimationsFromFolder();
selectedAnimationIndex = -1;
targetAnimation = null;
}
EditorGUILayout.Space();
// 显示文件夹中的动画文件
if (folderAnimations.Count > 0)
{
GUILayout.Label("文件夹中的动画文件:", EditorStyles.boldLabel);
// 显示当前选中的动画
if (selectedAnimationIndex >= 0 && selectedAnimationIndex < folderAnimations.Count)
{
EditorGUILayout.LabelField("当前选中的动画:", EditorStyles.boldLabel);
EditorGUILayout.ObjectField(folderAnimations[selectedAnimationIndex], typeof(AnimationClip), false);
targetAnimation = folderAnimations[selectedAnimationIndex];
}
else
{
EditorGUILayout.HelpBox("请从列表中选择一个动画文件", MessageType.Info);
}
EditorGUILayout.Space();
// 动画文件列表
folderAnimationsScroll = EditorGUILayout.BeginScrollView(folderAnimationsScroll, GUILayout.Height(150));
for (int i = 0; i < folderAnimations.Count; i++)
{
var anim = folderAnimations[i];
EditorGUILayout.BeginHorizontal();
// 使用单选按钮而不是按钮
bool isSelected = EditorGUILayout.Toggle(i == selectedAnimationIndex, GUILayout.Width(20));
if (isSelected && i != selectedAnimationIndex)
{
selectedAnimationIndex = i;
targetAnimation = anim;
}
EditorGUILayout.LabelField(anim.name);
EditorGUILayout.ObjectField(anim, typeof(AnimationClip), false, GUILayout.Width(150));
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
}
else if (targetFolder != null)
{
EditorGUILayout.HelpBox("该文件夹中没有找到动画文件", MessageType.Info);
}
EditorGUILayout.Space();
// 搜索选项
GUILayout.Label("搜索范围:", EditorStyles.boldLabel);
includeScenes = EditorGUILayout.Toggle("场景中的对象", includeScenes);
includePrefabs = EditorGUILayout.Toggle("预制体", includePrefabs);
includeAssets = EditorGUILayout.Toggle("其他资源", includeAssets);
EditorGUILayout.Space();
// 搜索按钮
if (GUILayout.Button("查找引用", GUILayout.Height(30)))
{
if (targetAnimation != null)
{
FindReferences();
}
else
{
EditorUtility.DisplayDialog("错误", "请先选择一个动画文件", "确定");
}
}
EditorGUILayout.Space();
// 显示结果
GUILayout.Label($"引用结果 ({referencedBy.Count})", EditorStyles.boldLabel);
if (referencedBy.Count == 0 && targetAnimation != null)
{
EditorGUILayout.HelpBox("未找到引用", MessageType.Info);
}
else if (referencedBy.Count > 0)
{
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
foreach (var obj in referencedBy)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.ObjectField(obj, typeof(Object), true);
if (GUILayout.Button("定位", GUILayout.Width(50)))
{
Selection.activeObject = obj;
EditorGUIUtility.PingObject(obj);
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
}
}
private void LoadAnimationsFromFolder()
{
folderAnimations.Clear();
if (targetFolder == null) return;
string folderPath = AssetDatabase.GetAssetPath(targetFolder);
if (!AssetDatabase.IsValidFolder(folderPath))
{
EditorUtility.DisplayDialog("错误", "请选择一个有效的文件夹", "确定");
return;
}
// 获取文件夹中的所有动画文件
string[] assetPaths = AssetDatabase.FindAssets("t:AnimationClip", new[] { folderPath });
foreach (string guid in assetPaths)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(path);
if (clip != null)
{
folderAnimations.Add(clip);
}
}
// 按名称排序
folderAnimations.Sort((a, b) => a.name.CompareTo(b.name));
}
private void FindReferences()
{
referencedBy.Clear();
string targetPath = AssetDatabase.GetAssetPath(targetAnimation);
if (includeScenes)
{
// 搜索当前打开的场景
foreach (GameObject go in UnityEngine.Object.FindObjectsOfType<GameObject>(true))
{
CheckGameObjectForAnimation(go, targetPath);
}
}
if (includePrefabs || includeAssets)
{
// 搜索项目中的所有预制体和资源
string[] allAssetPaths = AssetDatabase.GetAllAssetPaths();
foreach (string path in allAssetPaths)
{
if (!includePrefabs && path.EndsWith(".prefab")) continue;
if (!includeAssets && !path.EndsWith(".prefab")) continue;
var assets = AssetDatabase.LoadAllAssetsAtPath(path);
foreach (var asset in assets)
{
if (asset is GameObject go)
{
CheckGameObjectForAnimation(go, targetPath);
}
else if (asset is AnimatorOverrideController overrideController)
{
CheckAnimatorOverrideController(overrideController, targetPath);
}
else if (asset is UnityEditor.Animations.AnimatorController animatorController)
{
CheckAnimatorController(animatorController, targetPath);
}
}
}
}
Repaint();
}
private void CheckGameObjectForAnimation(GameObject go, string targetPath)
{
// 检查Animator组件
Animator animator = go.GetComponent<Animator>();
if (animator != null && animator.runtimeAnimatorController != null)
{
CheckRuntimeAnimatorController(animator.runtimeAnimatorController, targetPath, go);
}
// 检查Animation组件
Animation animation = go.GetComponent<Animation>();
if (animation != null)
{
if (animation.clip != null && AssetDatabase.GetAssetPath(animation.clip) == targetPath)
{
referencedBy.Add(go);
}
foreach (AnimationState state in animation)
{
if (state.clip != null && AssetDatabase.GetAssetPath(state.clip) == targetPath)
{
referencedBy.Add(go);
}
}
}
}
private void CheckRuntimeAnimatorController(RuntimeAnimatorController controller, string targetPath, GameObject source = null)
{
if (controller is AnimatorOverrideController overrideController)
{
CheckAnimatorOverrideController(overrideController, targetPath, source);
}
else if (controller is UnityEditor.Animations.AnimatorController animatorController)
{
CheckAnimatorController(animatorController, targetPath, source);
}
}
private void CheckAnimatorController(UnityEditor.Animations.AnimatorController controller, string targetPath, GameObject source = null)
{
foreach (var clip in controller.animationClips)
{
if (clip != null && AssetDatabase.GetAssetPath(clip) == targetPath)
{
referencedBy.Add(source != null ? source : controller);
}
}
}
private void CheckAnimatorOverrideController(AnimatorOverrideController overrideController, string targetPath, GameObject source = null)
{
foreach (var clip in overrideController.animationClips)
{
if (clip != null && AssetDatabase.GetAssetPath(clip) == targetPath)
{
referencedBy.Add(source != null ? source : overrideController);
}
}
// 检查控制器的原始动画
if (overrideController.runtimeAnimatorController != null)
{
CheckRuntimeAnimatorController(overrideController.runtimeAnimatorController, targetPath, source);
}
}
}