文章目录
一、前言二、Animator状态机组织三、过渡条件四、用代码设置过渡条件,触发动画播放五、CharacterAniLogic.cs完整代码
一、前言
文章列表 Unity游戏开发——新发教你做游戏(一):打开游戏开发新世界的大门 Unity游戏开发——新发教你做游戏(二):60个Unity免费资源获取网站 Unity游戏开发——新发教你做游戏(三):3种资源加载方式 Unity游戏开发——新发教你做游戏(四):角色移动控制 Unity游戏开发——新发教你做游戏(五):导航系统Navigation Unity游戏开发——新发教你做游戏(六):教你2个步骤实现摇杆功能 Unity游戏开发——新发教你做游戏(七):Animator控制角色动画播放 本工程Demo我已上传到GitHub,感兴趣的同学可以下载下来学习。 GitHub工程地址:https://github.com/linxinfa/Unity-RpgGameDemo
嗨,大家好,我是新发,上一篇文章我们讲了摇杆功能的实现。今天,来讲讲Animator控制角色动画播放的实现。
二、Animator状态机组织
现在,假设我们已经有了各个动画文件,比如站立、跑、攻击、受击等,用Animator把各个状态组织起来。 思路:默认状态是stand,然后stand和run可以相互过渡,然后从任意状态,都可以播放attack、hit、hit2、death,其中除了death,其他都要自动过渡回stand,这样,我们组织的状态机连线图如下:
三、过渡条件
这些过渡连线需要设置一些过渡条件,条件判断需要变量,所以,先创建两个变量:Speed,Action,类型都是Int。 设置状态过渡的条件 规则:移动相关的,用Speed来控制,行为相关的,用Action来控制。所有过渡条件如下:
state1state2conditions
standrunSpeed == 1runstandSpeed == 2Any StateattackAction == 1000Any StatehitAction == 2000Any Statehit2Action == 2001Any StatedeathAction == 3000
四、用代码设置过渡条件,触发动画播放
接下来就是用代码控制动画了:接口主要是用到Animator的SetInteger和GetInteger两个接口。
为了方便控制,可以封装一个类,我这里封装好了一个CharacterAniLogic.cs(在文章最下面) 封装出几个对外接口:
public void PlayRun();
public void PlayIdle();
public void PlayAnimation(int actionID
)
我们再定义一个枚举
public enum CharacterAniId
{
Run
= 1,
Idle
= 2,
Attack
= 1000,
Hit
= 2000,
Hit2
= 2001,
Death
= 3000,
}
这样,我们通过定义的枚举,就可以播放对应的动画了,比如播放attack
m_animator
.SetInteger("Action", (int)CharacterAniId
.Attack
);
还要,可能我们需要判断当前是在某个动画状态,可以通过AnimatorStateInfo来判断
public bool IsPlayingRunAni()
{
AnimatorStateInfo stateinfo
= m_animator
.GetCurrentAnimatorStateInfo(0);
return stateinfo
.IsName("run");
}
五、CharacterAniLogic.cs完整代码
using UnityEngine
;
using System
.Collections
.Generic
;
public class CharacterAniCtrler
{
private const string STR_ACTION
= "Action";
private const string STR_SPEED
= "Speed";
private const string STR_DEATH
= "death";
private Animator m_animator
;
private Queue
<int> m_animQueue
= new Queue<int>();
private AnimatorClipInfo
[] mClips
= null;
public bool IsPlayRunAction
= false;
public void Init(Animator ani
)
{
m_animator
= ani
;
}
public void LateUpdate()
{
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();
}
}
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);
}
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
);
}
public void PlayIdle()
{
if (null == m_animator
|| !m_animator
.isInitialized
)
return;
m_animator
.SetInteger(STR_SPEED
, (int)CharacterAniId
.Idle
);
}
public bool IsPlayingRunAni()
{
AnimatorStateInfo stateinfo
= m_animator
.GetCurrentAnimatorStateInfo(0);
return stateinfo
.IsName("run");
}
public void PlayRun()
{
if (null == m_animator
|| !m_animator
.isInitialized
)
return;
m_animator
.SetInteger(STR_SPEED
, (int)CharacterAniId
.Run
);
}
public void ClearAnimQueue()
{
if (m_animQueue
.Count
> 0)
{
m_animQueue
.Clear();
}
}
}
public enum CharacterAniId
{
#region 使用Speed参数
Run
= 1,
Idle
= 2,
#endregion
#region 使用Action参数
Attack
= 1000,
Hit
= 2000,
Hit2
= 2001,
Death
= 3000,
#endregion
}