Unity:如何在StateMachineBehaviour中实现状态延迟与Boss攻击冷却?
解决方案:实现Boss攻击后Run状态冷却
核心思路
StateMachineBehaviour 本身不是 MonoBehaviour 子类,无法直接启动协程。我们需要借助挂载在 Boss 对象上的 MonoBehaviour(即你的 Boss.cs 脚本)来管理冷却逻辑,同时在状态机中判断冷却状态,限制攻击触发。
步骤1:在Boss主脚本中添加冷却逻辑
打开你的 Boss.cs(挂载在Boss对象上的 MonoBehaviour 脚本),添加以下代码:
public bool isAttackOnCooldown = false; public float attackCooldown = 2f; // 冷却时长,可在Inspector面板调整 public Transform player; // 缓存Player引用 private void Start() { player = GameObject.FindGameObjectWithTag("Player").transform; } // 启动冷却协程的方法 public void StartAttackCooldown() { if (!isAttackOnCooldown) { StartCoroutine(AttackCooldownCoroutine()); } } // 冷却协程 private IEnumerator AttackCooldownCoroutine() { isAttackOnCooldown = true; yield return new WaitForSeconds(attackCooldown); isAttackOnCooldown = false; }
步骤2:修改Run状态的StateMachineBehaviour
更新你当前的Run状态行为脚本,添加冷却判断逻辑:
private Transform player; private Rigidbody2D rb; private Boss boss; private bool switchAttack = false; override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // 复用Boss脚本缓存的引用,避免重复查找 boss = animator.GetComponent<Boss>(); rb = animator.GetComponent<Rigidbody2D>(); player = boss.player; } override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { boss.LookAtPlayer(); Vector2 target = new Vector2(player.position.x, rb.position.y); Vector2 newPos = Vector2.MoveTowards(rb.position, target, speed * Time.fixedDeltaTime); rb.MovePosition(newPos); // 仅当不在冷却范围内,且距离满足时才触发攻击 if (!boss.isAttackOnCooldown && Vector2.Distance(player.position, rb.position) <= attackRange) { animator.SetTrigger("Attack"); animator.SetBool("AttackSwitch", switchAttack); } } override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { animator.ResetTrigger("Attack"); switchAttack = !animator.GetBool("AttackSwitch"); }
步骤3:在Attack状态添加冷却触发逻辑
创建一个新的 StateMachineBehaviour 脚本(比如命名为 AttackExitCooldown),用于在攻击结束时启动冷却:
using UnityEngine; public class AttackExitCooldown : StateMachineBehaviour { private Boss boss; override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { boss = animator.GetComponent<Boss>(); } override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { // 攻击动画结束时,启动冷却 boss.StartAttackCooldown(); } }
将这个脚本添加到Animator中所有攻击状态(比如Attack1、Attack2)的Behaviour列表里。
为什么之前的方法失败?
StateMachineBehaviour不是MonoBehaviour,无法直接调用StartCoroutine,必须通过同一对象上的MonoBehaviour(如你的Boss.cs)来启动。- 你之前的代码中未正确赋值
monoBehaviour变量,导致协程无法启动。 - 重复在协程中获取组件是冗余操作,应该复用已缓存的引用。
内容的提问来源于stack exchange,提问作者Alon Belkin
相关产品推荐
相关产品推荐

