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

一、前言

文章列表
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,然后standrun可以相互过渡,然后从任意状态,都可以播放attackhithit2death,其中除了death,其他都要自动过渡回stand,这样,我们组织的状态机连线图如下:
在这里插入图片描述

三、过渡条件

这些过渡连线需要设置一些过渡条件,条件判断需要变量,所以,先创建两个变量:SpeedAction,类型都是Int
在这里插入图片描述
设置状态过渡的条件
在这里插入图片描述
规则:移动相关的,用Speed来控制,行为相关的,用Action来控制。所有过渡条件如下:

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

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

接下来就是用代码控制动画了:接口主要是用到AnimatorSetIntegerGetInteger两个接口。

为了方便控制,可以封装一个类,我这里封装好了一个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
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林新发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值