DOTween官网提供了使用DOTween的实例,现在一一解析其中用法

http://dotween.demigiant.com/downloads/DOTweenExamples_Unity5.unitypackage

用例内容

Basics

Basic场景

Basic脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using UnityEngine;
using System.Collections;
using DG.Tweening;

public class Basics : MonoBehaviour
{
public Transform redCube, greenCube, blueCube, purpleCube;

IEnumerator Start()
{
// 一秒后启动 (避免Unity启动播放模式时卡顿)
yield return new WaitForSeconds(1);

// 将红色方块在两秒内移动到(0,4,0)
redCube.DOMove(new Vector3(0,4,0), 2);

// 将蓝色方块从(0,4,0)在两秒内移动到初始位置
greenCube.DOMove(new Vector3(0,4,0), 2).From();

// 使用SetRelative将蓝色方块在两秒移动到相对坐标(0,4,0)的位置
blueCube.DOMove(new Vector3(0,4,0), 2).SetRelative();

// 将紫色色方块在两秒移动到相对坐标(6,0,0)的位置
// 并且将颜色设为黄色
// 我们必须获取到方块的材质来改变颜色 (instead than its transform).
purpleCube.DOMove(new Vector3(6,0,0), 2).SetRelative();
// 使用SetLoops(-1, LoopType.Yoyo),来让材质颜色无限循坏,并且往返循环
purpleCube.GetComponent<Renderer>().material.DOColor(Color.yellow, 2).SetLoops(-1, LoopType.Yoyo);
}
}

转换后

Follow

初始位置

Follow脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using UnityEngine;
using System.Collections;
using DG.Tweening;

public class Follow : MonoBehaviour
{
public Transform target; // 跟随目标
Vector3 targetLastPos;
Tweener tween;

void Start()
{
// 开始时创建一个DOMOVE并且返回一个tweener.
// 设置SetAutoKill(false)从而能让这个tweener保持生效
// (否则这个tweener到达目标后就不会再执行了)
tween = transform.DOMove(target.position, 2).SetAutoKill(false);
// 储存目标的上一个位置,从而能够判断目标是否移动
// (防止目标在没有发生位置变化时一直计算tween)
targetLastPos = target.position;
}

void Update()
{
// 在Update阶段每帧更新tweener的EndValue()
// so that it updates to the target's position if that changed
if (targetLastPos == target.position) return;
// 使用ReStart(),来让tweener重新播放
tween.ChangeEndValue(target.position, true).Restart();
targetLastPos = target.position;
}
}

DragTarget脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using UnityEngine;
using System.Collections;

public class DragTarget : MonoBehaviour
{
Transform t;
Camera mainCam;
Vector3 offset;

void Start()
{
t = this.transform;
mainCam = Camera.main;
}

void OnMouseDown()//在这里记录偏移值,防止鼠标点击时方块突然移动到鼠标正中心
{
Vector2 mousePos = Input.mousePosition;
float distance = mainCam.WorldToScreenPoint(t.position).z;
Vector3 worldPos = mainCam.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, distance));
offset = t.position - worldPos;
}

void OnMouseDrag()
{
Vector2 mousePos = Input.mousePosition;
float distance = mainCam.WorldToScreenPoint(t.position).z;
t.position = mainCam.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, distance)) + offset;
}
}

拖动紫色方块

Materials

材质动画案例

Materials脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using UnityEngine;
using DG.Tweening;

public class Materials : MonoBehaviour
{
public GameObject target;
public Color toColor;

Tween colorTween, emissionTween, offsetTween;

void Start()
{
// NOTE: 所有的tween将被创建为一个暂停状态, 这样就可以通过UI来控制

// 首先获取材质
Material mat = target.GetComponent<Renderer>().material;

// 颜色补间动画
colorTween = mat.DOColor(toColor, 1).SetLoops(-1, LoopType.Yoyo).Pause();

// EMISSION贴图动画
// 注意在Unity的inspector中的EmissionColor是不能直接应用到材质的,我们必须直接书写shader中的名称
// 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贴图偏移动画
// LoopType.Incremental表示无限延长
offsetTween = mat.DOOffset(new Vector2(1, 1), 1).SetEase(Ease.Linear).SetLoops(-1, LoopType.Incremental).Pause();
}

// Toggle methods (called by UI events)使用TogglePause来改变Tween的暂停和播放状态

public void ToggleColor()
{
colorTween.TogglePause();
}

public void ToggleEmission()
{
emissionTween.TogglePause();
}

public void ToggleOffset()
{
offsetTween.TogglePause();
}
}

播放tween

Paths

路径移动

Paths脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using UnityEngine;
using System.Collections;
using DG.Tweening;

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).
// 使用SetOptions(true)来闭合路径
// 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);
}
}

脚本内容

通过自己设置Waypoints来形成路径

SetLookAt的方式

[DOTween - SetLookAt (demigiant.com)](http://dotween.demigiant.com/documentation.php?api=Path tween ➨ SetLookAt)

1
2
3
transform.DOPath(path, 4f).SetLookAt(new Vector3(2,1,3));
transform.DOPath(path, 4f).SetLookAt(someOtherTransform);
transform.DOPath(path, 4f).SetLookAt(0.01f);

CubicBezier模式

Sequence

序列案例

Sequences脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using UnityEngine;
using System.Collections;
using DG.Tweening;

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);

// 使用DOTween.Sequence来新建并返回一个新的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));
// 在Sequence开始执行时插入一个旋转补间,并且持续一半时间
// 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));
// 在Sequence执行一半时插入一个颜色变化补间,并且持续一半时间
s.Insert(duration / 2, cube.GetComponent<Renderer>().material.DOColor(Color.yellow, duration / 2));
// 循环整个sequence
s.SetLoops(-1, LoopType.Yoyo);
}
}

序列与 Tweener 类似,但它们不是为属性或值设置动画,而是将其他 Tweener 或序列作为一个组进行动画处理。

序列可以包含在其他序列中,而对层次结构的深度没有任何限制。

已排序的补间不必一个接一个。您可以使用 Insert 方法重叠补间。

补间(Sequence 或 Tweener)只能嵌套在单个其他序列中,这意味着您不能在多个序列中重复使用相同的补间。此外,主序列将控制其所有嵌套元素,您将无法单独控制嵌套补间(将序列视为电影时间线,一旦第一次启动就会固定)。 最后,请注意添加到序列的补间不能有无限循环(但根序列可以)。

重要提示:不要使用空序列。

sequences运行

UGUI

Dotween UGUI

工程引用设置

UGUI脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using DG.Tweening;

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.
// 没有设置无限循环的UI动画应该将AutoKill设为False,这样才可以Restart

// Animate the fade out of DOTween's logo
dotweenLogo.DOFade(0, 1.5f).SetAutoKill(false).Pause();

// Animate the circle outline's color and fillAmount,将image type改为Filled
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...使用SetRelative来添加
relativeText.DOText(" - This text will be added to the existing one", 2).SetRelative().SetEase(Ease.Linear).SetAutoKill(false).Pause();
// Animate the third (scrambled) text...设定ScrambleMode.All,就可以实现跳动出字的效果
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);
}
}

启动所有Tween

Custom Plugin

案例开始

在本例中将会展示如何制作用来补间一个自定义struct的DOTween插件

CuntomRange是一个用来被补间的自定义struct

CustomRangePlugin是一个用来补间CustomRange的自定义DOTween插件

CustomRange

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public struct CustomRange
{
public float min, max;

public CustomRange(float min, float max)
{
this.min = min;
this.max = max;
}

public static CustomRange operator +(CustomRange c1, CustomRange c2)
{
return new CustomRange(c1.min + c2.min, c1.max + c2.max);
}

public static CustomRange operator -(CustomRange c1, CustomRange c2)
{
return new CustomRange(c1.min - c2.min, c1.max - c2.max);
}
}

CustomRangePlugin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using DG.Tweening;
using DG.Tweening.Core;
using DG.Tweening.Core.Easing;
using DG.Tweening.Core.Enums;
using DG.Tweening.Plugins.Core;
using DG.Tweening.Plugins.Options;
using System;
using UnityEngine;

/// <summary>
/// Custom DOTween plugin example.
/// This one tweens a CustomRange value, but you can also create plugins just to do weird stuff, other than to tween custom objects
/// </summary>
public class CustomRangePlugin : ABSTweenPlugin<CustomRange, CustomRange, NoOptions>
{
// Leave this empty
public override void Reset(TweenerCore<CustomRange, CustomRange, NoOptions> t) {}

// Sets the values in case of a From tween 实现From
public override void SetFrom(TweenerCore<CustomRange, CustomRange, NoOptions> t, bool isRelative)
{
CustomRange prevEndVal = t.endValue;
t.endValue = t.getter();
t.startValue = isRelative ? t.endValue + prevEndVal : prevEndVal;
t.setter(t.startValue);
}

// Sets the values in case of a From tween with a specific from value
public override void SetFrom(TweenerCore<CustomRange, CustomRange, NoOptions> t, CustomRange fromValue, bool setImmediately, bool isRelative)
{
t.startValue = fromValue;
if (setImmediately) t.setter(fromValue);
}

// Used by special plugins, just let it return the given value
public override CustomRange ConvertToStartValue(TweenerCore<CustomRange, CustomRange, NoOptions> t, CustomRange value)
{
return value;
}

// Determines the correct endValue in case this is a relative tween
public override void SetRelativeEndValue(TweenerCore<CustomRange, CustomRange, NoOptions> t)
{
t.endValue = t.startValue + t.changeValue;
}

// Sets the overall change value of the tween
public override void SetChangeValue(TweenerCore<CustomRange, CustomRange, NoOptions> t)
{
t.changeValue = t.endValue - t.startValue;
}

// Converts a regular duration to a speed-based duration
public override float GetSpeedBasedDuration(NoOptions options, float unitsXSecond, CustomRange changeValue)
{
// Not implemented in this case (but you could implement your own logic to convert duration to units x second)
return unitsXSecond;
}

// Calculates the value based on the given time and ease
public override void EvaluateAndApply(NoOptions options, Tween t, bool isRelative, DOGetter<CustomRange> getter, DOSetter<CustomRange> setter, float elapsed, CustomRange startValue, CustomRange changeValue, float duration, bool usingInversePosition, UpdateNotice updateNotice)
{
float easeVal = EaseManager.Evaluate(t, elapsed, duration, t.easeOvershootOrAmplitude, t.easePeriod);

// Here I use startValue directly because CustomRange a struct, so it won't reference the original.
// If CustomRange was a class, I should create a new one to pass to the setter
startValue.min += changeValue.min * easeVal;
startValue.max += changeValue.max * easeVal;
setter(startValue);
}
}

接下来CustomPluginExampleBrain中应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using DG.Tweening;
using DG.Tweening.Plugins;
using UnityEngine;
using UnityEngine.UI;

public class CustomPluginExampleBrain : MonoBehaviour
{
public Text txtCustomRange ; // Used to show the custom range tween results

CustomRange customRange = new CustomRange(0, 10);

// Store the plugin so you won't have to instantiate it every time you use it
// (you can pass the same plugin instance to each tween, since they just do calculations and don't store data)
static CustomRangePlugin customRangePlugin = new CustomRangePlugin();

void Start()
{
// The difference with the regular generic way is simply
// that you have to pass the plugin to use as an additional first parameter
DOTween.To(customRangePlugin, () => customRange, x => customRange = x, new CustomRange(20, 100), 4);
}

void Update()
{
txtCustomRange.text = customRange.min + "\n" + customRange.max;
}
}

数值变化中