dotween官网
先验知识:Unity3d-Coroutines协程
Unity3d-C#扩展方法
dotween
在我的理解,dotween是一个扩展方法库,帮我们扩展了变换的方法,我们使得能够通过如transform.DoMove(vec3,time)这样简单的函数调用,实现在时间时间内移动到VEC3位置的动画效果。这次的仿写简单dotween本质上是使用了扩展方法和协程来实现。
这次实现的功能是dotween对象的管理以及使用dotween管理暂停,播放和杀对应动作,实现回调.dotween和动作对应的协程是一一对应的关系。
dotween对象
dotween对象对应的是对应动作的协程。通过改变成员变量中的isPause和autoKill可以决定对应的协程是否停止,dotween对象是否在执行完之后自动销毁。在扩展方法中,每次调用变换的扩展方法,就会产生一个对应的dotween,和一个协程.dotween在构造的时候会自动添加到Dotween工厂的列表中管理。
publicclassdotween{publicstringname;publicCoroutinecoroutine=null;publicTransformtransform=null;publicVector3target;publicfloattime;publicboolisPause=false;publicboolautoKill=true;publicdelegatevoidOnComplete();publicOnCompleteonComplete=null;publicdotween(stringn,Transformtrans,Vector3tar,floatt,Coroutineco){name=n;transform=trans;target=tar;time=t;//添加到工厂中管理Dotween.getInstance().Add(this);}publicvoidsetCoroutine(Coroutineco){coroutine=co;}publicvoidKill(){MonoBehaviourmono=transform.GetComponent();mono.StopCoroutine(coroutine);//生命周期结束,从工厂中删除Dotween.getInstance().Remove(this);}publicvoidPlay(){isPause=false;}publicvoidPause(){isPause=true;}//设置回调函数,可以设置多个回调函数publicvoidsetOnComplete(OnCompletefun){onComplete+=fun;}publicvoidrunOnComplete(){if(onComplete!=null){onComplete();}if(autoKill){Kill();}}//设置执行完动作后是否自动销毁publicvoidsetAutoKill(boolb){autoKill=b;}}
Dotween工厂
Dotween工厂的作用是管理所有的dotween,将他们保存在列表中,可以通过工厂让同一名字的动作一起暂停,播放,销毁。又或者让一个对象的所有动作停止,播放,销毁。
publicclassDotween{privatestaticListdotList=newList();privatestaticDotweendot=null;publicstaticDotweengetInstance(){if(dot==null){dot=newDotween();}returndot;}//添加一个dotween对象到列表中publicvoidAdd(dotweend){dotList.Add(d);}//从列表中删除一个dotween对象publicvoidRemove(dotweend){dotList.Remove(d);}//暂停publicstaticvoidPauseAll(){for(inti=dotList.Count-1;i>=0;i--){dotList[i].Pause();}}publicstaticvoidPause(stringname){for(inti=dotList.Count-1;i>=0;i--){if(dotList[i].name==name){dotList[i].Pause();}}}publicstaticvoidPause(Transformtransform){for(inti=dotList.Count-1;i>=0;i--){if(dotList[i].transform==transform){dotList[i].Pause();}}}//播放publicstaticvoidPlayAll(){foreach(dotweendindotList){d.Play();}}publicstaticvoidPlay(stringname){foreach(dotweendindotList){if(d.name==name){d.Play();}}}publicstaticvoidPlay(Transformtransform){foreach(dotweendindotList){if(d.transform==transform){d.Play();}}}//销毁publicstaticvoidKillAll(){for(inti=dotList.Count-1;i>=0;i--){dotList[i].Kill();}}publicstaticvoidKill(stringname){for(inti=dotList.Count-1;i>=0;i--){if(dotList[i].name==name){dotList[i].Kill();}}}publicstaticvoidKill(Transformtransform){for(inti=dotList.Count-1;i>=0;i--){if(dotList[i].transform==transform){dotList[i].Pause();}}}}
扩展方法
有了dotween和Dotween来管理我们的动作后,我们可以编写对应的扩展函数库了。
publicstaticclassextension_method{//DoMove扩展方法(MonoBehaviour,Transform)//通过time秒移动到指定的位置targetpublicstaticIEnumeratorDoMove(thisMonoBehaviourmono,dotweendot){//根据目标和现在的位置,按时间长度算出速度Vector3distance=(dot.target-dot.transform.position)/dot.time;for(floatf=dot.time;f>=0.0f;f-=Time.deltaTime){dot.transform.Translate(distance*Time.deltaTime);yieldreturnnull;//根据dotween确认状态while(dot.isPause==true){yieldreturnnull;}}//动作结束调用回调函数dot.runOnComplete();}publicstaticdotweenDoMove(thisTransformtransform,Vector3target,floattime){MonoBehaviourmono=transform.GetComponents()[0];//新建dotweendotweendot=newdotween("DoMove",transform,target,time,null);//创建协程Coroutinecoroutine=mono.StartCoroutine(mono.DoMove(dot));//给dotween设置对应协程dot.setCoroutine(coroutine);returndot;}}
这就成功扩展了一个DoMove函数,要扩展更多的函数,只要记得同样的步骤(创建dotween对象,创建协程,给dotween设置协程,在协程中确认状态,调用回调函数)就可以写。出更多的扩展方法例如扩展一个DoScale:
//DoScale扩展方法(MonoBehaviour,Transform)//通过time秒放大到特定倍数targetpublicstaticIEnumeratorDoScale(thisMonoBehaviourmono,dotweendot){Vector3distance=(dot.target-dot.transform.localScale)/dot.time;for(floatf=dot.time;f>=0.0f;f-=Time.deltaTime){dot.transform.localScale=dot.transform.localScale+distance*Time.deltaTime;yieldreturnnull;while(dot.isPause==true){yieldreturnnull;}}dot.runOnComplete();}publicstaticdotweenDoScale(thisTransformtransform,Vector3target,floattime){MonoBehaviourmono=transform.GetComponents()[0];dotweendot=newdotween("DoScale",transform,target,time,null);Coroutinecoroutine=mono.StartCoroutine(mono.DoScale(dot));dot.setCoroutine(coroutine);returndot;}
使用
完成了扩展之后,我们就可以在我们的脚本中调用对应的扩展函数,轻松实现运动效果。
publicclasstest:MonoBehaviour{dotweendot;// Use this for initializationvoidStart(){dot=transform.DoMove(newVector3(1,1,1),10.0f);transform.DoScale(newVector3(2,2,2),10.0f);transform.DoPause(5.0f);dot.setOnComplete(fun);}voidfun(){Debug.Log("onComplete");}// Update is called once per framevoidUpdate(){}}
效果:
完整的Dotween.cs代码:
usingUnityEngine;usingSystem.Collections;usingSystem.Collections.Generic;publicclassDotween{privatestaticListdotList=newList();privatestaticDotweendot=null;publicstaticDotweengetInstance(){if(dot==null){dot=newDotween();}returndot;}//添加一个dotween对象到列表中publicvoidAdd(dotweend){dotList.Add(d);}//从列表中删除一个dotween对象publicvoidRemove(dotweend){dotList.Remove(d);}//暂停publicstaticvoidPauseAll(){for(inti=dotList.Count-1;i>=0;i--){dotList[i].Pause();}}publicstaticvoidPause(stringname){for(inti=dotList.Count-1;i>=0;i--){if(dotList[i].name==name){dotList[i].Pause();}}}publicstaticvoidPause(Transformtransform){for(inti=dotList.Count-1;i>=0;i--){if(dotList[i].transform==transform){dotList[i].Pause();}}}//播放publicstaticvoidPlayAll(){foreach(dotweendindotList){d.Play();}}publicstaticvoidPlay(stringname){foreach(dotweendindotList){if(d.name==name){d.Play();}}}publicstaticvoidPlay(Transformtransform){foreach(dotweendindotList){if(d.transform==transform){d.Play();}}}//销毁publicstaticvoidKillAll(){for(inti=dotList.Count-1;i>=0;i--){dotList[i].Kill();}}publicstaticvoidKill(stringname){for(inti=dotList.Count-1;i>=0;i--){if(dotList[i].name==name){dotList[i].Kill();}}}publicstaticvoidKill(Transformtransform){for(inti=dotList.Count-1;i>=0;i--){if(dotList[i].transform==transform){dotList[i].Pause();}}}}publicclassdotween{publicstringname;publicCoroutinecoroutine=null;publicTransformtransform=null;publicVector3target;publicfloattime;publicboolisPause=false;publicboolautoKill=true;publicdelegatevoidOnComplete();publicOnCompleteonComplete=null;publicdotween(stringn,Transformtrans,Vector3tar,floatt,Coroutineco){name=n;transform=trans;target=tar;time=t;//添加到工厂中管理Dotween.getInstance().Add(this);}publicvoidsetCoroutine(Coroutineco){coroutine=co;}publicvoidKill(){MonoBehaviourmono=transform.GetComponent();mono.StopCoroutine(coroutine);//生命周期结束,从工厂中删除Dotween.getInstance().Remove(this);}publicvoidPlay(){isPause=false;}publicvoidPause(){isPause=true;}//设置回调函数,可以设置多个回调函数publicvoidsetOnComplete(OnCompletefun){onComplete+=fun;}publicvoidrunOnComplete(){if(onComplete!=null){onComplete();}if(autoKill){Kill();}}//设置执行完动作后是否自动销毁publicvoidsetAutoKill(boolb){autoKill=b;}}publicstaticclassextension_method{//DoMove扩展方法(MonoBehaviour,Transform)//通过time秒移动到指定的位置targetpublicstaticIEnumeratorDoMove(thisMonoBehaviourmono,dotweendot){//根据目标和现在的位置,按时间长度算出速度Vector3distance=(dot.target-dot.transform.position)/dot.time;for(floatf=dot.time;f>=0.0f;f-=Time.deltaTime){dot.transform.Translate(distance*Time.deltaTime);yieldreturnnull;//根据dotween确认状态while(dot.isPause==true){yieldreturnnull;}}//动作结束调用回调函数dot.runOnComplete();}publicstaticdotweenDoMove(thisTransformtransform,Vector3target,floattime){MonoBehaviourmono=transform.GetComponents()[0];//新建dotweendotweendot=newdotween("DoMove",transform,target,time,null);//创建协程Coroutinecoroutine=mono.StartCoroutine(mono.DoMove(dot));//给dotween设置对应协程dot.setCoroutine(coroutine);returndot;}//DoScale扩展方法(MonoBehaviour,Transform)//通过time秒放大到特定倍数targetpublicstaticIEnumeratorDoScale(thisMonoBehaviourmono,dotweendot){Vector3distance=(dot.target-dot.transform.localScale)/dot.time;for(floatf=dot.time;f>=0.0f;f-=Time.deltaTime){dot.transform.localScale=dot.transform.localScale+distance*Time.deltaTime;yieldreturnnull;while(dot.isPause==true){yieldreturnnull;}}dot.runOnComplete();}publicstaticdotweenDoScale(thisTransformtransform,Vector3target,floattime){MonoBehaviourmono=transform.GetComponents()[0];dotweendot=newdotween("DoScale",transform,target,time,null);Coroutinecoroutine=mono.StartCoroutine(mono.DoScale(dot));dot.setCoroutine(coroutine);returndot;}}