MyFramework Unity:TweenSequence 和 DOTween 有什么区别

Unity 项目里做 Tween 动画,很多人第一时间会想到 DOTween。

这很正常。

DOTween 是非常成熟的 Unity Tween 引擎,常见写法很简单:

bash 复制代码
transform.DOMove(targetPos, 0.3f);
transform.DOScale(Vector3.one, 0.3f);
transform.DORotate(targetRot, 0.3f);

如果要做组合动画,可以使用 Sequence

bash 复制代码
Sequence sequence = DOTween.Sequence();
sequence.Append(transform.DOLocalMove(targetPos, 0.3f));
sequence.Join(transform.DOScale(Vector3.one, 0.3f));
sequence.AppendInterval(0.2f);
sequence.Append(transform.DOLocalMove(originPos, 0.3f));

DOTween 官方文档里也明确提供了 Sequence,并且支持 AppendJoinInsert 等方式组织多个 Tween。Insert 可以让 Tween 在指定时间点播放,Join 可以让 Tween 和前一个 Tween 同时播放。

MyFramework 里也有一套自己的 TweenSequence

但它的定位和 DOTween 不一样。

MyFramework 的 TweenSequence 不是为了重新实现一个通用 Tween 引擎。

它更像是框架内部的一套序列动画配置组件。

它服务的是:

  • 框架内 UI 动画
  • 框架内对象动画
  • Inspector 配置
  • 编辑器预览
  • 框架组件生命周期
  • Transformable 统一位置、缩放、旋转控制
  • 项目里固定动画规则

所以这篇文章不是要说谁更强。

而是具体说清楚:

MyFramework 的 TweenSequence 和 DOTween 到底有什么区别。

项目地址:

github.com/ZHOURUIH/My...


一、定位不同:通用 Tween 引擎 vs 框架内动画序列组件

DOTween 的定位是通用 Tween 引擎。

它面向的是整个 Unity 项目。

你可以用它处理:

  • Transform 动画
  • UI 动画
  • 材质动画
  • 颜色动画
  • 数值动画
  • 路径动画
  • 回调
  • 延迟
  • 循环
  • Sequence 拼接

它的优势是功能非常完整,API 也非常丰富。

典型 DOTween 写法是代码驱动:

bash 复制代码
transform.DOLocalMove(new Vector3(100.0f, 0.0f, 0.0f), 0.3f)
         .SetEase(Ease.OutQuad)
         .OnComplete(onMoveDone);

如果要组合动画,就写:

bash 复制代码
Sequence sequence = DOTween.Sequence();
sequence.Append(transform.DOLocalMove(targetPos, 0.3f));
sequence.Join(transform.DOScale(Vector3.one, 0.3f));
sequence.SetLoops(-1);

MyFramework 的 TweenSequence 不是这种定位。

它不是让业务层到处写链式 Tween 代码。

它更偏向:

把一个动画序列挂在对象上,然后由框架组件播放。

真实代码里,TweenSequence 是一个 MonoBehaviour

bash 复制代码
public class TweenSequence : MonoBehaviour
{
    public List<TweenGroup> mGroupList = new();
    public bool mLoop;
    private Vector3 mOriginPos;
    private Vector3 mOriginScale;
    private Vector3 mOriginRot;
    private bool mNeedResetOrigin;        // 是否需要重置原始位置、缩放和旋转,当播放过以后就需要重置
    public bool mResetWhenStop;           // 停止播放时是否重置到原始位置、缩放和旋转
}

它本身挂在 Unity 对象上。

动画内容通过 mGroupList 配置。

播放时不是直接调用 DOTween API,而是由框架组件 COMTransformableSequence 驱动。

所以两者最核心的区别是:

DOTween 是通用 Tween 引擎。

TweenSequence 是 MyFramework 框架里的可配置动画序列组件。


二、组织方式不同:DOTween 用 Append / Join,TweenSequence 用 Group / Track

DOTween 组织 Sequence 的方式是代码链式调用。

比如顺序播放:

bash 复制代码
Sequence sequence = DOTween.Sequence();
sequence.Append(transform.DOLocalMove(pos0, 0.3f));
sequence.Append(transform.DOScale(scale0, 0.2f));

同时播放:

bash 复制代码
Sequence sequence = DOTween.Sequence();
sequence.Append(transform.DOLocalMove(pos0, 0.3f));
sequence.Join(transform.DOScale(scale0, 0.3f));

插入到指定时间:

bash 复制代码
sequence.Insert(0.5f, transform.DORotate(rot, 0.3f));

这种方式非常灵活。

代码里可以动态决定添加哪些 Tween,执行顺序也很自由。

MyFramework 的 TweenSequence 是另一种组织方式。

它不是用 AppendJoin 这种链式代码组织,而是用:

  • TweenSequence
  • TweenGroup
  • TweenTrack

TweenSequence 里有多个 TweenGroup

bash 复制代码
public List<TweenGroup> mGroupList = new();

每个 TweenGroup 里有多个 TweenTrack

bash 复制代码
[Serializable]
public class TweenGroup
{
    public List<TweenTrack> mTrackList = new();
    public float getGroupLength()
    {
        float length = 0.0f;
        foreach (TweenTrack track in mTrackList)
        {
            if (!track.mEnable)
            {
                continue;
            }
            length += track.mDuration;
            length += track.mStartDelay;
        }
        return length;
    }
}

这里的结构很直观:

一个 Sequence 里有多个 Group。

一个 Group 里有多个 Track。

每个 Track 有自己的:

  • 类型
  • 曲线
  • 持续时间
  • 开始延迟
  • 起始值
  • 目标值
  • 是否启用
  • 目标模式
  • 起始模式

真实代码里,TweenTrack 的字段是这样的:

bash 复制代码
[Serializable]
public class TweenTrack
{
    protected MyCurve mCurve;                            // 用于在运行时缓存曲线对象
    protected Vector3 mRuntimeStart;                     // 缓存的起始值,避免在START_MODE.CURRENT模式下每次都要获取目标对象的当前值导致错误
    protected Vector3 mRuntimeTarget;                    // 轨道开始播放时的目标值
    protected bool mPlaying;                             // 是否正在播放
    protected float mBeginTime;                          // 轨道的开始时间,由TweenSequence在buildTimeline()时设置
    protected float mEndTime;                            // 轨道的结束时间,由TweenSequence在buildTimeline()时设置
    public TARGET_MODE mTargetMode = TARGET_MODE.VALUE;  // 目标值的获取方式
    public START_MODE mStartMode = START_MODE.VALUE;     // 起始值的获取方式
    public Transform mTargetTransform;                   // 参考的目标节点,TRANSFORM模式
    public Vector3 mTargetOffset;                        // 是否加偏移
    public TWEEN_TYPE mType;                             // 轨道类型,如位置、缩放、旋转等
    public int mCurveID;                                 // 曲线ID,用于在运行时获取曲线对象
    public float mDuration = 0.3f;                       // 持续时间
    public float mStartDelay;                            // 开始前的延迟时间
    public Vector3 mStartValue;                          // 起始值,在编辑器中设置,运行时根据目标对象的当前值进行调整
    public Vector3 mTargetValue;                         // 目标值,用于VALUE模式
    public bool mEnable = true;                          // 轨道是否启用
}

DOTween 的组织方式偏代码动态构建。

TweenSequence 的组织方式偏数据配置。

这是两者很大的区别。


三、能力边界不同:DOTween 很全,TweenSequence 只做框架需要的变换

DOTween 的能力非常丰富。

它不只支持 Transform,还支持很多 Unity 对象和属性。

常见的有:

  • Move
  • Rotate
  • Scale
  • Color
  • Fade
  • Text
  • Material
  • Path
  • Value Tween
  • Callback
  • Sequence
  • Loop
  • Ease

它适合做各种类型的 Tween 动画。

MyFramework 的 TweenSequence 当前能力更收敛。

它主要处理三类变换:

bash 复制代码
// 缓动的类型
public enum TWEEN_TYPE : byte
{
    MOVE,                   // 平移
    ROTATE,                 // 旋转
    SCALE,                  // 缩放
}

也就是说,它主要围绕 Transform 的三个核心属性:

  • 位置
  • 缩放
  • 旋转

这不是因为做不了别的,而是设计目标不同。

MyFramework 的 TweenSequence 主要服务框架里的 UI 和对象动画。

这些动画里最常用的就是:

  • UI 移动
  • UI 缩放
  • UI 旋转
  • 节点弹出
  • 节点收起
  • 对象位移动画
  • 对象缩放动画
  • 简单循环动画

所以它没有追求 DOTween 那种完整通用能力。

它更像是:

为了框架内高频动画场景做的一套轻量配置方案。

这也是两者的取舍差异。

DOTween 适合"我想 Tween 任意属性"。

TweenSequence 适合"我想在框架规则内配置一段位置、缩放、旋转序列"。


四、播放入口不同:DOTween 返回 Tween 句柄,TweenSequence 接入 COMTransformableSequence

DOTween 播放时,一般会返回 Tween 或 Sequence 对象。

比如:

bash 复制代码
Tween tween = transform.DOLocalMove(targetPos, 0.3f);
tween.Kill();

或者:

bash 复制代码
Sequence sequence = DOTween.Sequence();
sequence.Append(transform.DOLocalMove(targetPos, 0.3f));
sequence.Kill();

所以 DOTween 的生命周期通常由 Tween / Sequence 句柄控制。

MyFramework 的播放入口不是这样。

它通过框架命令 CmdTransformableSequence 播放。

真实代码:

bash 复制代码
// 缓动序列
public class CmdTransformableSequence
{
    public static void execute(ITransformable obj, SequenceCallback doneCallback)
    {
        if (obj == null)
        {
            return;
        }
        if (isEditor() && 
            obj is myUGUIObject uiObj && 
            !uiObj.getLayout().canUIObjectUpdate(uiObj))
        {
            logError("想要使窗口播放缓动动画,但是窗口当前未开启更新:" + uiObj.getName());
        }
        obj.getOrAddComponent(out COMTransformableSequence com);
        com.setDoneCallback(doneCallback);
        com.setActive(true);
        com.play(obj.tryGetUnityComponent<TweenSequence>());
        // 需要启用组件更新时,则开启组件拥有者的更新,后续也不会再关闭
        obj.setNeedUpdate(true);
    }

    public static void execute(ITransformable obj)
    {
        if (obj == null)
        {
            return;
        }
        obj.getComponent(out COMTransformableSequence com);
        if (com == null || !com.isActive())
        {
            return;
        }
        com.stop(true);
    }
}

这段代码说明了 MyFramework 的特点。

业务层不是直接操作 Tween 对象。

而是:

  • 传入一个 ITransformable
  • 获取或添加 COMTransformableSequence
  • 从 Unity 对象上获取 TweenSequence
  • 让组件开始播放
  • 自动开启对象更新

真正播放的是 COMTransformableSequence

bash 复制代码
// 用于播放物体的缓动序列
public class COMTransformableSequence : GameComponent
{
    protected SequenceCallback mDoneCallback;   // 序列播放完成的回调,参数1:当前组件,参数2:是否被打断
    protected TweenSequence mSequence;          // 当前正在播放的缓动序列
    protected float mCurrentTime;               // 从上一次从头开始播放到现在的时长
    protected float mTotalLength;               // 序列的总长度,即所有TweenGroup中最长的长度
    protected PLAY_STATE mPlayState;            // 播放状态
}

更新时由框架组件推进时间:

bash 复制代码
public override void update(float elapsedTime)
{
    base.update(elapsedTime);
    if (mPlayState == PLAY_STATE.PLAY)
    {
        mCurrentTime += elapsedTime;
        mSequence.evaluateSequence(mCurrentTime, out Vector3 pos, out Vector3 scale, out Vector3 rotation);
        var transformable = mComponentOwner as Transformable;
        transformable.setPosition(pos);
        transformable.setScale(scale);
        transformable.setRotation(rotation);
        // 是否结束播放
        if (mCurrentTime >= mTotalLength)
        {
            if (mSequence.mLoop)
            {
                mCurrentTime -= mTotalLength;
            }
            else
            {
                stop(false);
            }
        }
    }
}

这就是 MyFramework 的设计重点:

TweenSequence 不自己变成一个到处传递的 Tween 句柄。

它被框架组件接管,并通过 Transformable 生命周期播放。

这样做的好处是它可以和 MyFramework 的对象组件系统统一。

UI 对象、场景对象、框架 Transformable 对象,都可以走同一套组件更新流程。


五、起点和终点模式不同:TweenSequence 更强调配置时和运行时的组合

DOTween 里常见写法是直接传目标值:

bash 复制代码
transform.DOLocalMove(targetPos, 0.3f);

如果要相对移动,可以使用 DOTween 的相对模式,例如 SetRelative()

MyFramework 的 TweenTrack 里,起点和终点有自己的模式。

起始值模式:

bash 复制代码
// 缓动的起始值的类型
public enum START_MODE : byte
{
    VALUE,                  // 编辑器配置的固定值
    SELF,                   // 播放时取节点当前值
}

目标值模式:

bash 复制代码
// 缓动的目标类型
public enum TARGET_MODE : byte
{
    VALUE,                  // 固定值
    TRANSFORM_REALTIME,     // 指定节点,并且在移动过程中实时获取节点的值进行调整,适用于目标对象会移动的情况
    TRANSFORM_SNAPSHOT,     // 指定节点,但是只在开始移动时获取节点的值进行调整,适用于目标对象不会移动的情况
    SELF,                   // 指定节点,但是只在开始移动时获取节点的值进行调整,适用于目标对象不会移动的情况
}

这里很有框架味道。

它把常见动画需求分成了几类:

第一,固定值。

比如从配置的 A 点移动到配置的 B 点。

第二,播放时取自己当前值。

比如 UI 当前在哪里,就从哪里开始弹出。

第三,目标节点快照。

比如播放开始时取某个目标节点的位置,之后不再变化。

第四,目标节点实时值。

比如目标对象会移动,动画过程中持续追踪目标位置。

TweenTrack.getTargetValue 就是按这个规则取目标值:

bash 复制代码
public Vector3 getTargetValue(Transform transform)
{
    switch (mTargetMode)
    {
        case TARGET_MODE.VALUE:                 return multiVector3(getParentAnchorScale(transform), mTargetValue);
        case TARGET_MODE.TRANSFORM_REALTIME:    return generateTargetValue(mTargetTransform);
        case TARGET_MODE.TRANSFORM_SNAPSHOT:    return mRuntimeTarget;
        case TARGET_MODE.SELF:                  return mRuntimeTarget;
    }
    Debug.LogError("Unsupported tween type:" + mType);
    return Vector3.zero;
}

播放开始时会缓存运行时起点和目标点:

bash 复制代码
// 开始播放
public void play(Transform transform)
{
    mPlaying = true;
    // 起点只能在开始播放时获取,终点可以实时获取
    switch (mStartMode)
    {
        case START_MODE.VALUE: mRuntimeStart = multiVector3(getParentAnchorScale(transform), mStartValue); break;
        case START_MODE.SELF:  mRuntimeStart = getTransformValue(transform); break;
    }
    if (mTargetMode == TARGET_MODE.TRANSFORM_SNAPSHOT)
    {
        mRuntimeTarget = generateTargetValue(mTargetTransform);
    }
    else if (mTargetMode == TARGET_MODE.SELF)
    {
        mRuntimeTarget = generateTargetValue(transform);
    }
}

这说明 TweenSequence 的重点不是链式 API 灵活拼装。

它更强调:

动画可以配置好,但播放时仍然能根据当前对象状态和目标节点状态计算起点和终点。

这对 UI 很有用。

比如一个界面元素可能因为分辨率、适配、父节点缩放不同,最终位置不一定固定。

如果起点、终点完全写死,适配会比较麻烦。

TweenSequence 里还会处理 ScaleAnchor

bash 复制代码
protected static Vector3 getParentAnchorScale(Transform transform)
{
    Transform parent = transform.parent;
    if (parent != null && parent.TryGetComponent(out ScaleAnchor anchor))
    {
        return getScreenScale(anchor.mAspectBase);
    }
    return Vector3.zero;
}

这说明它和框架 UI 适配体系也有关系。

DOTween 更通用。

TweenSequence 更项目化。


六、预览方式不同:TweenSequence 有自己的 Inspector 编辑和预览

DOTween 主要是代码驱动。

当然也可以配合第三方工具或自己写编辑器,但 DOTween 本身最常见的使用方式还是代码调用。

MyFramework 的 TweenSequence 本身带 Inspector 编辑器。

TweenSequenceAuthoringEditor 是它的自定义 Inspector:

bash 复制代码
[CustomEditor(typeof(TweenSequence))]
[CanEditMultipleObjects]
public class TweenSequenceAuthoringEditor : GameInspector
{
    private TweenSequence mSequence;
    private bool mPlaying;
    private float mPreviewTime;
    private double mStartTime;
}

编辑器里可以添加 Group:

bash 复制代码
if (button("Add Group"))
{
    Undo.RecordObject(mSequence, "Add Group");
    mSequence.mGroupList.Add(new TweenGroup());
    EditorUtility.SetDirty(mSequence);
}

可以添加 Track:

bash 复制代码
if (button("Add Track"))
{
    Undo.RecordObject(mSequence, "Add Track");
    group.mTrackList.Add(new TweenTrack());
}

可以选择类型、曲线、持续时间、延迟、起始值、目标值。

比如这里显示 Track 的核心配置:

bash 复制代码
toggle("Enable", ref track.mEnable);

displayEnum("Type", ref track.mType);

int[] ids = EditorCurveFactory.getIDs();
if (ids.Length == 0)
{
    return;
}
if (track.mCurveID == 0)
{
    track.setCurveID(ids[0]);
}
ids.find(track.mCurveID, out int curIndex);
int newIndex = EditorGUILayout.Popup("Curve", curIndex, EditorCurveFactory.getNames());
track.setCurveID(ids[newIndex]);
EditorGUILayout.CurveField("Preview", EditorCurveFactory.getPreviewCurve(track.mCurveID), GUILayout.Height(20));

displayFloat("Duration", ref track.mDuration);
displayFloat("StartDelay", ref track.mStartDelay);

它还支持在编辑器里预览。

点击播放时:

bash 复制代码
private void StartPlay()
{
    mPlaying = true;
    // 播放之前先确认所有轨道都是在停止状态的
    mSequence.stop(true);
    mSequence.play();
    mStartTime = EditorApplication.timeSinceStartup;
    EditorApplication.update -= UpdatePreview;
    EditorApplication.update += UpdatePreview;
}

预览更新时会直接调用:

bash 复制代码
mSequence.evaluateSequence(currentTime, out Vector3 pos, out Vector3 scale, out Vector3 rot);
Transform transform = mSequence.transform;
transform.localPosition = pos;
transform.localScale = scale;
transform.localEulerAngles = rot;

这点和 DOTween 的使用习惯不同。

TweenSequence 的动画可以提前挂在对象上,在 Inspector 里调整和预览。

DOTween 更适合代码里临时组合、动态创建 Tween。

所以这里的区别是:

DOTween 更像程序式动画工具。

TweenSequence 更像框架内可配置动画组件。


七、停止和还原逻辑不同:TweenSequence 内置原始 Transform 记录

DOTween 停止动画时,通常会通过 Tween 或 Sequence 句柄调用:

bash 复制代码
tween.Kill();
sequence.Kill();

是否回到初始状态,需要自己处理,或者使用其他方式组合。

MyFramework 的 TweenSequence 内部会记录播放前的位置、缩放、旋转。

播放时记录:

bash 复制代码
public void play()
{
    if (mLoop && hasSelfValueType())
    {
        logError("存在SELF模式轨道时不允许循环播放");
        mLoop = false;
    }
    // 开始播放时设置每个Track的开始时间和结束时间
    foreach (TweenGroup group in mGroupList)
    {
        float time = 0.0f;
        foreach (TweenTrack track in group.mTrackList)
        {
            if (!track.mEnable)
            {
                continue;
            }
            time += track.mStartDelay;
            track.setBeginTime(time);
            time += track.mDuration;
            track.setEndTime(time);
        }
    }
    mOriginPos = transform.localPosition;
    mOriginScale = transform.localScale;
    mOriginRot = transform.localEulerAngles;
    mNeedResetOrigin = true;
}

停止时可以还原:

bash 复制代码
public void stop(bool forceReset = false)
{
    foreach (var group in mGroupList)
    {
        foreach (var track in group.mTrackList)
        {
            track.stop();
        }
    }
    if (mNeedResetOrigin && (mResetWhenStop || forceReset))
    {
        transform.localPosition = mOriginPos;
        transform.localScale = mOriginScale;
        transform.localEulerAngles = mOriginRot;
        mNeedResetOrigin = false;
    }
}

这里的 mResetWhenStop 是 Inspector 上的配置。

这说明 TweenSequence 把"停止时是否恢复原始状态"作为组件行为的一部分。

这个设计很适合 UI。

比如一个窗口打开时播放弹出动画,关闭或停止时希望回到原始 Transform。

如果每次都让调用方自己记原始坐标,就会很重复。

TweenSequence 直接把这件事放进组件里处理。


八、循环限制不同:TweenSequence 禁止 SELF 模式循环

DOTween 的循环能力很强。

常见写法是:

bash 复制代码
tween.SetLoops(-1);

或者:

bash 复制代码
sequence.SetLoops(-1);

MyFramework 的 TweenSequence 也支持循环:

bash 复制代码
public bool mLoop;

但是它有一个限制:

存在 SELF 模式轨道时不允许循环播放。

真实代码:

bash 复制代码
public void play()
{
    if (mLoop && hasSelfValueType())
    {
        logError("存在SELF模式轨道时不允许循环播放");
        mLoop = false;
    }
    ...
}

TweenGroup 里会检查是否存在 SELF:

bash 复制代码
public bool hasSelfValueType()
{
    foreach (TweenTrack track in mTrackList)
    {
        if (track.mStartMode == START_MODE.SELF || track.mTargetMode == TARGET_MODE.SELF)
        {
            return true;
        }
    }
    return false;
}

Editor 里也会禁止勾选 Loop:

bash 复制代码
EditorGUI.BeginDisabledGroup(mSequence.hasSelfValueType());
toggle("Loop", ref mSequence.mLoop);
EditorGUI.EndDisabledGroup();
if (mSequence.hasSelfValueType())
{
    mSequence.mLoop = false;
    EditorGUILayout.HelpBox("存在SELF模式轨道时不允许循环播放", MessageType.Warning);
}

这个限制很合理。

因为 SELF 模式会在播放时取当前对象状态。

如果循环播放,每一轮的起点或目标可能不断基于上一次结果变化,容易出现位置、缩放、旋转持续偏移。

所以 TweenSequence 直接在规则层限制掉。

这也是框架内工具和通用工具的区别。

DOTween 给你更大的自由度。

TweenSequence 会加更多项目规则,避免常见错误。


九、适合场景不同

DOTween 更适合这些场景:

  • 代码里动态创建动画
  • 需要 Tween 任意属性
  • 需要丰富 Ease 类型
  • 需要 Path、Punch、Shake 等复杂 Tween
  • 需要完整 Tween 生态
  • 需要快速写临时动画
  • 需要和第三方工具或插件配合
  • 项目没有自己的动画组件体系

MyFramework 的 TweenSequence 更适合这些场景:

  • 动画挂在 Prefab 上配置
  • 希望在 Inspector 里编辑和预览
  • 动画主要是位置、缩放、旋转
  • UI 打开、关闭、提示、弹出这类固定动画
  • 需要接入 Transformable 组件体系
  • 需要统一 setPosition / setScale / setRotation
  • 需要停止时恢复初始状态
  • 需要限制 SELF 模式循环这类项目规则
  • 不希望业务层直接管理 Tween 句柄

所以这两个东西不是同一个目标。

DOTween 更适合通用 Tween 编程。

TweenSequence 更适合 MyFramework 内部的可配置动画序列。


总结

MyFramework 的 TweenSequence 和 DOTween 最大的区别,不是能不能移动、缩放、旋转。

而是定位不同。

DOTween 是成熟的通用 Tween 引擎。

它提供丰富 API,适合代码动态创建各种动画。

MyFramework 的 TweenSequence 是框架内部的动画序列组件。

它通过:

  • TweenSequence
  • TweenGroup
  • TweenTrack
  • COMTransformableSequence
  • CmdTransformableSequence

把一段位置、缩放、旋转动画接入自己的框架生命周期。

从代码上可以看到:

  • TweenSequence 负责保存 Group 和 Track
  • TweenGroup 负责组织一组轨道
  • TweenTrack 负责单条轨道的类型、曲线、起点、终点、延迟和持续时间
  • COMTransformableSequence 负责更新时间并把结果设置到 Transformable
  • CmdTransformableSequence 负责对外提供统一播放和停止入口
  • TweenSequenceAuthoringEditor 负责 Inspector 配置和编辑器预览

所以它不是为了替代 DOTween。

它解决的是另一个问题:

如何让动画序列成为 MyFramework 自己框架体系的一部分。

一句话总结:

DOTween 更像一个强大的通用动画引擎。

TweenSequence 更像 MyFramework 内部的可配置动画组件。

通用引擎适合解决各种 Tween 需求。

框架内组件适合解决项目里固定、可配置、可预览、可接入生命周期的动画流程。

相关推荐
SmalBox1 天前
【节点】[IrisOffset节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox2 天前
【节点】[IrisLimbalRing节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox3 天前
【节点】[EyeSurfaceTypeDebug节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox4 天前
【节点】[CorneaRefraction节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox5 天前
【节点】[CirclePupilAnimation节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox6 天前
【节点】[Zigzag节点]原理解析与实际应用
unity3d·游戏开发·图形学
_zhourui_h_7 天前
Unity MyFramework: 框架中的那些非常实用的 GC 处理技巧
unity3d
SmalBox7 天前
【节点】[Whirl节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox8 天前
【节点】[Truchet节点]原理解析与实际应用
unity3d·游戏开发·图形学