zoukankan      html  css  js  c++  java
  • 运行时用AnimatorOverrideController动态加载动画片段

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

    项目中经常会遇到这种情况:很多模型动画的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.html

    代码如下:

    [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".

    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",以便后面我们用上述代码来替换.另外有一点要注意的是

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

    这句会把所有State中的同名动画片段都替换掉.

    3.这里把每个动作单独作为一个anim保存而不是统一存在一个FBX中读取的原因是Unity现在还不能在运行时创建Animation(图2是16年2月Unity论坛的官方回复,后面我也没有找到新消息说支持了).

     
     

    图2

    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

  • 相关阅读:
    Median Value
    237. Delete Node in a Linked List
    206. Reverse Linked List
    160. Intersection of Two Linked Lists
    83. Remove Duplicates from Sorted List
    21. Merge Two Sorted Lists
    477. Total Hamming Distance
    421. Maximum XOR of Two Numbers in an Array
    397. Integer Replacement
    318. Maximum Product of Word Lengths
  • 原文地址:https://www.cnblogs.com/sanyejun/p/9076729.html
Copyright © 2011-2022 走看看