这里就不演示对战内容了(也特效,AI,镜头效果,结算,等)
还可以实现一些出场动画,等,其实这个小游戏项目可以完善的内容挺多的
总体来说,DOTween 虽然用起来不够顺手,但是也够用,相比,iTween,LeanTween 都好用一些。
部分动画我本想用 Unity Animation 来实现的,但是反而觉得可控制不太友好,所以就使用 Tween 库来封装一些类来处理,也是比较灵活的,如果是公司项目要给策划用的编辑器就不一样了,项目的接口设计会完全不一样。
这个小游戏项目从无到有,完全没用到以前积累的东西,也是蛋疼。
也是对 Unity 不够熟悉。
代码写得非常的简单易懂,基本没封装什么东西,就封装了一个 Loading 场景的统一处理,其他都是乱七八糟的代码。。。-_-!!!
后面有空需要去参考一些 Unity 现成的一些框架,参考他们的设计,再做适合自己项目的封装。
不然以后使用起来制作就相当麻烦了。
在使用一些动画的时候,找了一些 Tween 缓存库。
于是找了下面三个(最后我选择使用了:DOTween)。
花了一个上午,看完了三个 tween 库的介绍与文档,总结:
个人选择使用的是:DOTween,因为功能还是比较强大的。(说真的,这些所有的 Unity Tween 库使用起来都没有以前使用 AS3 的 greensock 那么顺手)
如果 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);
}
解决:如下面 判断一个 tween 是否完成的方式,在前面多加一句:if (xxx.active)
就可以了
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();
有还几种方式
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。注意打双引号的 没有
因为它的 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 会从当前的一些数据继续播放,但是就是前面说的,一些状态参数又需要重新设置了,这些设置不应该的,按道理是可以做到不到重复设置状态参数的,但暂时没有兴趣去看源码)
在 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
的差异也是不应该的