Unity游戏开发——新发教你做游戏(七):Animator控制角色动画播放

    科技2025-05-14  9

    文章目录

    一、前言二、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来控制。所有过渡条件如下:

    state1state2conditionsstandrunSpeed == 1runstandSpeed == 2Any StateattackAction == 1000Any StatehitAction == 2000Any Statehit2Action == 2001Any StatedeathAction == 3000

    四、用代码设置过渡条件,触发动画播放

    接下来就是用代码控制动画了:接口主要是用到Animator的SetInteger和GetInteger两个接口。

    为了方便控制,可以封装一个类,我这里封装好了一个CharacterAniLogic.cs(在文章最下面) 封装出几个对外接口:

    /// <summary> /// 播放跑步状态 /// </summary> public void PlayRun(); /// <summary> /// 播放站立状态 /// </summary> public void PlayIdle(); /// <summary> /// 播放不同动作ID /// </summary> /// <param name="isJump"></param> /// 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来判断

    //判断当前动画状态是否为run public bool IsPlayingRunAni() { AnimatorStateInfo stateinfo = m_animator.GetCurrentAnimatorStateInfo(0); return stateinfo.IsName("run"); }

    五、CharacterAniLogic.cs完整代码

    // 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; /// <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; } 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) { //将Action复位 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)CharacterAniId.Idle); } public bool IsPlayingRunAni() { AnimatorStateInfo stateinfo = m_animator.GetCurrentAnimatorStateInfo(0); return stateinfo.IsName("run"); } /// <summary> /// 播放跑步状态 /// </summary> 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 }
    Processed: 0.010, SQL: 8