關於動畫結束的處理

一時興起,寫了這一篇文章。在實際開發中爲了更好的表現,需要在一段動畫播放後,再做別的行爲

這篇文章3月6日開始定題,3月22日寫完初稿,5月4日再補充一點,今天發佈。

一.不同的動畫組件

  1. 動畫美術直接編輯動畫,定位到要變化掛點的幀(比如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()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章