using UnityEngine; using UnityEditor; using UnityEditor.Animations; using UnityEditorInternal; using System.Collections.Generic; using AnimatorController = UnityEditor.Animations.AnimatorController; public class AnimatorLinkWindow : EditorWindow { private AnimatorController animatorController; private List clips = new List(); private ReorderableList reorderableList; // 排版参数 private int statesPerColumn = 5; private float horizontalSpacing = 200f; private float verticalSpacing = 80f; [MenuItem("Tools/Animator Link Window")] public static void ShowWindow() { GetWindow("Animator Linker"); } private void OnEnable() { reorderableList = new ReorderableList(clips, typeof(AnimationClip), true, true, true, true); reorderableList.drawHeaderCallback = (Rect rect) => { EditorGUI.LabelField(rect, "Animation Clips (可拖拽排序)"); }; reorderableList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { clips[index] = (AnimationClip)EditorGUI.ObjectField( new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), clips[index], typeof(AnimationClip), false); }; reorderableList.onAddCallback = (ReorderableList list) => { clips.Add(null); }; reorderableList.onRemoveCallback = (ReorderableList list) => { clips.RemoveAt(list.index); }; } private Vector2 scrollPos; private void OnGUI() { GUILayout.Label("Animator Controller", EditorStyles.boldLabel); animatorController = (AnimatorController)EditorGUILayout.ObjectField( "Controller", animatorController, typeof(AnimatorController), false); GUILayout.Space(10); // 排版参数输入框 statesPerColumn = EditorGUILayout.IntField("每列多少个状态", statesPerColumn); horizontalSpacing = EditorGUILayout.FloatField("同列水平间隔", horizontalSpacing); verticalSpacing = EditorGUILayout.FloatField("列与列垂直间隔", verticalSpacing); // 开始滚动区域 scrollPos = EditorGUILayout.BeginScrollView(scrollPos); GUILayout.Space(10); reorderableList.DoLayoutList(); EditorGUILayout.EndScrollView(); // 结束滚动区域 Rect dropArea = GUILayoutUtility.GetRect(0.0f, 50.0f, GUILayout.ExpandWidth(true)); GUI.Box(dropArea, "拖拽 AnimationClip 到这里 (支持多选)"); HandleDragAndDrop(dropArea); GUILayout.Space(10); if (GUILayout.Button("生成状态并连线")) { GenerateStatesAndTransitions(); } } private void HandleDragAndDrop(Rect dropArea) { Event evt = Event.current; if (!dropArea.Contains(evt.mousePosition)) return; switch (evt.type) { case EventType.DragUpdated: case EventType.DragPerform: if (DragAndDrop.objectReferences.Length > 0) { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; if (evt.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); foreach (Object obj in DragAndDrop.objectReferences) { if (obj is AnimationClip clip) { clips.Add(clip); } } Debug.Log($"已添加 {DragAndDrop.objectReferences.Length} 个动画"); } } Event.current.Use(); break; } } private void GenerateStatesAndTransitions() { if (animatorController == null) { Debug.LogError("请先指定 AnimatorController"); return; } if (clips.Count == 0) { Debug.LogError("请至少添加一个 AnimationClip"); return; } var rootStateMachine = animatorController.layers[0].stateMachine; // 判断是否已有状态 if (rootStateMachine.states.Length > 0) { int option = EditorUtility.DisplayDialogComplex( "已有状态", "当前 AnimatorController 已经有状态,是否清空后重新生成?", "清空并重新生成", "从尾部继续添加", "取消" ); if (option == 0) { // 清空 rootStateMachine.states = new ChildAnimatorState[0]; } else if (option == 2) { // 取消 return; } // option == 1 表示从尾部继续添加,不清空 } AnimatorState prevState = null; if (rootStateMachine.states.Length > 0) { // 如果已有状态,从最后一个开始连线 prevState = rootStateMachine.states[rootStateMachine.states.Length - 1].state; } int existingCount = rootStateMachine.states.Length; for (int i = 0; i < clips.Count; i++) { var clip = clips[i]; if (clip == null) continue; // ✅ 计算偏移量:已有状态数量 + 新的索引 int index = existingCount + i; int col = index / statesPerColumn; int row = index % statesPerColumn; var state = rootStateMachine.AddState( clip.name, new Vector3(col * horizontalSpacing, row * verticalSpacing, 0) ); state.motion = clip; if (prevState != null) { var transition = prevState.AddTransition(state); transition.hasExitTime = true; transition.exitTime = 1f; transition.duration = 0f; } prevState = state; } Debug.Log("生成完成:已按顺序创建状态并排版连线"); } }