精华内容
下载资源
问答
  • 2021-04-01 12:40:09


    相信你们都学过Animator的一些东西,这里讲在建立状态切换的一些用法,让你状态切换看起来简洁,代码容易理解,不易出现bug

    Animator窗口

    首先是Animator窗口

    刚开始只有Any state,Entry,Exit

    Any state:任意状态切换,一般用于死亡状态切换,所以不使用Any state更能看清楚哪些状态之间能切换,哪些不能
    Entry,默认动画人口,一般是ilde站立
    Exit:动画退出出口,注意一定要加退出动画的状态,不然你可以会出现一直在播放某个动画,我刚开始没加,在代码写退出条件,这样状态一多,自己都看不懂当前的动画切换,而且容易卡在某一个动画上

    例子:站立idle,跳跃jump,奔跑run,攻击attack这4个动画的切换

    再提一下条件写在一个箭头里是满足所有条件,如果只需满足一个条件你要重新make transition图中就会变成多箭头的形式,一般状态切换为单箭头,退出动画为多箭头

    以下是我建的状态切换图:

    在这里插入图片描述
    每个状态都要不勾选has exit time,以便不需要动画播放结束就可以及时切换

    站立idel切换到run条件:在地面isGround为true跟向前速度forwardSpeed大于0.1即可

    run到idle:在地面isGround为true跟向前速度forwardSpeed小于0.1即可

    run退出动画条件:向前速度forwardSpeed小于0.1 | | isGround为false(跳跃状态)| | attack攻击状态,就是其它状态满足条件时来打断当前动画

    idle退出动画条件:向前速度forwardSpeed大于0.1 | | isGround为false(跳跃状态)| | attack攻击状态

    站立的3个动画

    然后在idle我是create sub-state machine而来,我在创建了一个子状态机,通过设置idle和idlewait的值来实现站立状态切换
    在这里插入图片描述
    idle_A到idle_B的条件为idle为0 && idlewait(等待时间)大于5的时候切换
    idle_B到idle_C的条件为idle为1 && idlewait(等待时间)大于5的时候切换
    idle_C到idle_D的条件为idle为2 && idlewait(等待时间)大于5的时候切换
    idle_D到idle_A的条件为idle为-1 && idlewait(等待时间)大于5的时候切换

    退出条件都一样,前面讲了

    要如何设置idle值的变化来播放动画?

    双击idle_A动画,在Events,添加事件,在动画末尾添加事件OnIdleEnd,然后在脚本里写对于事件名的方法,在动画结束时将会自动调用
    在这里插入图片描述
    同理在idle_b,idle_c也添加OnIdleEnd事件,而最后的站立动画要切换为初始状态,我们在动画结尾添加OnIdleStart

    public void OnIdleStart()
        {        
            animator.SetInteger("idle", -1);
            
            
        }
        private int b = 0;
        public void OnIdleEnd()
        {
            
            animator.SetInteger("idle", b % 3);
            b++;
            
        }
    

    攻击的3个动画

    attack参数是trigger通过鼠标点击触发,而normalizedTime是控制3个攻击动画的切换
    run->attack和idle->attack:条件是通过attack触发切换
    attack->run:向前速度forwardSpeed大于0.1
    attack->idle:向前速度forwardSpeed小于0.1,这样没有鼠标点击就自动切换为站立状态,而不用写退出动画的条件

    attack也是create sub-state machine创建而来,下面是3个攻击动画的状态机
    在这里插入图片描述
    atk2->atk3:attack&&normalizedTime>0.1&&normalizedTime<1
    atk3->atk4:attack&&normalizedTime>0.4&&normalizedTime<1
    atk4->atk1:attack&&normalizedTime>0.7&&normalizedTime<1

    这3个动画取消勾选has exit time,而退出条件勾选has exit time,且设置退出时间为1,不用写退出条件,只要没点击就回到站立状态
    在这里插入图片描述

    但这里不是通过事件触发的,而是通过normalizedTime的变化来控制的,normalizedTime是当前动画的播放进度,我们要特殊处理让它置于0-1之间

    下面是全部代码,看一下设置动画的部分即可

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerController : MonoBehaviour
    {
    
       #region 字段
        public float maxMoveSpeed = 5;
    
        public float jumpspeed = 7;
        public float gravity = 15;
    
        public bool isGrouned = true;
        public CharacterController Character;
        //
        public Transform renderCamera;
        //人物角速度
        public float maxAngleSpeed = 1200;
        public float minAngleSpeed = 400;
        //人物加速度
        public float acceleratedSpeedd = 15;
    
        public float moveSpeed = 0;
        public Animator animator;
    
    
        private float verticalspeed = 0;
        private PlayerInput playerInput;
    
        private Vector3 move;
        //当前动画信息
        private AnimatorStateInfo currentStateInfo;
        //获取指定动画
        //private int idleHash = Animator.StringToHash("Idle_A");
        //private int runHash = Animator.StringToHash("Run");
        //private int jumpHash = Animator.StringToHash("Jump");
        private AudioSource audioSource;
        #endregion
    
        // Start is called before the first frame update
        private void Awake()
        {
            Character = transform.GetComponent<CharacterController>();
            playerInput = transform.GetComponent<PlayerInput>();
            animator = transform.GetComponent<Animator>();
            audioSource = transform.GetComponent<AudioSource>();
            
        }
        void Start()
        {
            audioSource.enabled = false;
            audioSource.volume = 0.3f;
            
        }
    
        // Update is called once per frame
        void Update()
        {
            //获取动画层
            currentStateInfo = animator.GetCurrentAnimatorStateInfo(0);
            CaculateMove();
            CaculateVerticalSpeed();
            CaculateForwardSpeed();
            Attack();
            //AnimationSprint();
            //CaculateRotation();
        }
        
        //private void OnAnimatorMove()
        //{
        //    CaculateMove();
        //}
    
        private void CaculateMove()
        {
            //float h = Input.GetAxis("Horizontal");
            //float v = Input.GetAxis("Vertical");
    
            //Vector3 move = new Vector3(h, 0, v);
            //动画对于上一帧的偏移
            //print("1");
            //move = animator.deltaPosition;
    
            move.Set(playerInput.Move.x, 0, playerInput.Move.y);
            move *= Time.deltaTime * moveSpeed;
    
            //相机跟随人物移动的方向
            move = renderCamera.TransformDirection(move);
    
            if (move.x != 0 || move.z != 0)
            {
                move.y = 0;
                //旋转速度,根据插值让移动速度影响旋转速度
                float turnSpeed = Mathf.Lerp(maxAngleSpeed, minAngleSpeed, moveSpeed / maxMoveSpeed) * Time.deltaTime;
                //RotateTowards从人物方向旋转到人物移动方向,最后一个参数为过度时间
                transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(move), turnSpeed);
            }
            move += Vector3.up * verticalspeed * Time.deltaTime;
            
            
            Character.Move(move);
            isGrouned = Character.isGrounded;
        }
        private void Attack()
        {
            if(isGrouned)
            {
              //获取动画进度,通过Repeat函数置于0-1
                animator.SetFloat("normalizedTime",Mathf.Repeat(currentStateInfo.normalizedTime,1)  );
                //重新设置鼠标点击
                animator.ResetTrigger("attack");
                if(playerInput.Attack)
                {
                    print("攻击");
                    t = 0;
                    animator.SetFloat("idleWait", t);
                    animator.SetTrigger("attack");
                }
                
            }
        }
        public void OnAttackStart()
        {
            
        }
        public void OnAttackEnd()
        {
            
        }
        private float t = 0;
        private void CaculateVerticalSpeed()
        {
            if(isGrouned)
            {
                verticalspeed = -gravity * 0.3f;
                if(playerInput.Jump)
                {
                    t = 0;
                    animator.SetFloat("idleWait", t);
                    
                    verticalspeed = jumpspeed;
                    isGrouned = false;
                }
            }
            else
            {
                
                verticalspeed -= gravity * Time.deltaTime;
            }
            if (verticalspeed == 0)
                isGrouned = true;
            animator.SetBool("isGround", isGrouned);
            
        }
        
    
        //人物在移动时速度的过度在0-5之间
        private void CaculateForwardSpeed()
        {
            moveSpeed = Mathf.MoveTowards(moveSpeed, maxMoveSpeed 
                * playerInput.Move.normalized.magnitude, acceleratedSpeedd * Time.deltaTime);
            if (playerInput.Move.x == 0 && playerInput.Move.y == 0)
            {
                t += Time.deltaTime;
                audioSource.enabled = false;            
                if(t>5)
                    animator.SetFloat("idleWait", t);
                animator.SetFloat("forwardSpeed", 0.05f);
                
            }
            else
            {
                t = 0;            
                audioSource.enabled = true;
                animator.SetFloat("idleWait", t);            
                animator.SetFloat("forwardSpeed", moveSpeed);
            }
                
        }
    
        //private void AnimationSprint()
        //{
        //    if (currentStateInfo.shortNameHash == idleHash)
        //        print("当前播发站立动画");
        //    else if (currentStateInfo.shortNameHash == runHash)
        //        print("当前播放跑步动画");
        //    else if (currentStateInfo.shortNameHash == jumpHash)
        //        print("当前播放跳跃动画");
        //}
        //private void CaculateRotation()
        //{
        //    if (playerInput.Move.x != 0 || playerInput.Move.y != 0)
        //    {
        //        Vector3 targetDirection = renderCamera.TransformDirection
        //            (new Vector3(playerInput.Move.x, 0, playerInput.Move.y));
        //        targetDirection.y = 0;
    
        //        float turnSpeed = Mathf.Lerp(maxAngleSpeed, minAngleSpeed, moveSpeed / maxMoveSpeed) * Time.deltaTime;
        //        transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(targetDirection), turnSpeed);
        //    }
        //}
    
        public void OnIdleStart()
        {
            
            
            animator.SetInteger("idle", -1);
            
            
        }
        private int b = 0;
        public void OnIdleEnd()
        {
            
            animator.SetInteger("idle", b % 3);
            b++;
            
        }
        
    }
    
    

    如果状态切换上出现is not compatible withcondition type的错误?

    只需将状态切换的箭头删除再重新新建即可

    更多相关内容
  • Unity动画状态机Animator使用

    万次阅读 多人点赞 2019-07-01 16:05:22
    unity可以用两种方式控制动画 1 Animations,这种方式简单,直接 Play(“Idle”) 或者 CorssFade(“Idle”) 就可以播放动画 2 Animator,5.x之后推荐使用这种方式,因为里面可以加上混合动画,让动画切换更加平滑 ...

    一、前言

    Unity可以用两种方式控制动画
    1 Animation,这种方式简单,直接 Play(“Idle”)或者CorssFade(“Idle”)就可以播放动画;
    2 AnimatorUnity5.x之后推荐使用这种方式,因为里面可以加上混合动画,让动画切换更加平滑。

    二、Animator组件

    你通过Animation窗口(快捷键是Ctrl+6)中的Create New Clip创建Animation时,一个 Animator已经悄无声息地出现在了对应的GameObject
    在这里插入图片描述

    三、Animator Controller文件

    在第一步中生成的Animator组件上, 第一个Controller参数在创建Animator时已经被赋值了,可以点击该值,并切换到Project窗口下,会发现这个 Controller对应的文件是一个.controller文件。
    Animator Controller就是动画控制器,负责在不同的动画间切换,属于制作动画效果的必备原件。

    在这里插入图片描述

    注意,你也可以通过GameObject上的 Add Component添加一个崭新的 Animator组件,但是这种情况下 AnimatorController参数默认为空,所以需要我们手动将事先准备好的.controller文件拖拽到该参数位置,动画控制器才能正常工作。

    四、Animation Clip文件

    双击 .controller"文件,会弹出一个 Animator窗口,该窗口中显示的就是动画控制器文件中的所有内容(也可以在顶部的工具栏通过 Window - Animator打开这个界面)
    在这里插入图片描述
    Project窗口右键单击,选择Create->Animation创建Animation Clip.anim文件)
    在这里插入图片描述
    在这里插入图片描述
    再把.anim文件拖拽进Animator窗口,作为Animator Controller的一个状态(State
    在这里插入图片描述
    通过Animator创建出来的Animation Clip无法直接通过挂Animation组件进行播放,如果强行播放,Console会报一条警告信息:

    The AnimationClip 'XXX' used by the Animation component 'XXX' must be marked as Legacy.
    

    以及一条提示信息

    Default clip could not be found in attached animations list
    

    如下
    在这里插入图片描述
    为什么呢?
    如果我们把Inspector切换为Debug模式
    在这里插入图片描述
    可以看到Animation Clip有个Legacy勾选框
    在这里插入图片描述
    Legacy是遗产的意思,也就是传统的通过Animation组件来播放Animation Clip的做法,如果使用Animation组件来播放Animation Clip,则必须把Legacy勾选上,不过这种方式已经是过时的做法,推荐使用Animator来播放Animation Clip

    五、 状态机的状态(State)

    每个Animator Controller都会自带三个状态:Any State, EntryExit
    在这里插入图片描述

    1、Any State状态

    表示任意状态的特殊状态。例如我们如果希望角色在任何状态下都有可能切换到死亡状态,那么Any State就可以帮我们做到。当你发现某个状态可以从任何状态以相同的条件跳转到时,那么你就可以用Any State来简化过渡关系。

    2、Entry状态

    表示状态机的入口状态。当我们为某个GameObject添加上Animator组件时,这个组件就会开始发挥它的作用。
    如果Animator Controller控制多个Animation的播放,那么默认情况下Animator组件会播放哪个动画呢? 由Entry来决定的。
    但是Entry本身并不包含动画,而是指向某个带有动画的状态,并设置其为默认状态。被设置为默认状态的状态会显示为 橘黄色。
    在这里插入图片描述
    当然,你可以随时在任意一个状态上通过 鼠标右键->Set as Layer Default State更改默认状态。
    在这里插入图片描述

    记住, EntryAnimator组件被激活后 无条件 跳转到默认状态,并且每个Layer有且仅有一个默认状态。

    3、Exit状态

    表示状态机的出口状态,以红色标识。如果你的动画控制器只有一层,那么这个状态可能并没有什么卵用。但是当你需要从子状态机中返回到上一层(Layer)时,把状态指向Exit就可以了。
    在这里插入图片描述

    六、动画状态的属性

    我们可以选中某个自定义状态,并在Inspector窗口下观察它具有的属性
    在这里插入图片描述

    属性名描述
    Motion状态对应的动画。每个状态的基本属性,直接选择已定义好的动画(Animation Clip)即可
    Speed动画播放的速度。默认值为1,表示速度为原动画的1.0倍。
    Mutiplier勾选右侧的Parameter后可用,即在计算Speed的时考虑 区域1 中定义的某个参数。若选择的参数为smooth, 则动画播放速度的计算公式为 smooth * speed * fps(animation clip中指定)
    Mirror仅适用于humanoid animation(人型机动画)
    Cycle Offset周期偏移,取值范围为0-1.0,用于控制动画起始的偏移量。把它和正弦函数的offset进行对比就能够理解了,只会影响起始动画的播放位置。
    Foot IK仅适用于humanoid animation(人型机动画)
    Write Default最好保持默认,感兴趣可以参考官方手册
    Transitions该状态向其他状态发起的过渡列表,包含了Solo和Mute两个参数,在预览状态机的效果时起作用
    Add Behaviour用于向状态添加“行为”

    七、状态间的过渡关系(Transitions)

    直观上说它们就是连接不同状态的有向箭头
    在这里插入图片描述

    要创建一个从状态A状态B的过渡,直接在状态A上 鼠标右键 - Make Transition并把出现的箭头拖拽到状态B上点击鼠标左边即可。
    在这里插入图片描述

    八、添加状态控制参数

    参数有FloatIntBoolTrigger
    在这里插入图片描述
    FloatInt用来控制一个动画状态的参数,比如速度方向等可以用数值量化的东西,
    Bool用来控制动画状态的转变,比如从走路转变到跑步,
    Trigger本质上也是bool类型,但它默认为false,且当程序设置为true后,它会自动变回false

    如下这里创建一个Int类型的参数AnimState
    在这里插入图片描述

    九、编辑切换状态的条件

    点击连线,在Inspecter窗口中可以进行设置,在Conditions栏下可以添加条件,如下图表示当参数
    AnimState0时会执行这个动画Any StateNew Animation2的过渡

    必须在Parameters面板中添加了参数才可以在这里查看到,其次添加的条件为&&”与”关系,即必须同时满足。

    在这里插入图片描述

    十、代码中控制状态

    我们可以通过代码来设置条件状态,达到动画切换的目的

    Animator ator = go1.GetComponent<Animator>();
    ator.SetInteger("AnimState", 0);
    

    上面的代码,让AnimState这个参数值为0,满足了从Any StateNew Animation2的过渡条件,从而实现New Animation2动画的过渡。

    十一、检查动画状态

    方法1、AnimatorStateInfo

    在脚本中添加代码

    //检查是否正在播放jump动画.
    AnimatorStateInfo stateinfo = anim.GetCurrentAnimatorStateInfo(0);   
    bool playingJump = stateinfo.IsName("jump");
    if(playingJump)
    {
    	if(stateinfo.normalizedTime < 1.0f)
    	{
    		//正在播放
    	}
    	else
    	{
    		//播放结束
    	}
    	
    }
    

    当处于状态jump,则stateinfo.IsName("jump")返回true

    方法2、继承StateMachineBehaviour

    Animator的每个状态都可以挂载脚本,创建脚本,继承于StateMachineBehaviour类,用于检测状态机中动画切片(Anamation)的运行状态。
    官方示例:https://docs.unity3d.com/ScriptReference/StateMachineBehaviour.html
    将脚本挂载在对应的状态上即可。代码如下

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class JumpState : StateMachineBehaviour
    {
        private GameObject player;
    
    
        override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            // 正在played的状态的第一帧被调用
            Debug.Log("------OnStateEnter------------");
        }
    
        // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
        override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            
        }
    
        // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
        override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            // 转换到另一个状态的最后一帧 被调用
            Debug.Log("-------------OnStateExit-----------------");
        }
    
        // OnStateMove is called right after Animator.OnAnimatorMove()
        override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
        	// 在OnAnimatorMove之前被调用 
            
        }
    
        // OnStateIK is called right after Animator.OnAnimatorIK()
        override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
        {
            // 在OnAnimatorIK之后调用,用于在播放状态时的每一帧的monobehavior。
            // 需要注意的是,OnStateIK只有在状态位于具有IK pass的层上时才会被调用。
            // 默认情况下,图层没有IK通道,所以这个函数不会被调用
            // 关于IK的使用,可以看看这篇文章《Animator使用IK实现头部及身体跟随》
            // https://www.jianshu.com/p/ae6d65563efa
        }
    }
    

    十二、控制播放速度

    Animator ator = go1.GetComponent<Animator>();
    var stateinfo = ator.GetCurrentAnimatorStateInfo(0);
    if(stateinfo.IsName("Jump"))
    {
    	ator.speed = 2;
    }
    

    十三、注意事项

    1 取消勾选 Can Transition To Self,不然动画会出现抖动
    在这里插入图片描述

    2 动作循环。不然如果没有下个状态切换,直接停止动作
    在这里插入图片描述

    3 Has Exit Time,如果勾选了,则表示在该动作完成后才允许切换,但是一般我们要的都是立即切换,所以这里 不要勾选
    在这里插入图片描述

    十四、补充

    1、Mirror

    镜像,可以反转当前动画,减少动画师工作量
    在这里插入图片描述

    2、Solo与Mute

    Mute相当于把目标过渡禁用掉。Solo表示只生效这一条过渡
    可以多选,当选中后会出现箭头提示
    条件满足优先于Solo/Mute,当条件没有满足时依然不会过渡
    在这里插入图片描述

    展开全文
  • Unity动画系统详解3:如何播放、切换动画?

    万次阅读 多人点赞 2020-05-31 19:37:49
    摘要:【长文预警,建议先收藏】有了模型和多个动画以后,在Unity中如何控制它们的播放和切换呢?本文带你一站式解析Unity的Animator模块。 洪流学堂,让你快人几步。你好,我是跟着大智学Unity的萌新,我叫小新,...

    摘要:【长文预警,建议先收藏】有了模型和多个动画以后,在Unity中如何控制它们的播放和切换呢?本文带你一站式解析Unity的Animator模块。

    洪流学堂,让你快人几步。你好,我是跟着大智学Unity的萌新,我叫小新,这几周一起来复(yu)习(xi)动画系统。

    大智:“小新,还记得Unity的动画来源有哪些么?”

    小新:“有Unity中制作和外部导入两种,哦对!还可以用代码写动画,不过我不会,嘿嘿”

    大智:“没错,前两天我们学习的其实主要是Animation Clip的内容,也就是一个物体对应的一段动画,是整个动画系统的基本元素。今天我们要着重学习一下Animator。如果把Animation Clip比作是一段视频的话,那么Animator就是一个视频播放器,用来控制多段视频的播放、切换等等。”

    Animator组件

    想要在一个物体上播放动画,需要在这个物体上添加Animator组件。

    Animator中有一个很重要的属性是Controller,这个属性引用了一种叫Animator Controller的资源,这种资源以文件的形式存储在工程中,文件内存储了动画的各种状态以及状态之间的切换规则。本文后半部分会细讲。

    Avatar 设置使用的骨骼节点映射。

    Apply Root Motion 应用根节点运动。如果不启用,动画播放时根节点会保持在原地,需要通过脚本控制物体的移动。如果启用,如果动画中有运动,动画中的运动会换算到根节点中,根节点会发生运动。(通常用于人物/动物的运动动画)

    Update Mode 设置Animator更新的时机以及timescale的设置。

    • Normal Animator按正常的方式更新(随着Update调用更新,timescale减小时,动画播放也会减慢,timescale的具体含义和用法后续会详解)
    • Animate Physics Animator会按照物理系统的频率更新(根据FixedUpdate调用更新,后续会详解),适用于物理交互,例如角色加上了物理属性可以推动周围的其他物体。
    • Unscaled Time 根据Update调用更新,无视timescale。一般用于UI界面,当你使用timescale暂停游戏时,界面保持正常动画。

    Culling Mode 裁剪模式

    • Always Animate 动画一直运行,即使物体在屏幕外被裁剪掉并没有渲染
    • Cull Update Transforms 当物体不可见时,禁用Retarget、IK、Transforms的更新(后续动画进阶模块会细讲)
    • Cull Completely 当物体不可见时,完全禁用动画

    Animator Controller

    Animator Controller是Animator组件必须的资源,这种资源以文件的形式存储在工程中,文件内存储了动画的各种状态以及状态之间的切换规则。

    上图中有两个Animator Controller文件

    通常一个物体上有不止一段动画,使用Animator Controller可以很容易地管理各段动画以及动画之间的切换。比如角色身上有走、跑、跳、蹲的动画,使用Animator Controller可以很容易管理它们。不过,即使只有一段动画,仍然需要给动画物体添加Animator组件才能播放动画。

    大智之前讲过可以使用PlayableAPI绕过Animator Controller来播放动画,感兴趣的话可以去看一下

    Animator Controller中使用了一种叫State Machine(状态机)的技术来管理状态以及状态之间的切换。

    StateMachine 状态机

    状态机由State(状态)和Transition(转换)组成。State代表一个状态,在Animator Controller中一个State可以包含一段动画、一个子状态机或一个混合树(后面会细讲)。Transition用来设置状态之间的切换条件,一般会有一个或多个条件,用于从一个状态切换到另一个状态。

    在Animator窗口中,可以可视化看到State以及Transition。

    创建Animator Controller

    创建Animator Controller资源有如下几种方式:

    • 在Unity中创建Animation Clip时,如果选中的GameObject上没有Animator组件,会自动添加Animator组件并在工程中创建一个Animator Controller文件(和Animation Clip文件同目录)。
    • 将任意Animation Clip拖到一个物体上时,如果拖到的物体上没有Animator组件,会自动添加Animator组件并在工程中创建一个Animator Controller文件(和Animation Clip文件同目录)。
    • 可以在Project窗口中手动创建Animator Controller文件,如下图所示:

    创建Animator Controller文件

    编辑Animator Controller

    双击Animator Controller文件,可以打开Animator窗口,编辑该文件。

    今天我们先简单学习一下如何将导入的动画播放出来,后续的动画进阶模块会更详细讲解Animator Controller中的高级功能。

    在Project窗口中直接创建Animator Controller时,其中是不包含任何动画的。如下图所示:

    图中包含三个节点:

    Entry 入口。动画状态机会从这个节点开始,根据Transition进入一个默认State。

    Any State 任意状态。用于从任意状态转换到特定状态。比如射击类游戏中,如果被子弹打中后,不管当前处于什么状态,都会倒地死亡。

    Exit 退出状态机。一般用于嵌套的状态机的退出(后面动画进阶模块会讲)。

    添加状态

    可以在空白处右键添加Empty State,也可以将Animation Clip文件拖到Animator窗口中添加一个State。

    如果当前在Project窗口选中了一个Animation Clip,也可以通过上图的From Selected Clip创建一个State,不过还是直接将Clip拖到Animator中创建State更简单,如下图所示。

    拖拽添加State.gif

    第一个创建的State默认是橘黄色的,代表是默认状态。有一条黄色的箭头从Entry指向橘黄色的State。Animator组件会在一开始播放New State,如果New State中有动画,也会播放对应的动画。

    这时候如果你Play这个场景的话,设个物体就会播放默认State的动画。

    State设置

    每个State可以包含一段Animation Clip,处于该State时Animator组件所在的物体会播放该动画。选中一个State时,在Inspector中可以看到如下内容:

    Motion 可以设置一个Animation Clip,如果是从Animation Clip创建的动画,这里应该已经有动画了,你也可以从工程中选择动画。

    Speed 动画的播放速度

    Multiplier 乘数,可以使用一个参数来控制动画的播放速度,动画最终的播放速度会是Speed * Multiplier。后面会讲解Animator的参数以及如何在代码中控制参数。

    Normalized Time 单位化时间,范围是0-1,需要使用参数控制。

    Mirror 镜像动画。也可以使用一个参数控制。

    Cycle Offset 循环偏移量。可以用来同步循环的动画。偏移量使用的是单位化时间,范围是0-1。也可以使用参数来控制。

    Foot IK 只用于人形动画。角色的脚是否使用反向动力学。

    Write Defaults 是否初始化该State没有用到的参数为默认值。

    Transitions 该状态参与的状态转换。下面会细讲。

    Parameters 参数

    上面我们提到了参数的概念,那么参数是什么呢?

    Animator Controller中的参数可以作为控制transition切换的条件,也可以控制上面可以参数化的属性比如State中的几个属性。

    State中可以用参数做属性值的来源

    Animator Controller的参数可以通过代码进行控制,进而控制整个Animator状态机的运转。

    参数共有4种类型:

    • Int 整数类型
    • Float 浮点数(小数)类型
    • Bool true或false(真或者假,用于逻辑判断),界面上显示为复选框
    • Trigger 触发器,与Bool有点类似,但是transition在使用这个参数后会被自动设置为false状态。界面上显示为一个圆形按钮。

    Transition

    Transition代表状态之间的切换条件,一般会有一个或多个条件,用于从一个状态切换到另一个状态。

    添加Transition

    在一个State上右键,在弹出菜单中选择Make Transition,可以创建一个到其他State的Transition。

    增加Transition

    点击代表Transition的箭头,可以在Inspector上看到这条Transition的具体情况。选中Transition的源State(从哪个State出发),也可以在State的Inspector中看到这条Transition的具体信息。

    Transitions 显示当前选中的Transition。后面有两个复选框包括Solo和Mute。

    • Solo 如果两个State之间有多条Transition,勾选这个选项后,只有选中Solo的Transition生效。其他Transition会被禁用。

    比如Transition1设置为Solo,则从源State到目的State的3个Transition中只有1会生效

    • Mute 勾选这个选项后,该条Transition会被禁用。如果同时选中了Solo和Mute,Mute会优先生效。

    Name Field 名称框。如上图所示,可以给Transition命名,用于区分两个State之间的多个Transition时非常有用。

    Has Exit Time 是否有退出时间条件。退出时间是一种特殊的transition条件,它没有依赖参数(下面会讲),而是根据设置的退出时间点作为条件进行状态转换。

    Settings transition的一些参数设置。

    • Exit Time 如果勾选了Has Exit Time,该参数是可以设置的,设置动画退出的单位化时间。例如设置为0.75,代表动画播放到75%时为true,如果没有其他条件,会直接切换到下一个State。

      如果exit time小于1,那么state每次循环到对应位置的时候(不管动画是否设置为循环,state总是循环的),该条件都会为true。比如第一次播放到75%,第二次播放到75%……时退出条件都会为true。

      如果exit time大于1,该条件只会检测一次。比如exit time为3.5,state的动画会在循环3次后,在播放到第4次的50%时为true。

    • Fixed Duration 勾选时,下方Transition Duration参数的单位是秒,不勾选时,参数会作为一个百分比。

    • Transition Duration transition的过渡时间。两个状态在转换时,一般不会瞬间从一个状态转换到另一个状态,而是会经过平滑混合,这个属性就是设置了平滑混合的时间。可以从下图的两个蓝色箭头看出转换的时间。

    • Transition Offset 目标状态开始播放的时间偏移。比如设置为0.5,则转换到下一个State时,会从50%的位置开始播放。

    如图设置为0.5时,下一个State会从50%开始转换

    • Interruption SourceOrdered Interruption 这两个参数可以用来控制transition的打断。下面会进行详解。

    Transition图

    上面的参数不仅可以手动修改数值,也可以通过Transition图预览、修改。

    Conditions 条件

    一个Transition可以有一个条件,也可以有多个条件,甚至没有条件。

    如果Conditions中没有条件,但是勾选了Has exit time,那么exit time会被作为state退出的条件,到达exit time时,会切换到下一个state。

    如果有一个或多个条件,需要同时满足这些条件才能切换下一个state。

    一个条件可以是:

    • 相等/不相等判断,一个参数等于/不等于一个常量时为true(int,float,bool类型参数)
    • 比较判断,一个参数与一个常量的比较结果(int,float类型参数)
    • 触发器,触发器激活时为true

    如果Has Exit Time勾选了,并且transition还有一个或多个条件,那么transition需要同时满足到达exit time同时条件全为true,才会切换到下一个state。

    一个transition至少要有一个条件(Has Exit Time可以作为一个条件),否则transition会被忽略。

    【选读】Transition Interruption

    之前我们提到了Interruption SourceOrdered Interruption 这两个参数可以用来控制transition的打断。那么究竟什么是transition打断呢?

    一般情况下,动画系统的transition是不能打断的:一旦transition开始从一个state切换到另一个state,没有打断的方法。就像乘坐跨大西洋航班的乘客一样,你舒适地坐在座位上,直到到达目的地,无法改变主意。对于大多数用户来说,这很好。

    但是如果你需要对transition进行更多控制,可以通过多种方式配置动画系统来满足需求。如果你对目前的目的地不满意,你可以跳进飞行员的座位,在飞行途中改变计划。这能带来更灵活的动画控制,但也很有可能迷失在复杂的打断中。

    我们通过几个例子来深入探索一下打断。从一个相当简单的状态机开始,这个状态机具有四个状态,标记为A到D,并且使用trigger作为每个transition的条件。

    默认情况下,当A到B的切换触发后,状态机开始切换到B,在切换到B之前无法被改变。但是,如果将A->B的transition的interruption source属性从None切换到Current State,A到B的切换就可以被A上的一些触发器中断。

    为什么只有一些呢?因为Ordered Interruption属性默认也会被勾选。这意味着只有优先级大于当前的transition才能打断。选中State A,在Inspector中查看,我们看到A -> C的优先级高于 A -> B,那也意味着只有A -> C能打断A -> B的转换。

    如果我们激活A->B的trigger,然后立马激活A->D的trigger,A到B的transition不会被打断。但是,如果我们激活A->B的trigger,然后立马激活A->C的trigger,A到B的transition会被打断,转而切换到C。

    在动画系统内部,会记录下被打断时的动画的状态,然后从打断的状态混合到新的目标动画。

    如果不勾选Ordered Interruption属性,会发生什么情况呢?A->C 和 A->D 都能打断 A -> B 的transition了。但是,如果在同一帧激活了A->C和A->D的trigger,A->C仍然会优先激活因为A->C的优先级更高。

    如果将A -> B的interruption source属性改为Next State,也就是下一个状态。A->C 和 A->D就不能打断A -> B了。如果我们激活A->B的trigger,然后立马激活B->D的trigger,A到B的transition会被打断,转而切换到D。

    B上的Transition的顺序也有影响。但是这时候Ordered Interruption属性就无法勾选了(因为A -> B是在State A上不在State B上,不参与B的排序)。B上transition的顺序会决定同时触发时,会使用哪一个transition。例如下图的排序,如果B->D 和B->C在同一帧被触发,B->D的transition会被执行。

    如果想完整控制,我们可以设置interruption source属性为Current State Then Next State或Next State Then Current State。设置为这两个值时,State A和State B上的transition都会被考虑在内。例如设置如下,选中了Current State Then Next State:

    如果A到B切换时,同时激活的A->C, A->D, B->C和B->D,会发生什么情况?

    如果选中了Ordered Interruption,那么首先可以忽略A->D(因为比A->B)的优先级低。然后先考虑Current State A,那么A->C会胜出,甚至不用考虑Next State B了。

    如果同样的配置,只激活了B->C 和 B->D,那么B->D会胜出,因为B->D的优先级比B->C更高。

    小结

    上面我们只使用了A->B一种情况作为例子进行了讲解,其他的中断都是类似的,只需要根据他们自身的规则即可。

    有一点很重要需要记住的是:不管打断发生了几次,只要transition没有完成,source state会一直不会变。比如A->B被B->C打断,又被C->D打断,transition未完成前source state会一直是A。Animator.GetCurrentAnimatorStateInfo()也会返回State A。

    简而言之,transition中断功能很强大,并提供了很大的灵活性,但会变得非常混乱。因此,合理地使用transition中断,而且一定要在编辑器中多进行测试。

    总结

    今天讲了Animator组件,希望你能记住一下几点:

    • 如果把Animation Clip比作是一段视频的话,那么Animator就是一个视频播放器,用来控制多段视频的播放、切换等等。
    • Animator Controller就是一个剧本,用来指导视频播放器如何播放多段视频。

    今日思考题

    大智:“导入Standard Assets中的Character包,看看里面的Animator Controller是如何设置的。”
    小新:“好嘞~”
    大智:“收获别忘了分享出来!别忘了点击右下角请好友看免费分享给你的朋友,也许能够帮到他。”

    扩展阅读

    【扩展学习】洪流学堂公众号回复动画可以阅读本系列所有文章,更有视频教程等着你!


    呼~ 今天小新絮絮叨叨的真是够够的了。没讲清楚的地方欢迎评论,咱们一起探索。

    我是大智(微信:zhz11235),你的技术探路者,下次见!

    别走!点赞收藏哦!

    好,你可以走了。

    展开全文
  • unity2D游戏动画状态切换为实例,简单明了讲解animator以及animation的使用。
  • Unity动画状态机学习笔记一、建平面,拖人物模型、建状态、动画导入、拖组件——实现Game时人物动画为等待状态。二、拖WAIT01、WAIT02、WAIT03、WAIT04——实现按数字1切换动作1,按数字2切换动作2,按数字3切换...

    纯步骤学习,最终完成一个人物动画——按数字1、2、3、4键换动作;WASD键控制前后行走与左右偏移;shift键控制人物奔跑;空格键实现跳跃。
    在这里插入图片描述

    一、建平面,拖人物模型、建状态机、动画导入、拖组件——实现Game时人物动画为等待状态。

    人物模型为Unity资源商店里unity-chan!
    在这里插入图片描述
    在这里插入图片描述

    动画层级Animation Layers :如果一个角色要播放移动射击动作,上下身的动作是需要分离的,因此需要用不同的动画层来控制不同身体部位的动作。
    Weight:权重。当前动画层级播放的动画对角色动作的影响程度。
    Mask:遮罩。来屏蔽部分肢体的动画效果。
    Sync:同步。
    Timing:时间配置。
    IK Pass:逆向运动学传递。;
    动画参数 Animation Parameters :动画参数是一系列在动画系统中定义的变量,也可以通过脚本进行访问和赋值。
    参数值的四种类型:
    Float:浮点型
    Int:整数
    Bool:返回布尔值,通过复选框来选择true或flase
    Trigger:触发一个布尔值,复位控制器消耗一个转变,由一个圆按钮表示。
    动画状态 Animation States(点状态机里的动画) :Motion:当前状态下的动画片段
    Speed:默认速度
    Normalized Time:实现动画播放结束的获取
    Mirror:镜像开关。仅对人形动画有效。
    Cycle Offset:循环偏移量。
    Foot IK:是否对足部使用逆向运动学,仅对人形动画有效。
    Write Defaults:动画状态是否写回默认值。动画终止时会覆盖起始状态。
    Transitions:由当前状态出发的过渡条件列表。

    二、拖WAIT01、WAIT02、WAIT03、WAIT04——实现按数字1切换动作1,按数字2切换动作2,按数字3切换动作3,按数字4切换动作4。

    在这里插入图片描述 if (Input.GetKeyDown("1")) { anim.Play("WAIT01", -1, 0f); } if (Input.GetKeyDown("2")) { anim.Play("WAIT02", -1, 0f); } if (Input.GetKeyDown("3")) { anim.Play("WAIT03", -1, 0f); } if (Input.GetKeyDown("4")) { anim.Play("WAIT04", -1, 0f); }

    动画过渡 Animation Transitions(点箭头) :动画过渡是指由一个动画状态过渡到另一个动画状态。(选择状态机里的箭头时出现)
    动画过渡不仅定义了状态之间的混合需要多长的时间,而且定义了它们应该在什么条件下激活。只有当某些条件为真时,才能设置转换。
    加两个箭头表示有两个过渡条件,每个过渡条件是或的关系,两个条件满足一个,就可以实现转换。但是每个过渡条件的参数是且的关系,必须全部同时满足,动画才可以过渡。
    Has Exit Time:是否启用退出时间。启用后,当前动画播放完才能进入下一个动画。
    Setting:设置过度的时间、偏移量等
    Conditions:当动画参数符合相应条件时,触发动画过渡。(动画与脚本交互的关键)。

    三、建混合树run、walk、加入跳的动作——实现按WASD键让角色前进后退,并能左右偏移,Shift键跑,空格键跳跃。

    混合树:混合树是对两个或多个动画进行混合。
    例:角色在跑步时,向左偏移或向右偏移。
    动画过渡与动画混合的区别:
    (1)动画过渡:在一段给定的时间内完成由一个动作状态向另一个动画状态的平滑过渡。走→跑
    (2)动画混合:通过插值技术实现同时对多个动画片段的混合,每个动作对结果的影响取决于权重。

    1. 建参数inputH、inputV(float);run、jump(bool) :
      在这里插入图片描述

    2. 建混合树run、walk :
      2D混合 :通过两个参数来控制子动画的混合。
      walk1D混合 :-1为向左偏移,0为向前跑,1为向右偏移,此时图形没有和其他部分重合;-1~0处,一个重合的深色三角,这里根据权重混合向左跑和向前跑的动画。
      run3.在基础层选中箭头进行设置 :
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述

    完整代码:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class player : MonoBehaviour
    {
        private Animator anim;
        private Rigidbody rbody;
    
        private float inputH;
        private float inputV;
        private bool run;
    
    
    
        void Start()
        {
            anim = GetComponent<Animator>();
            rbody = GetComponent<Rigidbody>();
            run = false;
           
        }
    
        
        void Update()
        {
            if (Input.GetKeyDown("1"))
            {
                anim.Play("WAIT01", -1, 0f);
            }
            if (Input.GetKeyDown("2"))
            {
                anim.Play("WAIT02", -1, 0f);
            }
            if (Input.GetKeyDown("3"))
            {
                anim.Play("WAIT03", -1, 0f);
            }
            if (Input.GetKeyDown("4"))
            {
                anim.Play("WAIT04", -1, 0f);
            }
    
            if (Input.GetKey(KeyCode.LeftShift))
            {
                run = true;
            }
            else
            {
                run = false;
            }
            if (Input.GetKey(KeyCode.Space))
            {
                anim.SetBool("jump", true);
            }
            else
            {
                anim.SetBool("jump", false);
            }
    
            inputH = Input.GetAxis("Horizontal");
            inputV = Input.GetAxis("Vertical");
    
            anim.SetFloat("inputH", inputH);
            anim.SetFloat("inputV", inputV);
            anim.SetBool("run", run);
                   
            float moveX = inputH * 20f * Time.deltaTime;  //X轴的速度
            float moveZ = inputV * 50f * Time.deltaTime;
            if (moveZ <= 0f)
            {
                moveX = 0f;
            }
            else if (run)
            {
                moveX *= 3f;
                moveZ *= 3f;
            }
    
            rbody.velocity = new Vector3(moveX, 0f, moveZ);
        }
    }
    
    

    初来乍到,如果有错误,还请各位大佬指正!

    参考:https://www.bilibili.com/video/BV1h7411L7NE?t=1911

    展开全文
  • 这里写目录标题一、Animator组件二、Controller动画控制文件三、Animation Clip文件四、动画状态机 状态1、Entry状态2、Any状态3、Exit状态 二、Controller动画控制文件 三、Animation Clip文件 四、动画状态机 状态...
  • Unity按键切换状态机

    2021-07-03 21:29:10
    开始想用状态机里的参数来实现,但切换有延迟 后面发现可以直接在脚本里播放指定动画,类似虚幻引擎里的动画蒙太奇 把要切换动画拖进去 添加状态过渡 给过渡加个参数变量挡着,不然直接一运行就切换过去...
  • 如何避免Unity动画状态机的蛛网地狱 提示:这里对文章进行总结: 例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。 ...
  • 2 为不同动画状态切换设置参数 点击之前在Assets->Animation->Player里面创建的Player(Animator类型)的文件,就会看到下图中间这个Animatior面板。这里面会看到之前我们为Player设置的run、idle等动画状态。 每个...
  • unity-动画状态机Animator

    万次阅读 多人点赞 2016-08-27 11:17:08
    Animator,5.x之后推荐使用这种方式,因为里面可以加上混合动画,让动画切换更加平滑 1、导入模型及动作,做成预制件(perfab)直接把整个模型文件夹拷入对应位置,unity会自动import进来 把模型拖进场
  • 今天做红白坦克大战项目,吃到五角星坦克会升级,这就涉及到Animator的动画切换。我看了Unity的官方文档。AnimatorOverrideController官方API说明,里面讲解的更加细致。我刚开始看不懂,慢慢琢磨才看懂一些皮毛。...
  • Unity 动画的简单切换

    千次阅读 2020-12-08 16:39:28
    1.在Project面板下Asset中创建一个Animator Controller; 2.创建两个Animation,分别命名为Walk,Idle; **3.**打开Animator面板,创建两个Creat State—Empty,分别命名为Walk,Idle; ...(如上图) ...
  • Animation动画状态机:是旧版的动画状态机 Animator动画状态机:是新版的动画状态机,其实就是由Animation组成的(这里我们常用这个) Animator的使用: (1)从网上找的3D模型FBX文件,包括了模型的动画文件...
  • Unity中使用动画状态机控制Spine动画

    千次阅读 2019-05-30 17:08:14
    为了在Unity中支持Spine动画,在http://zh.esotericsoftware.com/spine-unity-download/#Download下载spine-unity的导入包,导入到项目中。 导入Spine动画资源 Spine动画导出后一般是如下的3个文件(注意atlas文件要...
  • 你好,我是跟着大智学Unity的萌新,我叫小新,这是复(yu)习(xi)动画系统的最后一节。 小新:“大智,除了使用Layer还有没有更好的组织状态的方式呢?感觉一个Layer里面状态多的时候,还是很显得很乱” 大智:...
  • Unity Animator状态切换打断探索

    千次阅读 2020-08-18 17:38:38
    一、前言 最近在研究animator的时候Interruption ...首先解释下我测试结果测试的原因,对于animator初步了解把下图红色框的过程当做了切换过程。所以我在刚触发A-B时就立即触发A-C,即Interruption没有效果, 后来
  • 有时候需要让美术做一些刚体位移动画, 那么美术在Unity中就要Project视图->Creat->Animation.但是这样创建出来的动画是新版动画,这样播放的话要需要AnimationController文件。 我就想用老版动画怎么办呢? ...
  • 故将当前动画播放时间设置为0,直接停止,并进行动画强行切换和融合 public static void ForceCrossFade(this Animator animator, string name, float transitionDuration, int layer = 0, float normalizedTim...
  • Scanvenger游戏制作笔记(一)Unity3D状态机转换前言一、打开Controller二、选择 Parameters,创建新的trigger三、选择状态转换线四、返回到原状态,选择返回的剪头系列链接 前言 本文章是我学习SIKI学院...
  • 关于Unity动画状态机Animator使用教程
  • unity动画机在面对岔路时,会根据 这个由上到下的顺序依次判断,越往上优先级越高。
  • AnyStatus满足条件到达动画状态Interrupt后一直卡在状态开头,不执行动画。动画该有的都有,试了很久,发现如果不连AnyStatus,动画就能正常播放,问题就出在AnyStatus。 AnyStatus包含本身的状态,满足条件时会无限...
  • Unity动画状态机Animator使用解析

    千次阅读 2018-06-27 00:13:54
    Animator,5.x之后推荐使用这种方式,因为里面可以加上混合动画,让动画切换更加平滑下面就和大家介绍下动画状态机Animator的使用。1、导入模型及动作,做成预制件(perfab)直接把整个模型文件夹拷入对应位置,...
  • Unity动画状态机

    2019-08-01 22:00:06
    通过动画状态机控制动画播放: 人物的Inspector的 Animator组件 是进行动画播放的,【该组件中的Controller属性即为 动画状态机 !】 在Project中创建一个 Animator Controller (动画状态机)—>将其赋值(拖拽...
  • Unity 控制动画状态机

    千次阅读 2017-12-05 22:16:03
    unity控制动画的两种方式 (1) Animation 先在GameObject上添加一个Animation组件,在gameobject脚本中添加 ...(2)Animator,5.x之后推荐使用这种方式,因为里面可以加上混合动画,让动画切换更加平滑。
  • unity 游戏内实现3连击动画状态机
  • 状态嘛,提供了动画状态之间的切换功能、自带动画融合、能编辑动画播放的逻辑顺序、能设置随机播放、能设置行为树。现役动画状态机是在4.0版本问世的,他跟前代相比。那简直是bip骨骼跟bone骨骼的区别。...
  • unity的Animator状态机的基本使用

    千次阅读 2021-11-17 20:07:16
    3.idle是状态刚开始的默认动画状态,anystate则是任何状态的跳转,一般根据实际情况连接到一些随时可以发生的动画状态上去。以及exit则是一些特殊情况需要用到的跳出状态时连接起来。 2.右边的conditions可以...
  • 设计游戏时,框架设计时十分重要的,项目内容一大,各个功能系统间的耦合性就会不...本期是在Unity实现一个简单的框架应用。这可以减少脚本的编写量,通过预先在脚本中写好可以复用的功能,并在场景的游戏物品中修改脚
  • 摘要:使用Cinemachine可以快速制作相机切换动画,来看看我是怎么做的吧。 洪流学堂,让你快人几步。你好,我是跟着大智学Unity的萌新,我叫小新,这是我本周的学习总结报告哦。 好久不见。我最近在帮大智处理家...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,131
精华内容 1,652
关键字:

unity动画状态机切换

友情链接: 语音识别系统3.rar