一時興起,寫了這一篇文章。在實際開發中爲了更好的表現,需要在一段動畫播放後,再做別的行爲
這篇文章3月6日開始定題,3月22日寫完初稿,5月4日再補充一點,今天發佈。
一.不同的動畫組件
- 動畫美術直接編輯動畫,定位到要變化掛點的幀(比如24幀),在Events裏添加一個動畫事件, 名字規範成 TakeWeapon
這個方案
優:讓美術準確控制幀數, 可以個性化
劣:所有模型該動作都要加一下。
二.用程序添加
網上有animation添加事件的
AnimationEvent evt = new AnimationEvent();
evt.time = 0;
evt.functionName = "Test";
animation.GetClip("ani").AddEvent(evt);
但我們現在用的新動畫系統Animator, 如何找到對應名字的動畫呢?
找了一下 Animator的接口和成員變量,還是有一個可用的:
for(int i=0;i< animator.runtimeAnimatorController.animationClips.Length;++i)
{
if(animator.runtimeAnimatorController.animationClips[i].name == name)
{
return animator.runtimeAnimatorController.animationClips[i];
}
}
能找到對應的名字的 animationClip,然後就可以
AnimationEvent evt = new AnimationEvent();
evt.time = 24f/30;
evt.functionName = "TakeWeapon";
animClip.AddEvent(evt);
優:所有角色動畫動作可以統一處理,不需要美術再加工
劣:時間不太好做個性化。
事件綁定好了,但是執行時報錯誤:
AnimationEvent ‘TakeWeapon’ has no receiver!
原來 TakeWeapon方法所在腳本必須掛在Animation(或Animator)所在GameObject上!
三.當使用Animator組件的時候
void Update()
{
var stateInfo = an.GetCurrentAnimatorStateInfo(0);
if(stateInfo.IsName(_openName)&& stateInfo.normalizedTime >= 1f)
{
//播放結束
}
}
四.使用IEnumerator 等待動畫的長度
Animation Anim;
float time = Anim.Getclip("anim1").Length;
private IEnumerator WaitAnimationEnd()
{
yield return new WaitForSeconds(time);
EndAnimation();
}
private void EndAnimation()
{
// 動作播放結束
}
五.使用Animation踩的坑
1. 有一個頭像大小縮放的動畫,從Animation是沒有任何問題的,但實際代碼調用的時候,一直不執行。
功能開發中,優先級並不是特別高。就一直沒查。
後來查找原因,當界面沒有打開的狀態下,執行動畫的播放.當界面打開的時候再播放,動畫部生效了,所以在animation調用的時候,要一句
if(this.gameObject.activeInHierarchy == false)return;
2.基於四的思路,做了一個文字動畫反覆播放顯示的內容。當同時添加兩段文字的時候,只播放了一次。設計上是將文字做了隊列緩存 。當一個動畫播完在播放另一個。
private Animation Anim;
public Queue<string> TipsStringQueue = new Queue<string>();
//Add String
public void AddString(string tips)
{
TipsStringQueue.Enqueue(tips);
if(!Anim.isPlaying)
{
ParseString();
}
}
private void ParseString()
{
if(TipsStringQueue.count == 0)
return;
string tips = TipsStringQueue.Dequeue();
if(!string.IsNullOrEmpty(tips))
{
//Json解析
//UI元素賦值
Anim["Anim01"].time = 0;
Anim.Play();
StopCoroutine(WaitAnimationEnd());
StartCoroutine(WaitAnimationEnd());
}
}
private IEnumerator WaitAnimationEnd()
{
yield return new WaitForSeconds(Anim.GetClip("Anim01").length);
EndAnimation();
}
private void EndAnimation()
{
if(TipsStringQueue.count>0)
{
ParseString();
}
}
Anim[“Anim01”].time = 0;在Play()之前寫這句很重要的,不然就會出現當同時加入兩個文字的時候,播放一次。
補充 把Loop的Animation停止指定幀
當時實習生遇到,把一個Loop的動畫停在初始幀。
把循環動畫停在指定的幀上,先給time賦值,在simple(),在stop()。
private void StoLoopAnimationOnBegin()
{
Animation an;
an["an1"].time = 0;
an.Sample();
an.Stop();
}
原因是
在調用了動畫播放之後,動畫並不會立即應用(骨骼Transform並不會立即改變),最快也要等到本幀lateUpdate才能生效。
如果有特殊需求,希望在調用了動畫播放之後立即生效,則可以緊接着調一句Animation.sample()