200 lines
6.6 KiB
C#
Raw Normal View History

2025-11-05 17:34:40 +08:00
#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