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

Unity中如何从OnTriggerStay协程启停其他协程解决伤害堆叠问题

核心问题原因

  • 协程停止逻辑错误:StopCoroutine(Damager()) 每次会生成新的协程实例,你停止的根本不是之前已经启动的协程,所以旧协程会一直运行,最终导致伤害堆叠、无法正常停止
  • OnTriggerStay2D 本身就是每帧执行的,你每帧都执行停止再启动协程的操作,既会打乱伤害和音效的计时逻辑,还会重复生成大量协程实例
  • 触发退出判断逻辑错误:不能在OnTriggerStay2D的else分支里停止协程,只要有一个伤害碰撞体还在触发范围内,就不应该停止伤害协程,原逻辑只要碰到非伤害碰撞体就会误停协程
  • 无限循环的协程没有绑定可追踪的实例,即使需要停止也找不到对应的运行中的协程

修复方案

1. 声明协程实例存储变量

首先在类内部新增变量,用来保存已经启动的协程实例,后续启停都基于这两个实例操作:

// 存储运行中的伤害、音效协程实例
private Coroutine damageCoroutine;
private Coroutine sfxCoroutine;
// 可选:多伤害碰撞体场景下的触发计数,避免提前停协程
private int damageTriggerCount = 0;
// 可选:提前缓存AudioManager引用,提升性能
private AudioManager audioManager;

private void Awake()
{
    audioManager = FindObjectOfType<AudioManager>();
}

2. 拆分触发逻辑,改用Enter/Exit事件管控协程

删掉原有的OnTriggerStay2D协程,改用进入/离开触发事件来启停协程,避免每帧重复操作:

// 进入伤害区域时启动协程
private void OnTriggerEnter2D(Collider2D collision)
{
    if (collision.CompareTag("Damage"))
    {
        damageTriggerCount++;
        // 仅当第一次接触伤害碰撞体时启动协程,避免重复启动
        if (damageTriggerCount == 1)
        {
            // 先清理残留的协程
            if (damageCoroutine != null) StopCoroutine(damageCoroutine);
            if (sfxCoroutine != null) StopCoroutine(sfxCoroutine);
            // 启动新协程并保存实例
            damageCoroutine = StartCoroutine(Damager());
            sfxCoroutine = StartCoroutine(DamageSFX());
        }
    }
}

// 离开伤害区域时停止协程
private void OnTriggerExit2D(Collider2D collision)
{
    if (collision.CompareTag("Damage"))
    {
        damageTriggerCount--;
        // 所有伤害碰撞体都离开后再停止协程
        if (damageTriggerCount == 0)
        {
            if (damageCoroutine != null)
            {
                StopCoroutine(damageCoroutine);
                damageCoroutine = null;
            }
            if (sfxCoroutine != null)
            {
                StopCoroutine(sfxCoroutine);
                sfxCoroutine = null;
            }
        }
    }
}

3. 优化协程逻辑

调整音效协程,使用提前缓存的AudioManager引用,避免每帧查找:

IEnumerator Damager()
{
    while (true)
    {
        // 注意修正原拼写错误curruntHealth→currentHealth
        currentHealth--;
        yield return new WaitForSeconds(Delay);
    }
}

IEnumerator DamageSFX()
{
    while (true)
    {
        audioManager.Play("Damage SFX");
        yield return new WaitForSeconds(SoundDelay);
    }
}

内容的提问来源于stack exchange,提问作者JESTA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 23:27:03