1. DG.Tweening入门:为什么它是Unity动画的首选工具
第一次接触DG.Tweening是在五年前的一个手游项目里,当时需要实现一个复杂的UI入场动画。手动写协程和Lerp函数让我差点崩溃,直到同事推荐了这个神器。用transform.DOMoveX(5, 1f)替代了十几行代码的那一刻,我就知道这工具会改变我的开发方式。
DG.Tweening本质上是一个补间动画库,但它把Unity中的动画编程从"写代码"变成了"写句子"。比如要让一个物体在1秒内移动到x=5的位置,传统方法需要写时间计算、插值运算,而用DG.Tweening只需要:
transform.DOMoveX(5, 1f).SetEase(Ease.OutBack);这个简单的例子展示了它的三大优势:
- 链式语法:像说话一样串联动画指令
- 预设缓动曲线:OutBack这种弹簧效果原本需要复杂数学计算
- 极简API:方法名直指意图(DOMoveX就是Do Move on X axis)
我特别喜欢它在性能上的表现。在最近的一个2D横版游戏中,同时运行200+个物体动画时,DG.Tweening的CPU占用率比Unity原生Animator低了近40%。这得益于它内部的对象池设计和值计算优化。
安装过程简单到令人发指:
- 从Asset Store导入DOTween.unitypackage
- 在任意脚本中添加
using DG.Tweening; - 首次运行时自动初始化(或手动调用DOTween.Init())
提示:如果遇到API无法识别的问题,检查是否勾选了DOTween的模块支持。比如要做UI动画就需要在Tools/Demigiant/DOTween Utility Panel中激活UI模块。
2. 核心API深度解析:从基础运动到高级控制
2.1 四大基础动画类型
位移动画是使用频率最高的功能。除了基本的DOMove,我经常用DOMoveX/Y/Z做轴锁定。比如角色受击后退效果:
// 只影响X轴,避免角色浮空或下陷 enemy.DOMoveX(transform.position.x - 2, 0.3f) .SetEase(Ease.OutQuad);旋转动画有个坑我踩过多次——旋转模式。默认的RotateMode.Fast性能最好但不保证最短路径,做360度旋转时会抽搐。后来我都改用RotateMode.LocalAxisAdd:
// 道具收集时的旋转效果 item.DORotate(new Vector3(0, 360, 0), 1f, RotateMode.LocalAxisAdd) .SetLoops(-1, LoopType.Restart);缩放动画最实用的技巧是配合Punch效果。比如按钮点击反馈:
button.DOPunchScale(Vector3.one * 0.2f, 0.3f) .SetEase(Ease.OutBack);透明度动画不仅用于UI,也适用于粒子系统。最近做的一个技能消散效果:
particleSystem.GetComponent<Renderer>().material.DOFade(0, 0.5f) .OnComplete(() => Destroy(gameObject));2.2 动画控制的黑科技
回调系统是动画逻辑的粘合剂。OnComplete/OnStart这些基础回调大家都会用,但OnUpdate的潜力很多人没发掘。比如实现进度条数值跟随:
float fakeProgress = 0; slider.DOValue(1, 2f) .OnUpdate(() => { progressText.text = $"{fakeProgress:P0}"; fakeProgress += Time.deltaTime / 2f; });动画混合是高级技巧。通过SetAs可以复制动画参数:
var baseTween = transform.DOMoveX(5, 1f) .SetEase(Ease.InOutSine); material.DOColor(Color.red, 1f) .SetAs(baseTween); // 继承相同的持续时间和缓动曲线3. Sequence序列动画:复杂动画编排的艺术
3.1 基础序列构建
第一次用Sequence是在做新手引导时,需要实现"高亮按钮→箭头指向→气泡弹出"的连贯效果。传统方法需要维护多个协程,而Sequence让一切变得优雅:
var guideSeq = DOTween.Sequence(); guideSeq.Append(button.DOScale(1.2f, 0.3f)); // 第一步 guideSeq.Append(arrow.DOMove(targetPos, 0.5f)); // 上一步完成后执行 guideSeq.Join(bubble.DOFade(1, 0.2f)); // 与上一步同时开始 guideSeq.PrependInterval(1f); // 整个序列开始前等待Join与Append的区别是很多人容易混淆的点。简单来说:
- Append是"之后做",加入队列末尾
- Join是"一起做",与上一个动画并行
3.2 高级序列技巧
循环控制的SetLoops参数很强大。做闪烁警告效果时:
DOTween.Sequence() .Append(renderer.material.DOColor(Color.red, 0.3f)) .Append(renderer.material.DOColor(Color.white, 0.3f)) .SetLoops(3, LoopType.Yoyo) // 往返循环3次 .OnComplete(() => Debug.Log("警告结束"));时间缩放在游戏暂停时特别有用。通过SetUpdate可以控制动画是否受Time.timeScale影响:
// UI动画应该无视游戏暂停 menu.DOMoveX(100, 1f) .SetUpdate(true); // 使用独立时间4. 实战案例:从UI交互动画到技能连招
4.1 高级UI动画系统
去年我们项目需要一套统一的UI动画规范,最终基于DG.Tweening开发了动画模板系统。核心思路是预定义动画片段:
public static Tween BounceIn(RectTransform target) { target.localScale = Vector3.zero; return target.DOScale(Vector3.one, 0.5f) .SetEase(Ease.OutBack); } public static Tween FadeOut(CanvasGroup group) { return group.DOFade(0, 0.3f) .SetEase(Ease.OutQuad); }使用时可以灵活组合:
// 弹窗关闭动画 Sequence closeAnim = DOTween.Sequence(); closeAnim.Append(BounceIn(transform).PlayBackwards()) .Join(FadeOut(GetComponent<CanvasGroup>()));4.2 角色技能连招系统
在ARPG项目中,我们用Sequence实现了三段式技能连招:
public void PlayComboAttack(int comboStep) { if (currentSequence != null && currentSequence.IsPlaying()) { currentSequence.Complete(true); // 强制完成当前动画 } currentSequence = DOTween.Sequence(); // 根据连招段数选择不同动作 switch (comboStep) { case 1: currentSequence.Append(animator.DOPlay("Slash1")); currentSequence.Join(weaponTrail.DOEmissive(Color.white, 0.2f)); break; case 2: currentSequence.Append(animator.DOPlay("Slash2")); currentSequence.Join(transform.DOMoveX(2, 0.3f).SetRelative()); break; case 3: currentSequence.Append(animator.DOPlay("SpinAttack")); currentSequence.AppendCallback(() => PlayExplosionVFX()); break; } currentSequence.OnComplete(() => comboSystem.ResetCombo()); }这套系统后来扩展支持了技能取消、连招分支等高级特性,全部基于DG.Tweening的动画控制API实现。