在Unity开发过程中,我们都可能会需要用到DOTween来做一些补间动画,其中,这些补间动画往往会有一些曲线效果。那么,如何来查看这些曲线的轨迹以及曲线的作用效果呢?DOTween插件里好像没有对应的预览器,所以我在闲杂时间便撸了个代码,方便后面编辑动画时,查看动画曲线的效果。直接上代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using DG.Tweening;
public class EasingDemoPreviewWindow : EditorWindow
{
[MenuItem("Window/Dotween Easing Demo")]
public static void ShowWindow()
{
GetWindow<EasingDemoPreviewWindow>("Dotween Easing Demo");
}
const int POINT_COUNT = 60;
const float TIME_DELTATIME = 0.02f;
const int POINT_LENGTH = 10;
Ease _ease = Ease.Linear;
private int _easeEnumLength = 0;
Vector2 _rectStartPos = new Vector2(50,200);
private Vector3 _ballTmpPos = new Vector3(200, 200, -10);
private float _ballMoveTimer;
private float _ballMoveDuration = 5;
private bool _isBallMove = false;
private Vector2 _ballTargetPos;
private Vector3 _ballStartPos;
private Texture _ballTex;
private Texture _bgTex;
private float _overshootOrAmplitude = DOTween.defaultEaseOvershootOrAmplitude; // 过冲或振幅
private float _period = DOTween.defaultEasePeriod; // 周期
private void OnEnable()
{
var easeArray = System.Enum.GetValues(typeof(Ease));
_easeEnumLength = easeArray.Length - 2;
_ballTex = GetBallTexture();
_bgTex = GetBGTex();
EditorApplication.update += Update;
}
private void Update()
{
if (_isBallMove)
{
_ballMoveTimer += TIME_DELTATIME;
if (_ballMoveTimer > _ballMoveDuration)
{
_ballMoveTimer = _ballMoveDuration;
_isBallMove = false;
}
var lerp = Evaluate(_ease, _ballMoveTimer, _ballMoveDuration, _overshootOrAmplitude, _period);
_ballTmpPos.x = _ballStartPos.x + (_ballTargetPos.x - _ballStartPos.x) * lerp;
_ballTmpPos.y = _ballStartPos.y + (_ballTargetPos.y - _ballStartPos.y) * lerp;
Repaint();
}
}
private void OnGUI()
{
HandleEvent();
DrawBgGridUI();
DrawCurveUI();
DrawballUI();
}
private void OnDisable()
{
EditorApplication.update -= Update;
}
private void OnDestroy()
{
DestroyImmediate(_ballTex);
DestroyImmediate(_bgTex);
}
void HandleEvent()
{
if(Event.current.type == EventType.KeyDown)
{
int e = (int)_ease;
switch (Event.current.keyCode)
{
case KeyCode.UpArrow:
e--;
if (e < 0)
{
e = _easeEnumLength - 1;
}
_ease = (Ease)e;
break;
case KeyCode.DownArrow:
e++;
if (e > _easeEnumLength - 1)
{
e = 0;
}
_ease = (Ease)e;
break;
}
_isBallMove = false;
Repaint();
}
if (Event.current.type == EventType.MouseDown && Event.current.button == 0)
{
if(Event.current.mousePosition.y < _rectStartPos.y)
{
return;
}
_isBallMove = true;
_ballStartPos = _ballTmpPos;
_ballTargetPos = Event.current.mousePosition;
_ballMoveTimer = 0;
}
}
void DrawBgGridUI()
{
GUI.DrawTexture(new Rect(_rectStartPos.x, _rectStartPos.y, POINT_COUNT * POINT_LENGTH, POINT_COUNT * POINT_LENGTH), _bgTex);
}
void DrawCurveUI()
{
for (int i = 0; i < POINT_COUNT; i++)
{
var time = i * 1f;
var value = POINT_COUNT * Evaluate(_ease, time, POINT_COUNT, _overshootOrAmplitude, _period);
var p1 = new Vector2(_rectStartPos.x + time * POINT_LENGTH, _rectStartPos.y + POINT_COUNT * POINT_LENGTH - value * POINT_LENGTH);
if (i >= POINT_COUNT - 1)
{
continue;
}
var time2 = (i + 1) * 1f;
var value2 = POINT_COUNT * Evaluate(_ease, time2, POINT_COUNT, _overshootOrAmplitude, _period);
var p2 = new Vector2(_rectStartPos.x + time2 * POINT_LENGTH, _rectStartPos.y + POINT_COUNT * POINT_LENGTH - value2 * POINT_LENGTH);
Handles.color = Color.red;
Handles.DrawLine(p1, p2);
}
Handles.color = Color.white;
}
void DrawballUI()
{
_ease = (Ease)EditorGUILayout.EnumPopup("Easing:", _ease);
_ballMoveDuration = EditorGUILayout.FloatField("duration:", _ballMoveDuration);
_overshootOrAmplitude = EditorGUILayout.FloatField("overshootOrAmplitude:", _overshootOrAmplitude);
_period = EditorGUILayout.FloatField("period:", _period);
var rect = new Rect(_ballTmpPos.x - _ballTex.width/2, _ballTmpPos.y - _ballTex.height/2, _ballTex.width,_ballTex.height);
GUI.DrawTexture(rect, _ballTex);
}
Texture GetBallTexture()
{
var r = 32;
var tex = new Texture2D(r * 2, r * 2, TextureFormat.ARGB32, false);
var center = new Vector2(r, r);
Color c1 = Color.white;
for (int y = 0; y < tex.height; ++y)
{
for (int x = 0; x < tex.width; ++x)
{
var dis = Vector2.Distance(new Vector2(x, y), center);
c1.a = 1 - Evaluate(Ease.InExpo, dis, r, _overshootOrAmplitude, _period);
tex.SetPixel(x, y, c1);
}
}
tex.Apply();
tex.filterMode = FilterMode.Point;
tex.hideFlags = HideFlags.HideAndDontSave;
return tex;
}
Texture GetBGTex()
{
var tex = new Texture2D(64, 64);
Color c1 = new Color(0.5f, 0.5f, 0.5f, 0.82f);
for (int y = 0; y < tex.height; ++y)
{
for (int x = 0; x < tex.width; ++x)
{
tex.SetPixel(x, y, c1);
}
}
tex.Apply();
tex.filterMode = FilterMode.Point;
tex.hideFlags = HideFlags.HideAndDontSave;
return tex;
}
float Evaluate(Ease easeType, float time, float duration, float overshootOrAmplitude, float period)
{
return DG.Tweening.Core.Easing.EaseManager.Evaluate(easeType,null,time, duration, overshootOrAmplitude, period);
}
}
使用方法:把脚本放到Editor目录下,打开Window->DoTween Easing Demo
效果如下:
点击任意地方,小球会根据选择的曲线类型进行测试移动,更直观查看曲线运动轨迹。
注意:因为是DOTween曲线预览器,所以,工程里必须要有DOTween插件库,不然放到Unity里会报错