相信你可能遇到这样的情况,在用Animator的时候,播放一个动画,调用了一下SetInteger之后,动画就鬼畜了,这是因为没有及时重置动画状态的问题,SetInteger进入状态A后,假设要让它回调状态B,必须至少隔一帧然后SetInteger到B
这里教大家正确的姿势
Animator状态机
现在,假设我们已经有了各个动画文件,比如出场、站立、跑、攻击等,用Animator把各个状态组织起来
设置两个参数:Speed, Action
设置状态过渡的条件
用法
接下来就是用代码控制动画了:接口主要是SetInteger
和GetInteger
为了方便控制,可以封装一个类,我这里封装好了一个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
}