首先我们要知道一段攻击和技能可以分为攻击前摇,攻击判定,攻击后摇。在不是很精细的攻击下,可以将判定和后摇归并在一起,简化攻击过程。
将动画划分为前摇和判定+后摇的形式,那么在Animator Controller里前摇为过度段,而后面的后摇+判定则需要一个判断,如果按下攻击键则进入下一段攻击的前摇。
如下连接
在动做连接处添加转换条件(可以用bool或Trigger,Trigger为触发),我在里有四段,所以用四个判断条件;
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,但是动画是可以分层的,这有效的避免了乱七八糟的连线,不至于连线连得自己都乱了
点击加号可以添加动画层
动画状态添加脚本
在每个大段切换的前动画添加Behaviour脚本(关于Behaviour的具体内容)
为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个切换态上。
由于重击是在每次按下攻击键单独判断的,所以每段攻击后不松开攻击键都可以触发重击。