【问题标题】:How to stop one specific instance of a Coroutine如何停止协程的一个特定实例
【发布时间】:2020-09-14 17:08:19
【问题描述】:

所以我有一个 OnTriggerEnter 函数,它使用协程每秒删除一次生命值。我想用 OnTriggerExit 函数和 StopCoroutine 来停止它。虽然这只适用于一个游戏对象,但它会因多个碰撞器而中断,因为它总是取消“例程”。为离开 Collider 的对象停止协程的最佳方法是什么?我觉得有一个简单的解决方案,但我只是没有看到它。

OnTriggerEnter/Exit

    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);
}

【问题讨论】:

  • 您可以将协程存储在进入/退出触发器的“其他”对象中。或者您可以将协程保存在字典中,通过其他游戏对象查找。

标签: c# unity3d crontrigger


【解决方案1】:

使用 Dictionary&lt;Collider, Coroutine&gt; 来存储和检索给定对撞机对象的例程:

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); 
    }
}

另见

【讨论】:

    猜你喜欢
    • 2021-11-15
    • 1970-01-01
    • 2014-10-01
    • 2014-07-09
    • 2019-01-05
    • 1970-01-01
    • 2020-08-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多