運行時用AnimatorOverrideController動態加載動畫片斷

https://blog.csdn.net/tlrainty/article/details/54602786html

 

項目中常常會遇到這種狀況:不少模型動畫的AnimatorController是如出一轍的(好比人類男,人類女),可是因爲在AnimatorController中須要爲每一個State指定具體的Motion(好比人類女的Run和Attack要分別指定Human_Female_Run和Human_Female_Attack,如圖1),咱們並不能簡單地在編輯器中給它們指定同一個AnimatorControllor,不然若是人類男用了人類女的AnimatorController咱們就會發現人類男走起路來也一扭一扭的了=_=|||(緣由是決定骨骼動畫的Avatar信息存儲在這個Motion所指定的AnimationClip中)架構

 

圖1編輯器

 

要解決這個問題就要用到Unity的AnimatorOverrideController了,先貼個API手冊: https://docs.unity3d.com/ScriptReference/AnimatorOverrideController.htmlide

代碼以下:動畫

 

[csharp]  view plain  copy
 
  1. private readonly string PrePath = "Prefabs/AnimationClips/";  
  2. private readonly string[] ActionList = {"Run", "Attack"};  
  3. private Animator m_animator = GetComponent<Animator>();  
  4.   <span style="white-space:pre;">   </span>[HideInInspector]  
  5. public string m_modelName;  
  6. //...  
  7.   
  8. if (m_animator != null)  
  9. {  
  10.     AnimatorOverrideController overrideController = new AnimatorOverrideController();  
  11.     overrideController.runtimeAnimatorController = m_animator.runtimeAnimatorController;  
  12.     foreach (var actionName in ActionList)  
  13.         overrideController[actionName] = Resources.Load(PrePath + m_modelName + "_" + actionName) as AnimationClip;  
  14.     m_animator.runtimeAnimatorController = overrideController;  
  15. }  

這裏主要須要注意的是

 

1. Resources.Load()的是以"模型名_動做名"格式命名的.anim文件,好比模型名是"Human_Female",動做名是"Run",那動畫文件就是"Human_Femal_Run.anim".ui

2. overrideController中保存的是當前animator中全部用到的動畫片斷. overrideController[actionName] 的actionName是動畫片斷的名字,而不是State名字,即圖1紅框中的部分.咱們並不對State進行任何操做,包括Motion中指定的動畫片斷的名字也不改變.所以建立AnimatorController的時候,須要先隨便給每一個State的Motion指定一個名字爲actionName的動畫,保證overrideController[actionName]存在,而後咱們再用本身的AnimationClip去替換它.拿剛纔的人類男和人類女舉例來講,就是須要先給Run這個State指定一個名字爲Run的動畫,Attack這個State也要指定一個名字爲Attack的動畫.這裏隨便用誰的動畫均可以,由於咱們這裏只是爲了"讓Dictionary中存在這個Key",以便後面咱們用上述代碼來替換.另外有一點要注意的是spa

 

[csharp]  view plain  copy
 
  1. overrideController[actionName] = Resources.Load(PrePath + m_modelName + "_" + actionName) as AnimationClip;  

 

這句會把全部State中的同名動畫片斷都替換掉..net

3.這裏把每一個動做單獨做爲一個anim保存而不是統一存在一個FBX中讀取的緣由是Unity如今還不能在運行時建立Animation(圖2是16年2月Unity論壇的官方回覆,後面我也沒有找到新消息說支持了).3d

 

 
 

圖2code

 

4. 這種方法保存出來的帶animator的prefab的動畫在編輯器中看會是錯的,由於此時尚未加載正確的animator controller,想看正確的動畫須要看最原始的FBX文件

 

 

P.S.從FBX中提取單一anim的方法:當把FBX截取出Clips以後

在Project視圖中點開FBX後面的白三角就會出現這些動畫片斷,單擊想要提取的anim而後按ctrl+D(即Duplicate)就會在同一文件夾下生成相應的anim文件

 

本文中所用Unity版本爲5.4.1f1

 
=======================================================================================================================================================================================================================
【動態替換clip】
【動態添加動畫事件】
using UnityEngine; /// <summary>
/// 代碼示例 /// </summary>
public class SetupAnimatorOverrideController : MonoBehaviour { public AnimationClip m_clip; private void Update() { if (Input.GetKeyDown(KeyCode.W)) { Debug.Log("切換"); OverrideAnimationClip("suit03_Boy_idle", m_clip); AddAnimEvent(m_clip); } } public RuntimeAnimatorController GetEffectiveController(Animator animator) { RuntimeAnimatorController controller = animator.runtimeAnimatorController; AnimatorOverrideController overrideController = controller as AnimatorOverrideController; while (overrideController != null) { controller = overrideController.runtimeAnimatorController; overrideController = controller as AnimatorOverrideController; } return controller; } /// <summary>
    /// 動態替換clip /// </summary>
    /// <param name="name"></param>
    /// <param name="clip"></param>
    public void OverrideAnimationClip(string name, AnimationClip clip) { Animator animator = GetComponent<Animator>(); AnimatorOverrideController overrideController = new AnimatorOverrideController(); overrideController.runtimeAnimatorController = GetEffectiveController(animator); overrideController[name] = clip; animator.runtimeAnimatorController = overrideController; } /// <summary>
    /// 動態添加動態事件 /// </summary>
    /// <param name="clip"></param>
    public void AddAnimEvent(AnimationClip clip) { AnimationEvent aEvent1 = new AnimationEvent(); aEvent1.time = clip.length; aEvent1.functionName = "OnOpenComplete"; clip.AddEvent(aEvent1); } public void OnOpenComplete() { Debug.Log("呵呵"); } }

 

 

 

 

 

 

 =================================2018年5月24日20:10:14=======================================

/// 老版動畫系統一些功能有所缺乏(例如,不支持位移動畫,會閃回)
/// 新版動畫惟一坑爹的就是缺乏動態去添加clip,只能把原有的clip替換成新的clip
/// 那麼要想支持具備大量動畫的遊戲,有2種辦法
/// 1.animator裏面添加足夠多的clip,以便於到時候隨意替換,由於animator.Play("xx") 能夠直接播放動畫,不須要經過觸發器
/// 2.構建一種三角形的萬能架構(用於去支持流星的動態連招),直接動態變換clip

相關文章
相關標籤/搜索