Unity - DOTween库的使用问题

文章目录

  • 使用 DOTween 来实现的小游戏部分动画内容
    • 封面
    • 封面继续
    • 菜单项
    • 进入对战场景
  • unity tween libs
    • [Do Tween](http://dotween.demigiant.com/)
    • LeanTween
    • iTween
  • DOTween
    • DOTween 使用的一些注意问题
      • 协程中的 WaitForCompletion
      • 判断一个 tween 是否完成
      • kill 一个 tween
      • Pause 与 Resume 不对称
      • OnComplete 在 Sequence 与 Tween 中使用

这几天做了个小游戏,给家里人玩玩,其中很多东西需要自己去弄:

  • 程序 : CSharp、ShaderLab
  • 动画 : DOTween(没去用 Unity 的 Animation 或是 Timeline)
  • 美术 : 配色,部分纹理
  • UI : 使用 UGUI(不熟悉,都是临时查阅资料就能用)
  • AI : 因为游戏比较简单,AI 也没用行为树,直接配置控制甩武器的速度参数即可即可
  • 特效 : Unity 粒子系统(不熟悉,都是临时查阅资料就能用)
  • 音效 : 自己网上找免费资源
  • 模型 : Unity 内置 Cube,Sphere,Cylinder 足够了,要是对外发布,可能还要自己学习建模 Blender(有计划,现在还没开始,惭愧)

使用 DOTween 来实现的小游戏部分动画内容

封面

Unity - DOTween库的使用问题_第1张图片

封面继续

Unity - DOTween库的使用问题_第2张图片

菜单项

Unity - DOTween库的使用问题_第3张图片
Unity - DOTween库的使用问题_第4张图片

进入对战场景

这里就不演示对战内容了(也特效,AI,镜头效果,结算,等)
还可以实现一些出场动画,等,其实这个小游戏项目可以完善的内容挺多的
Unity - DOTween库的使用问题_第5张图片

最后是战斗中返回开始界面
Unity - DOTween库的使用问题_第6张图片

总体来说,DOTween 虽然用起来不够顺手,但是也够用,相比,iTween,LeanTween 都好用一些。

部分动画我本想用 Unity Animation 来实现的,但是反而觉得可控制不太友好,所以就使用 Tween 库来封装一些类来处理,也是比较灵活的,如果是公司项目要给策划用的编辑器就不一样了,项目的接口设计会完全不一样。

这个小游戏项目从无到有,完全没用到以前积累的东西,也是蛋疼。

也是对 Unity 不够熟悉。

代码写得非常的简单易懂,基本没封装什么东西,就封装了一个 Loading 场景的统一处理,其他都是乱七八糟的代码。。。-_-!!!

后面有空需要去参考一些 Unity 现成的一些框架,参考他们的设计,再做适合自己项目的封装。

不然以后使用起来制作就相当麻烦了。


在使用一些动画的时候,找了一些 Tween 缓存库。

于是找了下面三个(最后我选择使用了:DOTween)。


unity tween libs

花了一个上午,看完了三个 tween 库的介绍与文档,总结:

  • Do Tween

    • Unity 中的 Tween 引擎,说是引擎也不为过,因为功能相当丰富,而且很多平台多有封装库,如果想要在多个平台使用 tween 库,这是不二之选。
    • Do Tween 官方文档 - 文档做得相当良心,谁看谁知道。
    • Dotween常用方法详解 - 中文的话这位博主总结的挺不错。
    • Unity - DOTween库的使用问题_第7张图片Unity - DOTween库的使用问题_第8张图片Unity - DOTween库的使用问题_第9张图片
  • LeanTween

    • docment : http://dentedpixel.com/LeanTweenDocumentation/classes/LeanTween.html
    • 风格与以前使用 AS3 的 Greensock 比较像
    • Unity - DOTween库的使用问题_第10张图片
  • iTween

    • 个人感觉是制作最不用心的,作为学习的话,也是可以用,因为库相当精简,回调函数我看过竟然限制于 GameObject 内的组件的方法,用 SendMessage 来广播的极地效率的方式。
    • iTween assetstore
    • Unity3D关于iTween知识详解和接口总结

DOTween

个人选择使用的是:DOTween,因为功能还是比较强大的。(说真的,这些所有的 Unity Tween 库使用起来都没有以前使用 AS3 的 greensock 那么顺手)


DOTween 使用的一些注意问题

协程中的 WaitForCompletion

如果 tween_show_loading 的动画足够短,并且直接 在 tween_show_loading 之前,还有一个比较长时间的动画,那么直接 yield return tween_show_loading.WaitForCompletion 可能会报一些警告:This Tween has been killed and is now invalid

代码如下:

    IEnumerator _StartHideLoading()
    {
        _KillRollingTrackerTween();

        tween_rolling_tracker = tracker.DOLocalMove(target_roll_tracker_move_in_pos, 1.0f)
            .SetEase(Ease.Linear);

        var seq = loadingBar.Hide();

        if (tween_rolling_tracker.active) yield return tween_rolling_tracker.WaitForCompletion();
        Debug.Log("after yield return tween_rolling_tracker.WaitForCompletion();");

        //if (seq.active) yield return seq.WaitForCompletion();
        yield return seq.WaitForCompletion();
        Debug.Log("after yield return seq.WaitForCompletion();");

        _KillHideLoadingSeq();

        tween_hide_loading = contentCG.DOFade(0.0f, 0.5f);

        yield return tween_hide_loading.WaitForCompletion();
        Debug.Log("after yield return seq_hide_loading.WaitForCompletion();");
        
        loadingRoot.SetActive(false);
    }

Unity - DOTween库的使用问题_第11张图片

Unity - DOTween库的使用问题_第12张图片

解决:如下面 判断一个 tween 是否完成的方式,在前面多加一句:if (xxx.active) 就可以了


判断一个 tween 是否完成

  • 第一:bool Tween.IsComplete() ; 但要确保你的 tween 不是 autoKill,默认所有的 tween 都是 autoKill 的,除非显示设置 AutoKill(false);
  • 第二:Tween.active 如果你的 tween 是 autoKill 的,那么可以使用 tween.active 来判断

下面的代码演示就是一个 autoKill 的tween 在判断是否完成了或有效的方法

// 如果还是有效的、激活的,或是未那么可以使用 WaitForCompletion 来等待完成
if (tween_show_loading.active) yield return tween_show_loading.WaitForCompletion();

kill 一个 tween

有还几种方式

tween.Kill();
DOTween.Kill(tween.id);
DOTween.Kill(tween.intId);
DOTween.Kill(tween.stringId);

但是最好还是使用:一个独立的 string 来保存起来,再 Kill

(为何要用 Kill,因为有些动画需要重复频率操作很多的特别需要各种 Kill,以前使用 AS3 就经常需要这么处理,不然动画会有冲突)

代码如下:

tween 同一时刻只有一个,可以这么写:

private void ShowXXX()
{
	DOTween.Kill($"{GetType().Name}"); // 如果你嫌弃效率问题,可以保存起来
	xxx.DOXXX().SetXXX().SetXXX().SetID($"{GetType().Name}");
}

如果 tween 对象可以有多个,那么需要其他的写法,或是使用 Sequence 来处理。

如果 Sequence 处理起来吃力,就使用 Unity 的 Coroutine + Sequence 来处理即可

可能有同学问,为何不使用 int 的方式,保存一个 int 比起一个 string 效率好多了,内存也少

但是我也试过了,会有问题,具体我也没去看 DOTween 开源的逻辑了,后面如果需要,还需要看它的 Git 代码,还考虑需要亲手去修改代码。

使用 int 的方式的 代码,如下:

private static int tween_id_counter;
private int tween_id = -1;
private void ShowXXX()
{
	if (tween_id != -1) {
		DOTween.Kill(tween_id);
	}
	tweenId = ++tween_id_counter;
	xxx.DOXXX().SetXXX().SetXXX().SetId(tweenId).OnComplete(()=>{tweenId = -1});
}

上面的 tween 同一时刻只能有一个,如果上次的没有运行完,那么就需要先将之前未完成的先 kill 掉。

我的代码曾经这样使用过,发现动画有异常。但是如果使用上面 string 的方式就没有问题。暂时没去查看代码(使用的是 .dll 的 DOTween)


Pause 与 Resume 不对称

有 Pause 但 “没有” Resume。注意打双引号的 没有

因为它的 Resume 还是使用 Play 来处理。

如,下伪代码:

private Tween tween;
private void ToggleTween()
{
	if (tween == null) 
	{
		tween = go_transform.DOMoveX(
				()=>the_x,value=>the_x=value,100,1.0f)
				.SetLoops(-1, LoopType.Restart));
	}
	else
	{
		// resume
		if (tween.isPlaying()) 	tween.Play().SetLoops(-1, LoopType.Restart); // 注意参数要重新设置
		// pause
		else 					tween.Pause();
	}
}

其中注意我的注释中的一句, resume 处理需要恢复参数,所以 DOTween 的 Resume 是用会 Play() 来处理的(我习惯了很多 Tween 库都是有 Resume 的,一下当时没找到,试了一下 Play,果然还真是,只不过,后来发现不会重复播放了,所以我有重新设置会参数,注意 Pause 后的 tween 再次 play 会从当前的一些数据继续播放,但是就是前面说的,一些状态参数又需要重新设置了,这些设置不应该的,按道理是可以做到不到重复设置状态参数的,但暂时没有兴趣去看源码)


OnComplete 在 Sequence 与 Tween 中使用

在 Tween 中使用如下代码:

trans.DOXXX().OnComplete(()=>{Debug.Log("Test1");});

一般不出什么意外 "Test1" 的输出还是比较确定的

但如果使用 Sequence:

var seq = DOTween.Sequence();
seq.Append(trans.DOXXX(....));
seq.Append(trans.DOXXX(....));
seq.AppendInterval(1.0f);
seq.OnComplete(()=>{Debug.Log("Test2");});

基本上补回输出 "Test2"

但如果 Sequence 完成的回调使用 AppendCallback 来替代就比较稳定

var seq = DOTween.Sequence();
seq.Append(trans.DOXXX(....));
seq.Append(trans.DOXXX(....));
seq.AppendInterval(1.0f);
seq.AppendCallback(()=>{Debug.Log("Test2");}); // 注意此句使用 AppendCallback

这样就可以输出 "Test2"

而我看了一下:Sequence 就一个空类,但是继承与 Tween 的,因为作者使用 public static RET_TYPE Extension_Func(this XXX xxx, ArgType1 .., ArgTypeN...); 的方式来扩展 Sequence 与 Tween 的方法来处理的

所以这些 OnComplete 的差异也是不应该的

你可能感兴趣的:(unity)