如何停止协程的一个特定实例

问题描述

所以我有一个OnTriggerEnter函数,该函数每隔一秒钟使用协程删除一次运行状况。我想使用OnTriggerExit函数和StopCoroutine停止它。虽然这仅适用于一个gameObject,但由于总是取消“常规”,因此它会与多个对撞机中断。什么是停止协程离开左撞机的最佳方法?我觉得有一个简单的解决方案,但我看不到。

OnTrigger进入/退出

    private float delay= 1f;
    void OnTriggerEnter(Collider other)
    {
        Dealdamage(other,delay);
    }
    private void OnTriggerExit(Collider other)
    {
        Stopdamage();
    }

协程

private Coroutine routine;
private void Dealdamage(Collider col,float damageRate)
{
    var health = col.GetComponent<IChangeHealth>();
    if (health == null) return;
    routine = StartCoroutine((damageEverySecond(health,damageRate)));
}
IEnumerator damageEverySecond(IChangeHealth health,float rate)
{
    while (true)
    {
       health.RemoveHealth(damage);       
               yield return new WaitForSeconds(rate); 
    }
}
protected void Stopdamage()
{
    StopCoroutine(routine);
}

解决方法

当被提及时,使用Dictionary<Collider,Coroutine>存储和检索给定对撞机对象的例程:

private float _delay= 1f;
private readonly Dictionary<Collider,Coroutine> _routines = new Dictionary<Collider,Coroutine>();

private void OnTriggerEnter(Collider other)
{
    DealDamage(other,_delay);
}

private void OnTriggerExit(Collider other)
{
    // pass on the collider reference
    StopDamage(other);
}

private void DealDamage(Collider col,float damageRate)
{
    // In general don't use null check for types derived from UnityUngine.Object but rather the bool operator
    if (!col.TryGetComponent(out IChangeHealth health)) return;

    // Check if a routine already exists for this collider
    if(_routines.TryGetValue(col,out var routine) && routine != null)
    {
        // Avoid concurrent routines for the same object
        StopCoroutine(routine);
    }

    // start a routine for this collider and store the reference
    routines[col] = StartCoroutine((DamageEverySecond(health,damageRate)));
}

protected void StopDamage(Collider other)
{
    // Check if a routine already exists for this collider
    if(_routines.TryGetValue(other,out var routine) && routine != null)
    {
        // if yes stop it
        StopCoroutine(routine);
    }
}

private IEnumerator DamageEverySecond(IChangeHealth health,float rate)
{
    while (true)
    {
       health.RemoveHealth(Damage); 
  
       yield return new WaitForSeconds(rate); 
    }
}

另请参见