Unity格斗游戏蓄力攻击协程停止后异常重启问题排查
问题解决:松开攻击键后蓄力重复启动的修复
问题根源
StopCoroutine(ChargeAttack())无法正确终止协程:每次调用StartCoroutine(ChargeAttack())都会创建新的协程实例,直接传入方法名无法定位到正在运行的那个协程。ChargeAttack协程内部没有中断判断:即使松开按键,协程里的延迟和循环仍会继续执行,导致蓄力值继续增加。- 状态重置不彻底:松开按键后没有明确标记蓄力状态结束,可能触发后续不必要的逻辑。
修复方案
- 用变量存储正在运行的蓄力协程引用,确保能精准终止。
- 在
ChargeAttack协程中加入按键按住状态的判断,实时中断蓄力流程。 - 优化状态管理,确保松开按键时所有蓄力相关状态都被正确重置。
修改后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Attack : MonoBehaviour { public KeyCode attackKey; public KeyCode stunKey; public int damage; public bool isCharging; // 标记当前是否在蓄力状态 public float maxChargeMultiplier; public float charge; public float attackDelay; public float attackTimer; public Stats target; private Coroutine activeChargeCoroutine; // 存储当前运行的蓄力协程引用 private void Start() { attackTimer = attackDelay; } void Update() { // 启动蓄力:按下攻击键且冷却完成 if (Input.GetKeyDown(attackKey) && attackTimer >= attackDelay) { attackTimer = 0; isCharging = true; // 存储协程引用,方便后续终止 activeChargeCoroutine = StartCoroutine(ChargeAttack()); } // 松开攻击键:终止蓄力、结算伤害、重置状态 if (Input.GetKeyUp(attackKey)) { isCharging = false; Damage(); // 终止正在运行的蓄力协程(如果存在) if (activeChargeCoroutine != null) { StopCoroutine(activeChargeCoroutine); activeChargeCoroutine = null; } charge = 0; StartCoroutine(RechargeAttack()); } } public IEnumerator RechargeAttack() { for (int i = 0; i < attackDelay * 10; i++) { yield return new WaitForSecondsRealtime(0.1f); attackTimer += 0.1f; } } public IEnumerator ChargeAttack() { // 等待1秒蓄力启动延迟,符合需求设定 yield return new WaitForSecondsRealtime(1f); // 循环蓄力:每0.1秒增加0.1,直到达到最大值或松开按键 while (isCharging && charge < maxChargeMultiplier) { yield return new WaitForSecondsRealtime(0.1f); charge += 0.1f; // 确保蓄力值不超过最大值 charge = Mathf.Min(charge, maxChargeMultiplier); } } public void Damage() { if(target != null) { if (target.blocking) { return; } else { target.health -= Mathf.RoundToInt(damage * charge); gameObject.GetComponent<Stats>().combo += 20; } } charge = 0; } private void OnTriggerEnter2D(Collider2D col) { if (col.GetComponent<Stats>()) { target = col.gameObject.GetComponent<Stats>(); } } private void OnTriggerExit2D(Collider2D col) { if (col.GetComponent<Stats>() == target) { target = null; } } }
关键修改点说明
- 添加
activeChargeCoroutine变量:用来保存启动的蓄力协程实例,确保StopCoroutine能精准终止目标协程。 - 新增
isCharging状态标记:在ChargeAttack的循环中实时检查该标记,一旦松开按键(标记设为false),立即停止蓄力循环。 - 调整蓄力启动延迟:将原1.25秒改为需求中的1秒,符合设计要求。
- 加入蓄力值上限限制:用
Mathf.Min确保蓄力值不会超过maxChargeMultiplier,避免溢出。
内容的提问来源于stack exchange,提问作者Maddox Fox
相关产品推荐
相关产品推荐

