连续攻击及其动画转换

  • 首先我们要知道一段攻击和技能可以分为攻击前摇,攻击判定,攻击后摇。在不是很精细的攻击下,可以将判定和后摇归并在一起,简化攻击过程。

将动画划分为前摇和判定+后摇的形式,那么在Animator Controller里前摇为过度段,而后面的后摇+判定则需要一个判断,如果按下攻击键则进入下一段攻击的前摇。

如下连接

连续攻击及其动画转换_第1张图片

在动做连接处添加转换条件(可以用bool或Trigger,Trigger为触发),我在里有四段,所以用四个判断条件;

连续攻击及其动画转换_第2张图片
连续攻击及其动画转换_第3张图片

1,2,3为控制动画切换的时间过渡参数,自行调整(更为具体的内容可以查看官方文档)

4为要添加的条件

attack1:stand->attack_a-01

attack2:attack_a-02->attack_b-01

attack3:attack_b-02->attack_c-01

attack4:attack_c-02->attack_d-01

第四段攻击过后为自动过度到站立动画,不用判断条件,调好参数即可。


  • 代码

挂在角色身上的攻击代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class attack : MonoBehaviour
{
    public static attack at;//使其他脚本可以访问到

    public Animator an;//获取动画组件,记得在unity里面拖进去
    public bool canReceive;//能去接收攻击信号
    public bool receiveInput;//接收攻击信号
    public int time;//计时器
    public int Ti;//判断重击

    private void Awake()
    {
        at = this;
    }

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        Attack();
    }

    public void Attack()
    {
        /*
            获取按键:
            1.前面的GetAxis,GetAxisRaw和GetButton都只能获取unity所提供的特定键(具体内容自行查找),
              GetButton:按下只要不松开就一直返回true(如按下一直发射子弹)。
              GetButtonDown:只有按下的一瞬间返回true。
              GetButtonUp:只有抬起的一瞬间返回true。

            2.GetKey,同GetButton一样,有三种(同上),但键要更多。可以通过KeyCode点出来
                    
        */


        if (Input.GetKeyDown(KeyCode.A))
        {
            Ti = 1;//判断重击
            if (canReceive)
            {
                receiveInput = true;
                canReceive = false; ;
            }
            else
            {
                return;
            }
        }

        if (Input.GetKey(KeyCode.A))
        {
            time++;//由于按下之后会一直返回true且速度很快,time用来减缓重击动画播放的时间
            if (time > 130 && Ti == 1)//Ti用来限定重击次数,每长按一次仅触发一次重击动画
            {
                an.Play("attack_d-02");//播放重击动画,因为该动画为不循环动画,所以播完自动停止继而播放站立动画
                Ti = 0;
            }
        }
        else
        {
            time = 0;
        }
    }
}

关于Animator.Play的详细信息(所以在切换动画时可以用连线,可以用纯代码)

  • 这里引入一个知识,前面说过一个角色只能有一个Animator,但是动画是可以分层的,这有效的避免了乱七八糟的连线,不至于连线连得自己都乱了

连续攻击及其动画转换_第4张图片

点击加号可以添加动画层


  • 动画状态添加脚本

在每个大段切换的前动画添加Behaviour脚本(关于Behaviour的具体内容)

连续攻击及其动画转换_第5张图片

为stand添加Behaviour(下面的同理)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class change01 : StateMachineBehaviour
{
    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    //当状态机评估此状态时,在第一个 Update 帧上进行调用。
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        attack.at.canReceive = true;//在开始时将canReceive设为true,表示此时可以接收输入信号
    }

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    //除第一帧和最后一帧外,在每个 Update 帧上进行调用。
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        if (attack.at.receiveInput)//接收到了信号
        {
            animator.SetBool("attack1", true);//播放动画
            attack.at.receiveInput = false;
            attack.at.canReceive = false;
        }
    }

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    //当状态机评估此状态时,在最后一个 Update 帧上进行调用。
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.SetBool("attack1", false);//在结束时将动画关闭,并开启接收信号
        attack.at.canReceive = true;
    }

    // OnStateMove is called right after Animator.OnAnimatorMove()
    //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that processes and affects root motion
    //}

    // OnStateIK is called right after Animator.OnAnimatorIK()
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that sets up animation IK (inverse kinematics)
    //}
}

为 attack_a-02添加Behaviour

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class change02 : StateMachineBehaviour
{
    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    //override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //  attack.at.canReceive = true;
    //}

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        if (attack.at.receiveInput )
        {
            animator.SetBool("attack2", true);
            attack.at.receiveInput = false;
            attack.at.canReceive = false;
        }
    }

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.SetBool("attack2", false);
        attack.at.canReceive = true;
    }

    // OnStateMove is called right after Animator.OnAnimatorMove()
    //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that processes and affects root motion
    //}

    // OnStateIK is called right after Animator.OnAnimatorIK()
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that sets up animation IK (inverse kinematics)
    //}
}

为attack_b-02添加Behaviour

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class change03 : StateMachineBehaviour
{
    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    /*override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        attack.at.canReceive = true;
    }*/

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        if (attack.at.receiveInput )
        {
            animator.SetBool("attack3", true);
            attack.at.receiveInput = false;
            attack.at.canReceive = false;
        }
        /*animator.SetBool("attack1", false);*/
    }

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.SetBool("attack3", false);
        attack.at.canReceive = true;
    }

    // OnStateMove is called right after Animator.OnAnimatorMove()
    //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that processes and affects root motion
    //}

    // OnStateIK is called right after Animator.OnAnimatorIK()
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that sets up animation IK (inverse kinematics)
    //}
}

为attack_c-02添加Behaviour

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class change04 : StateMachineBehaviour
{
    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    /*override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        attack.at.canReceive = true;
    }*/

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        if (attack.at.receiveInput )
        {
            animator.SetBool("attack4", true);
            attack.at.receiveInput = false;
            attack.at.canReceive = false;
        }
        /*animator.SetBool("attack1", false);*/
    }

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        animator.SetBool("attack4", false);
        attack.at.canReceive = true;
    }

    // OnStateMove is called right after Animator.OnAnimatorMove()
    //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that processes and affects root motion
    //}

    // OnStateIK is called right after Animator.OnAnimatorIK()
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that sets up animation IK (inverse kinematics)
    //}
}
  • 注意这是4个脚本,分别挂在4个切换态上。

  • 由于重击是在每次按下攻击键单独判断的,所以每段攻击后不松开攻击键都可以触发重击。

你可能感兴趣的:(Unity,2D基础,安全)