相信你可能遇到这样的情况,在用Animator的时候,播放一个动画,调用了一下SetInteger之后,动画就鬼畜了,这是因为没有及时重置动画状态的问题,SetInteger进入状态A后,假设要让它回调状态B,必须至少隔一帧然后SetInteger到B
这里教大家正确的姿势

Animator状态机

现在,假设我们已经有了各个动画文件,比如出场、站立、跑、攻击等,用Animator把各个状态组织起来

unity 动态播放音频 unity播放动图_unity


设置两个参数:Speed, Action

unity 动态播放音频 unity播放动图_动画_02


设置状态过渡的条件

unity 动态播放音频 unity播放动图_System_03

用法

接下来就是用代码控制动画了:接口主要是SetIntegerGetInteger 为了方便控制,可以封装一个类,我这里封装好了一个CharacterAniLogic.cs(在文章最下面)

现在,假设现在我们有一个角色GameObject,身上有一个Animator组件
先创建一个角色控制的脚本: PlayerBhv.cs,挂在角色GameObject上
然后在PlayerBhv中通过CharacterAniLogic组件来控制动画播放
注:CharacterAniLogic可以动态AddComponent,也可以事先挂好然后GetComponent 使用示例

// PlayerBhv.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class PlayerBhv : MonoBehaviour
{
	private CharacterAniLogic m_aniCtr;
	public GameObject modelObj;
	
	void Start()
	{
		var ani = modelObj.GetComponent<Animator>();
		m_aniCtr = modelObj.AddComponent<CharacterAniLogic>();
		m_aniCtr.Init(ani);
	}
	
	void Update()
	{
		#region Speed类型的动画
		if(Input.GetButtonDown(KeyCode.A))
		{
			//播放跑动作
			m_aniCtr.PlayRun();
		}
		else if(Input.GetButtonDown(KeyCode.B))
		{
			//播放站立动作
			m_aniCtr.PlayIdle();
		}
		#endregion
		
		#region Action类型的动画
		//Action类型的动画,封装类内部做了队列播放///
		//播放攻击动作,具体Action的值看你的Animator的过渡条件编辑
		if(Input.GetButtonDown(KeyCode.C))
		{
			m_aniCtr.PlayAnimation(10020);
		}
		else if(Input.GetButtonDown(KeyCode.D))
		{
			m_aniCtr.PlayAnimation(10030);
		}
		#endregion
	}
}

CharacterAniLogic组件代码

// CharacterAniLogic.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

// 角色动画逻辑
public class CharacterAniLogic : MonoBehaviour
{
    private const string STR_ACTION = "Action";
    private const string STR_SPEED = "Speed";
    private const string STR_DEATH = "death";
    private Animator m_animator;

    /// <summary>
    /// 准备播放的动作
    /// </summary>
    private Queue<int> m_animQueue = new Queue<int>();
    private AnimatorClipInfo[] mClips = null;

    /// <summary>
    /// 是否播放跑步动作
    /// </summary>
    public bool IsPlayRunAction = false;

    public void Init(Animator ani)
    {
        m_animator = ani;
    }

	void LateUpdate()
	{
		TickAnimation();
	}
	
    private void TickAnimation()
    {
        if (m_animator == null)
        {
            return;
        }
        if (!m_animator.isInitialized || m_animator.IsInTransition(0))
        {
            return;
        }
        if (null == mClips)
            mClips = m_animator.GetCurrentAnimatorClipInfo(0);
        if (null == mClips || mClips.Length == 0)
            return;

        int actionID = m_animator.GetInteger(STR_ACTION);
        if (actionID > 0)
        {
            m_animator.SetInteger(STR_ACTION, 0);
        }
        //将剩余队列的动作重新拿出来播放
        PlayRemainAction();

        if (IsPlayRunAction)
        {
            IsPlayRunAction = false;
            PlayRun();
        }
    }

    /// <summary>
    /// 将剩余队列的动作重新拿出来播放
    /// </summary>
    void PlayRemainAction()
    {
        if (m_animQueue.Count > 0)
        {
            PlayAnimation(m_animQueue.Dequeue());
        }
    }

    public void PlayDieImmediately()
    {
        PlayAniImmediately(STR_DEATH);
    }

    public void PlayAniImmediately(string name)
    {
        m_animator.Play(name, 0, 0.95f);
    }

    /// <summary>
    /// 播放不同动作ID
    /// </summary>
    /// <param name="isJump"></param>
    /// 
    public void PlayAnimation(int actionID)
    {
        if (m_animator == null)
            return;
        if (m_animator != null && (!m_animator.isInitialized || m_animator.IsInTransition(0) && actionID != 20))
        {
            m_animQueue.Enqueue(actionID);
            return;
        }
        m_animator.SetInteger(STR_ACTION, actionID);
    }


    /// <summary>
    /// 播放站立状态
    /// </summary>
    public void PlayIdle()
    {
        if (null == m_animator || !m_animator.isInitialized)
            return;
        m_animator.SetInteger(STR_SPEED, (int)CharacterAnimId.Idle);
    }

    /// <summary>
    /// 播放跑步状态
    /// </summary>
    public void PlayRun()
    {
        if (null == m_animator || !m_animator.isInitialized)
            return;
        m_animator.SetInteger(STR_SPEED, (int)CharacterAnimId.Run);
    }

    public void ClearAnimQueue()
    {
        if (m_animQueue.Count > 0)
        {
            m_animQueue.Clear();
        }
    }

    /// <summary>
    /// 强制切回idle
    /// </summary>
    public void ForceToActionIdle()
    {
        PlayAnimation((int)CharacterAnimId.ActionToFightIdle);
    }

}

public enum CharacterAnimId
{
    #region 使用Speed参数
    Run = 1,
    Idle = 2,

    AttackIdle = 4,//战斗待机
    AttackRun = 3,//战斗跑步

    MountIdle = 7,//坐骑待机
    MountRun = 8,//坐骑跑步

    BossIdle = 9,//boss小动作

    MountIdle01 = 50,//坐骑待机
    MountRun01 = 51,//坐骑跑步
    #endregion

    AttackStandToStand = 5,//战斗待机过渡到普通待机
    StandToAttackStand = 6,//普通待机过渡到战斗待机


    /// <summary>
    /// 跳跃第一段
    /// </summary>
    Jump01 = 10,
    /// <summary>
    /// 跳跃第二段
    /// </summary>
    Jump02 = 11,
    /// <summary>
    /// 跳跃结束
    /// </summary>
    JumpOver = 12,
    //跳跃结束回正常待机
    JumpOverToStand = 13,
    //跳跃结束回战斗待机
    JumpOverToAttackStand = 14,
    //受击
    Hit = 20,
    AttackFly = 21,
    HitHeavy = 22,

    //死亡
    Dead = 30,
    //死亡击飞
    DeadFly = 31,

    //出生动作
    Born = 32,
    //复活
    Revive = 33,
    ChongFeng = 40,
    //冲锋回战斗待机
    ChongFengToStand = 41,

    ActionToFightIdle = 100,
    ActionToIdle = 101,

    ActionToMountIdle = 102,//强制切回坐骑idle状态
    ActionToMountRun = 103,//强制切回到坐骑跑步状态

    ActionToMountIdle01 = 110,//强制切回坐骑idle01状态
    ActionToMountRun01 = 111,//强制切回到坐骑跑步01状态
    /// <summary>
    /// 打坐-单人
    /// </summary>
    Meditating_One = 120,
    /// <summary>
    /// 打坐-双人
    /// </summary>
    Meditating_Two = 121,
    /// <summary>
    /// 行走
    /// </summary>
    Walk = 200,
    /// <summary>
    /// 左转
    /// </summary>
    ZhuanShen01 = 201,
    /// <summary>
    /// 右转
    /// </summary>
    ZhuanShen02 = 202,
    /// <summary>
    /// 喘息
    /// </summary>
    ChuanXi = 203,
    /// <summary>
    /// 喝酒动作
    /// </summary>
    HeJiu01 = 204,
    /// <summary>
    /// 喝完动作
    /// </summary>
    HeJiu02 = 205,
    /// <summary>
    /// 告别
    /// </summary>
    GaoBie = 206,
    /// <summary>
    /// 跨立
    /// </summary>
    KuaLi = 207,
    /// <summary>
    /// 挑衅
    /// </summary>
    TiaoXin = 208,
    /// <summary>
    ///  拔刀
    /// </summary>
    BaDao = 209
}