上节课讲了unity 游戏内实现3连击动画的实现,因为在游戏中我们的连击动画可能会有很多,为了避免使用较多的if  else 我们这节课开始引用状态机来更好的实现效果,那么接下来我们就开始状态机的讲解!!!

首先是写一个我们管理动画的状态机

/// <summary>
/// 状态机
/// </summary>
public class ActionState
{
    public PlayerController playerc;
    /// <summary>
    /// 开始进入状态该做什么
    /// </summary>
    public virtual void Enter()
    {
        OnEnter();
    }
    /// <summary>
    /// 进入状态回调
    /// </summary>
    protected void OnEnter()
    {
        playerc.currentState = this;
        this.playerc.stateName = this.GetType().ToString();//状态名称赋值  在这里为了更好地让我们看到当前所在状态,所以在public属性面板可以看到
    }
    /// <summary>
    /// 处理玩家输入事件
    /// </summary>
    public virtual void HandleInput()
    {

    }
}

然后写我们的玩家控制脚本  我们要把这个脚本挂在人物上

///玩家控制脚本
public class PlayerController : MonoBehaviour
{
    public ActionState currentState;//当前的状态
    public Attack1 attack1;
    public Attack2 attack2;
    public Attack3 attack3;
    public Attack4 attack4;
    public IdleState idleState;
    public Animator animator;
    public bool leftMouse_KeyDown;//鼠标左键
    public bool leftControl_KeyDown;//左Ctrl键
    public string stateName;//状态名称
    private AnimatorStateInfo info;//显示当前状态名
    /// <summary>
    /// 判断可不可以攻击
    /// </summary>
    /// <param name="start">开始</param>
    /// <param name="end">结束</param>
    /// <returns></returns>
    public bool CanAttack(float start, float end)
    {
        return info.normalizedTime >= start && info.normalizedTime <= end;
    }

    void Start()
    {
        animator=GetComponent<Animator>();
        idleState = new IdleState() { playerc = this };
        attack1 = new Attack1() { playerc = this };
        attack2 = new Attack2() { playerc = this };
        attack3 = new Attack3() { playerc = this };
        attack4 = new Attack4() { playerc = this };
        currentState = idleState;//默认设置当前状态为休闲状态
        currentState.Enter();//进入休闲状态
    }

    // Update is called once per frame
    void Update()
    {
        leftMouse_KeyDown = Input.GetMouseButtonDown(0);//获取鼠标左键
        leftControl_KeyDown = Input.GetKeyDown(KeyCode.LeftControl);//获取左ctrl键
        bool input_attack= leftMouse_KeyDown|| leftControl_KeyDown;//获取当前输入
        info = this.animator.GetCurrentAnimatorStateInfo(0);//获取当前状态
        if (currentState != idleState && !animator.IsInTransition(0) && info.IsName("Idle_A")) 
        {
            idleState.Enter();
        }
        if (input_attack)//判断当前输入
        {
            currentState.HandleInput();//进入
        }
    }
}

接下来我们来写我们的状态类脚本  我们的Idle状态和攻击状态都要继承刚才所写的ActionState去重写我们的方法来实现状态的切换

//状态Idle
public class IdleState : ActionState
{
    public override void HandleInput()
    {
        base.HandleInput();
        if (playerc.leftMouse_KeyDown)//鼠标左键
        {
            playerc.attack1.Enter();//攻击1状态进入
        }
        else if (playerc.leftControl_KeyDown)//左Ctrl键
        {
            playerc.attack2.Enter();//攻击二状态进入
        }
    }
    public override void Enter()
    {
        base.Enter();
        playerc.animator.CrossFade("Idle_A", 0.1f);//播放idle状态
    }
}
public class Attack4 : ActionState
{
    public override void Enter()
    {
        base.Enter();
        playerc.animator.CrossFade("Atk4", 0.1f);
    }
    public override void HandleInput()
    {
        base.HandleInput();
        if (playerc.CanAttack(0.45f, 0.9f))
        {
            if (playerc.leftMouse_KeyDown)
            {
                playerc.idleState.Enter();
            }
            else if (playerc.leftControl_KeyDown)
            {
                playerc.idleState.Enter();
            }
        }
    }
}
public class Attack3 : ActionState
{
    public override void Enter()
    {
        base.Enter();
        playerc.animator.CrossFade("Atk3", 0.1f);
    }
    public override void HandleInput()
    {
        base.HandleInput();
        if (playerc.CanAttack(0.45f, 0.9f))
        {
            if (playerc.leftMouse_KeyDown)
            {
                playerc.attack4.Enter();
            }
            else if (playerc.leftControl_KeyDown)
            {
                playerc.attack1.Enter();
            }
        }
    }
}
public class Attack2 : ActionState
{
    public override void Enter()
    {
        base.Enter();
        playerc.animator.CrossFade("Atk2", 0.1f);
    }
    public override void HandleInput()
    {
        base.HandleInput();
        if (playerc.CanAttack(0.45f, 0.9f))
        {
            if (playerc.leftMouse_KeyDown)
            {
                playerc.attack3.Enter();
            }
            else if (playerc.leftControl_KeyDown)
            {
                playerc.attack4.Enter();
            }
        }
    }
}
public class Attack1 : ActionState
{
    public override void Enter()
    {
        base.Enter();
        playerc.animator.CrossFade("Atk1", 0.1f);//播放对应动画
    }
    public override void HandleInput()
    {
        base.HandleInput();
        if (playerc.CanAttack(0.45f,0.9f))
        {
            if (playerc.leftMouse_KeyDown)
            {
                playerc.attack2.Enter();
            }
            else if (playerc.leftControl_KeyDown)
            {
                playerc.attack3.Enter();
            }
        }
    }
}

在这里就不多敲注释了  只要实现了一个状态  我们到后边改变状态就是复制粘贴的问题了

最后实现效果:

一直点击鼠标左键 :攻击1-攻击2-攻击3-攻击4-休闲

一直左Ctrl:攻击2-攻击4-休闲

先左键然后Ctrl接着左键再ctrl:攻击1-攻击3-攻击2-攻击4-休闲

在这里实现效果有很多就不一一列举了

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐