You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity格斗游戏蓄力攻击协程停止后异常重启问题排查

问题解决:松开攻击键后蓄力重复启动的修复

问题根源

  1. StopCoroutine(ChargeAttack())无法正确终止协程:每次调用StartCoroutine(ChargeAttack())都会创建新的协程实例,直接传入方法名无法定位到正在运行的那个协程。
  2. ChargeAttack协程内部没有中断判断:即使松开按键,协程里的延迟和循环仍会继续执行,导致蓄力值继续增加。
  3. 状态重置不彻底:松开按键后没有明确标记蓄力状态结束,可能触发后续不必要的逻辑。

修复方案

  • 用变量存储正在运行的蓄力协程引用,确保能精准终止。
  • 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 21:22:41