#if UNITY_EDITOR using System; using UnityEditor; using UnityEditorInternal; using UnityEngine; using UnityEngine.UIElements; namespace TweenAnimation { [CustomEditor(typeof(TweenPath))] public class TweenPathEditor : Editor { TweenPath tweenPath; ReorderableList targetsList; int selectIndex = -1; private AnimationCurve inverseSpeedCurve; float startPos = 0f; SerializedProperty targetsProp; public override VisualElement CreateInspectorGUI() { tweenPath = (target as TweenPath); targetsProp = serializedObject.FindProperty("targets"); targetsList = new ReorderableList(serializedObject, targetsProp, true, true, true, true); targetsList.onSelectCallback += (_) => { if (selectIndex == targetsList.index) { targetsList.ClearSelection(); selectIndex = -1; } else { selectIndex = targetsList.index; var target = tweenPath.targets[selectIndex]; startPos = Time2StartPos(target.startPos); } }; targetsList.drawHeaderCallback = DrawHeader; targetsList.drawElementCallback = DrawListItems; targetsList.displayAdd = false; inverseSpeedCurve = new AnimationCurve(); for (int i = 0; i < tweenPath.speedCurve.length; i++) { float inWeight = (tweenPath.speedCurve.keys[i].inTangent * tweenPath.speedCurve.keys[i].inWeight); float outWeight = (tweenPath.speedCurve.keys[i].outTangent * tweenPath.speedCurve.keys[i].outWeight); Keyframe inverseKey = new Keyframe(tweenPath.speedCurve.keys[i].value, tweenPath.speedCurve.keys[i].time, 1 / tweenPath.speedCurve.keys[i].inTangent, 1 / tweenPath.speedCurve.keys[i].outTangent, inWeight, outWeight); inverseSpeedCurve.AddKey(inverseKey); } return base.CreateInspectorGUI(); } private void DrawListItems(Rect rect, int index, bool isActive, bool isFocused) { if (index < 0) { return; } EditorGUI.PropertyField(rect, targetsProp.GetArrayElementAtIndex(index).FindPropertyRelative("transform")); } private void DrawHeader(Rect rect) { string name = "目标物体"; EditorGUI.LabelField(rect, name); } private void UpdateTargets() { if (targetsProp.arraySize != tweenPath.transform.childCount) { var tr = tweenPath.transform; if (tweenPath.transform.childCount > targetsProp.arraySize) { var cnt = tweenPath.transform.childCount - targetsProp.arraySize; for (int i = 0; i < cnt; i++) { targetsProp.InsertArrayElementAtIndex(targetsProp.arraySize); targetsProp.GetArrayElementAtIndex(targetsProp.arraySize - 1).managedReferenceValue = new TweenPath.TweenTarget(); } } serializedObject.ApplyModifiedProperties(); for (int i = 0; i < targetsProp.arraySize; i++) { var target = targetsProp.GetArrayElementAtIndex(i).managedReferenceValue as TweenPath.TweenTarget; if (target == null) { targetsProp.GetArrayElementAtIndex(i).managedReferenceValue = new TweenPath.TweenTarget() { transform = tr.GetChild(i), startPos = 0 }; } else if (target.transform && target.transform.parent != tweenPath.transform) { targetsProp.DeleteArrayElementAtIndex(i); } else if (target.transform != tr.GetChild(i)) { target.transform = tr.GetChild(i); target.startPos = 0; } } } else { if (tweenPath.targets == null) { return; } Array.Sort(tweenPath.targets, (a, b) => { var ai = 0; var bi = 0; for (int i = 0; i < tweenPath.transform.childCount; i++) { if (tweenPath.transform.GetChild(i) == a.transform) { ai = i; } if (tweenPath.transform.GetChild(i) == b.transform) { bi = i; } } return ai.CompareTo(bi); }); } serializedObject.ApplyModifiedProperties(); } public override void OnInspectorGUI() { serializedObject.Update(); UpdateTargets(); base.OnInspectorGUI(); targetsList.DoLayoutList(); serializedObject.ApplyModifiedProperties(); } public void OnSceneGUI() { if (selectIndex == -1) { tweenPath.isEditing = false; Tools.hidden = false; return; } Tools.hidden = true; tweenPath.isEditing = true; DrawSelectHandle(); } private void DrawSelectHandle() { var target = tweenPath.targets[selectIndex]; target.transform.localPosition = tweenPath.path.EvaluateLocalPosition(startPos); var newPos = Handles.PositionHandle(target.transform.position, Quaternion.identity); startPos = tweenPath.path.FindClosestPoint(newPos, 0, 1, 1000); target.startPos = StartPos2Time(startPos); } private float Time2StartPos(float t) { var p = tweenPath.speedCurve.Evaluate(t); p = p * (tweenPath.path.MaxPos - tweenPath.path.MinPos); return p; } private float StartPos2Time(float pos) { var t = pos / (tweenPath.path.MaxPos - tweenPath.path.MinPos); t = inverseSpeedCurve.Evaluate(t); return t; } private void OnDestroy() { Tools.hidden = false; } } } #endif