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

  • 相关阅读:
    《算法导论》第二章笔记
    Python实现websocket之Django Channel实时推送与聊天
    zabbix设置钉钉报警
    ESXi安装报错,No network adapters were detected...
    supervisor指南
    Flask入门到放弃(五)—— 蓝图
    Flask入门到放弃(四)—— 数据库
    Flask入门很轻松(三)—— 模板
    Flask入门很轻松 (二)
    Flask入门很轻松 (一)
  • 原文地址:https://www.cnblogs.com/sanyejun/p/9076729.html
Copyright © 2011-2022 走看看