运行时用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

相关文章
相关标签/搜索