本文中大部分内容学习来自DOTween官方文档
此处无法展示动图(懒得录GIF),请下载官方案例场景自行学习
文章目录
- 场景1 基本补间
- 场景2 动态补间
- 场景3 Shader修改
- 场景4 路径拟合运动
- 场景5 序列播放
- 场景6 UGUI
场景1 基本补间
案例一展示了最基础的一些用法:
IEnumerator Start()
{
// Start after one second delay (to ignore Unity hiccups when activating Play mode in Editor)
yield return new WaitForSeconds(1);
// Let's move the red cube TO 0,4,0 in 2 seconds
redCube.DOMove(new Vector3(0,4,0), 2);
// Let's move the green cube FROM 0,4,0 in 2 seconds
greenCube.DOMove(new Vector3(0,4,0), 2).From();
// Let's move the blue cube BY 0,4,0 in 2 seconds
blueCube.DOMove(new Vector3(0,4,0), 2).SetRelative();
// Let's move the purple cube BY 6,0,0 in 2 seconds
// and also change its color to yellow.
// To change its color, we'll have to use its material as a target (instead than its transform).
purpleCube.DOMove(new Vector3(6,0,0), 2).SetRelative();
// Also, let's set the color tween to loop infinitely forward and backwards
purpleCube.GetComponent<Renderer>().material.DOColor(Color.yellow, 2).SetLoops(-1, LoopType.Yoyo);
}
解读一下代码,redCube的移动是在两秒内移动到了指定坐标0,4,0
,而greenCube移动带有From
方法,则是从坐标0,4,0
移动到原坐标。blueCube指定了SetRelative
,则会以自身坐标为原点,移动到相对于自身坐标轴的0,4,0
坐标上去。
而purpleCube除了应用Move的坐标变换,还将其组件的材质颜色进行了修改,使其由紫色变为黄色,并用SetLoops
将循环模式设置为了-1,LoopType.Yoyo
,第一个参数代表循环次数,-1代表了无限循环,第二个参数则代表了循环曲线模式。
场景2 动态补间
场景2实现了Follower对Followed的实时跟踪
public class Follow : MonoBehaviour
{
public Transform target; // Target to follow
Vector3 targetLastPos;
Tweener tween;
void Start()
{
// First create the "move to target" tween and store it as a Tweener.
// In this case I'm also setting autoKill to FALSE so the tween can go on forever
// (otherwise it will stop executing if it reaches the target)
tween = transform.DOMove(target.position, 2).SetAutoKill(false);
// Store the target's last position, so it can be used to know if it changes
// (to prevent changing the tween if nothing actually changes)
targetLastPos = target.position;
}
void Update()
{
// Use an Update routine to change the tween's endValue each frame
// so that it updates to the target's position if that changed
if (targetLastPos == target.position) return;
// Add a Restart in the end, so that if the tween was completed it will play again
tween.ChangeEndValue(target.position, true).Restart();
targetLastPos = target.position;
}
}
简单三行代码,轻松实现,效果比德芙还丝滑,用SetAutoKill(false)
确保Tween
不会被自动回收,使用targetLastPos
来每帧更新追踪(移动)的目标坐标,使用ChangeEndValue(target.position, true)
来改变Tween
的结束位置,第一个参数指定结束位置的值,第二个参数指定是否重新移动要从初始设置的值开始(还有一个重载函数public abstract Tweener ChangeEndValue(object newEndValue, float newDuration = -1, bool snapStartValue = false
,第二个float值决定是否设置新的Duration时长)。
最后使用Restart()
来重新开启补间动画。
场景3 Shader修改
public class Materials : MonoBehaviour
{
public GameObject target;
public Color toColor;
Tween colorTween, emissionTween, offsetTween;
void Start()
{
// NOTE: all tweens will be created in a paused state, so they can be toggled via the UI
// Store the material, since we will tween that
Material mat = target.GetComponent<Renderer>().material;
// COLOR
colorTween = mat.DOColor(toColor, 1).SetLoops(-1, LoopType.Yoyo).Pause();
// EMISSION
// Note that the float value you see in Unity's inspector, next to the emission's color,
// doesn't really exist in the shader (it's generated by Unity's inspector and applied to the material's color),
// se we have to tween the full _EmissionColor.
emissionTween = mat.DOColor(new Color(0, 0, 0, 0), "_EmissionColor", 1).SetLoops(-1, LoopType.Yoyo).Pause();
// OFFSET
// In this case we set the loop to Incremental and the ease to Linear, because it's cooler
offsetTween = mat.DOOffset(new Vector2(1, 1), 1).SetEase(Ease.Linear).SetLoops(-1, LoopType.Incremental).Pause();
}
// Toggle methods (called by UI events)
public void ToggleColor()
{
colorTween.TogglePause();
}
public void ToggleEmission()
{
emissionTween.TogglePause();
}
public void ToggleOffset()
{
offsetTween.TogglePause();
}
}
案例三中介绍了对shader中的材质的各种值的补间变化,定义了colorTween,emissionTween,ToggleOffset
三个Tween
的补间。DO
方法都是相似的,需要注意的是emissionTween
由于是直接改变Shader
中的值,所以用字符串读取了该Shader
中的_EmissionColor
。SetEase(Ease.Linear)
设置了增长类型并设定为线性的。
所有的Tween
在初始化时设置了Pause()
,当我们点击按钮时,触发TogglePause()
方法,如果正在播放则暂停,如果暂停则播放。
场景4 路径拟合运动
场景4允许我们自定义路径和坐标,让物体沿着坐标点拟合的路径进行运动
public class Paths : MonoBehaviour
{
public Transform target;
public PathType pathType = PathType.CatmullRom;
public Vector3[] waypoints = new[] {
new Vector3(4, 2, 6),
new Vector3(8, 6, 14),
new Vector3(4, 6, 14),
new Vector3(0, 6, 6),
new Vector3(-3, 0, 0)
};
void Start()
{
// Create a path tween using the given pathType, Linear or CatmullRom (curved).
// Use SetOptions to close the path
// and SetLookAt to make the target orient to the path itself
Tween t = target.DOPath(waypoints, 4, pathType)
.SetOptions(true)
.SetLookAt(0.001f);
// Then set the ease to Linear and use infinite loops
t.SetEase(Ease.Linear).SetLoops(-1);
}
}
想要拟合出路径,只需要设置好坐标点数组Vector3[]
,然后设定补间时间,最后设定拟合路径的曲线类型pathType
,默认是线性的。使用SetOptions
来设定路径是否闭合,(注意,SetOptions
是一个很特别的方法,对于不同的DO
方法,对应的SetOptions
有不同的参数,具体还是得看官方文档)。DOPath
也有重载方法,学会查看引用和查阅官方文档是很重要的事情!
场景5 序列播放
public class Sequences : MonoBehaviour
{
public Transform cube;
public float duration = 4;
IEnumerator Start()
{
// Start after one second delay (to ignore Unity hiccups when activating Play mode in Editor)
yield return new WaitForSeconds(1);
// Create a new Sequence.
// We will set it so that the whole duration is 6
Sequence s = DOTween.Sequence();
// Add an horizontal relative move tween that will last the whole Sequence's duration
s.Append(cube.DOMoveX(6, duration).SetRelative().SetEase(Ease.InOutQuad));
// Insert a rotation tween which will last half the duration
// and will loop forward and backward twice
s.Insert(0, cube.DORotate(new Vector3(0, 45, 0), duration / 2).SetEase(Ease.InQuad).SetLoops(2, LoopType.Yoyo));
// Add a color tween that will start at half the duration and last until the end
s.Insert(duration / 2, cube.GetComponent<Renderer>().material.DOColor(Color.yellow, duration / 2));
// Set the whole Sequence to loop infinitely forward and backwards
s.SetLoops(-1, LoopType.Yoyo);
}
}
使用序列可以执行多个Tween
,正常Append
的话就是像委托一样的一个一个地执行,(感兴趣可以试试下面的代码),这样子的话整个动画的执行就是每个Append
中的Tween
依次执行动画,也就是先移动,再旋转,再变色,而执行完毕之后由于设置了loop,整个序列动画会再倒放一次,直到回到原始状态又开始播放。
而使用Insert
方法,我们可以设定什么时间点可以直接播放Tween
补间动画,由第一个参数指定播放的时间即可。这样就可以再移动的同时,也会旋转和变色了。并且Sequence
作为一个整体,只有全部动画播完才会循环倒放,而不是各个Tween
独自计算播放循环,各个Tween
是相关联的。
public class Sequences : MonoBehaviour
{
public Transform cube;
public float duration = 4;
IEnumerator Start()
{
// Start after one second delay (to ignore Unity hiccups when activating Play mode in Editor)
yield return new WaitForSeconds(1);
// Create a new Sequence.
// We will set it so that the whole duration is 6
Sequence s = DOTween.Sequence();
// Add an horizontal relative move tween that will last the whole Sequence's duration
s.Append(cube.DOMoveX(6, duration).SetRelative().SetEase(Ease.InOutQuad));
// Insert a rotation tween which will last half the duration
// and will loop forward and backward twice
s.Append( cube.DORotate(new Vector3(0, 45, 0), duration / 2).SetEase(Ease.InQuad).SetLoops(2, LoopType.Yoyo));
// Add a color tween that will start at half the duration and last until the end
s.Append(cube.GetComponent<Renderer>().material.DOColor(Color.yellow, duration / 2));
// Set the whole Sequence to loop infinitely forward and backwards
s.SetLoops(-1, LoopType.Yoyo);
}
}
场景6 UGUI
该场景展示了一些使用DOTween
实现的常见的动画效果,包括图像渐入渐出,循环环状载入条,循环条状条,字体变化等等。
public class UGUI : MonoBehaviour
{
public Image dotweenLogo, circleOutline;
public Text text, relativeText, scrambledText;
public Slider slider;
void Start()
{
// All tweens are created in a paused state (by chaining to them a final Pause()),
// so that the UI Play button can activate them when pressed.
// Also, the ones that don't loop infinitely have the AutoKill property set to FALSE,
// so they won't be destroyed when complete and can be resued by the RESTART button
// Animate the fade out of DOTween's logo
dotweenLogo.DOFade(0, 1.5f).SetAutoKill(false).Pause();
// Animate the circle outline's color and fillAmount
circleOutline.DOColor(RandomColor(), 1.5f).SetEase(Ease.Linear).Pause();
circleOutline.DOFillAmount(0, 1.5f).SetEase(Ease.Linear).SetLoops(-1, LoopType.Yoyo)
.OnStepComplete(()=> {
circleOutline.fillClockwise = !circleOutline.fillClockwise;
circleOutline.DOColor(RandomColor(), 1.5f).SetEase(Ease.Linear);
})
.Pause();
// Animate the first text...
text.DOText("This text will replace the existing one", 2).SetEase(Ease.Linear).SetAutoKill(false).Pause();
// Animate the second (relative) text...
relativeText.DOText(" - This text will be added to the existing one", 2).SetRelative().SetEase(Ease.Linear).SetAutoKill(false).Pause();
// Animate the third (scrambled) text...
scrambledText.DOText("This text will appear from scrambled chars", 2, true, ScrambleMode.All).SetEase(Ease.Linear).SetAutoKill(false).Pause();
// Animate the slider
slider.DOValue(1, 1.5f).SetEase(Ease.InOutQuad).SetLoops(-1, LoopType.Yoyo).Pause();
}
// Called by PLAY button OnClick event. Starts all tweens
public void StartTweens()
{
DOTween.PlayAll();
}
// Called by RESTART button OnClick event. Restarts all tweens
public void RestartTweens()
{
DOTween.RestartAll();
}
// Returns a random color
Color RandomColor()
{
return new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 1);
}
}
使用DOFade
实现渐隐效果,第一个是alpha值,第二个参数是补间时间。
环状进度条变化的代码很巧妙,首先使用DOFillAmount
对image组件进行百分比的填充,这是基于组件本身的填充模式的,在本场景中该组件的填充模式是顺时针,但是SetLoops()
是会倒放补间动画的,也就是刚开始播放时,环状进度条顺时针减少,接着如果倒放就会变成逆时针增加,但是顺时针增加会比逆时针增加好看很多,所以在这里用了OnStepComplete
来判断当补间动画播放完毕的时候,添加一个委托,让指针方向取反,顺时针就成了逆时针,而逆时针对应倒放就是顺时针,从而实现了顺时针减少进度条,倒放时顺时针增加进度条。而之所以重新定义了DOColor
的补间动画,是希望颜色能够始终随机变化,而不是倒放回去。
DOText
展现了三种文字变化的模式,分别对应逐字变化,空白打字,乱码显字三种字体的显示效果。按照上述代码设置即可。
最后就是PlayAll
和RestartAll
,这两个方法控制所有的Tween
的行为。
使用DOTween
,能够简单地实现强大的视觉效果,真的牛b。