动态协程名称

Dynamic Coroutine name

如何让Coroutine的名字动态化? 我用这个让目标在几秒钟后自动死亡:

void InitiateKill(int i)
{
   //i is the number of the target
   StartCoroutine(TargetDie(i, timeAlive/1000));
   //some other stuff
}

当目标在这个计时器结束之前被杀死时,我显然得到一个错误,因为它不能再次杀死目标。

这就是为什么我想停止那个特定目标的协程,但我不知道如何。

我试过了:

Coroutine b[i] = StartCoroutine(TargetDie(i, timeAlive/1000));

但这给出了语法错误。 b[i] 不能用于协程。

如何以正确的方式做到这一点?

更新:

这是我的 TargetDie 函数的(相关部分):

IEnumerator TargetDie(int i, float delayTime)
{
    yield return new WaitForSeconds(delayTime);
    Destroy(targets[i]);
}

当玩家杀死目标时,我做:

void Damage(int i)
{
   // at this time, the first Coroutine, started in InitiateKill, should stop, because otherwise it tries to destroy the target twice
   StartCoroutine(TargetDie(i, 0));
}

最简单的方法,将协程移动到对象本身。

public class DieScript: MonoBehaviour
{
    private Manager manager;
    public void StartDeathProcess(Manager manager)
    {
        this.manager = manager;
        StartCoroutine(DieAsync(manager));
    }
    private IEnumerator DieAsync(Manager manager)
    {
        yield return new WaitForSeconds(timer);
        Destroy(this.gameObject);
    }
    public void Dmaage() // This is register as listener for death of the object
    {
         this.manager.PropagateDeath(this);
         Destroy(this.gameObject);
    }
}

public class Manager:MonoBehaviour
{
    private List<DieScript> die;
    void InitiateKill(int i)  
    {
        die[i].StartDeathProcess(this);
    }
}

试图将控制权保留在控制器上将带来更多的痛苦而不是解决方案。

您可以有一个 IEnumerator 列表来跟踪 运行 协程。但是您仍然需要来自对象的消息来通知控制器它已经死了。所以你错过了这部分。 您需要目标上的脚本,以便控制器了解此类型。 控制器运行协程并引用该脚本询问每一帧你是否正在死去。当目标要死时,它会设置一个布尔值来通知。使用 Destroy 将对象保留到帧结束,这样它就可以解决了。

但这注定要失败。让控制器做所有事情有点违反编程概念。您应该更多地将其视为信息的旁路。

您可以在销毁它之前简单地检查它是否为空,这样您就不会得到任何错误:

if (targets != null)
    Destroy(targets[i]);

但是如果你想要停止旧协程,下面是推荐的方法。


可以用Dictionary来处理。使用 int i 作为键,使用 Coroutine 作为值。

当你调用 InitiateKill 时,将 int i 添加到字典中,当你启动协程时,也将 Coroutine 作为值添加到字典中。

调用Damage时,检查Dictionary中是否存在该int值。如果是,则使用它来检索 Coroutine 值并停止旧协程。如果它没有退出,则启动一个新的协程,然后将其添加到该字典中。

字典应如下所示:

Dictionary<int, Coroutine> dyingTarget = new Dictionary<int, Coroutine>();

您的新 InitiateKill 函数添加到 Dictionary:

void InitiateKill(int i)
{
    //i is the number of the target
    Coroutine crt = StartCoroutine(TargetDie(i, timeAlive / 1000));

    //Add to Dictionary
    dyingTarget.Add(i, crt);
}

您的新 Damage 函数现在检查该项目是否已在字典中,然后重试,停止协程并将其从 Dictionary 中删除。

void Damage(int i)
{
    // at this time, the first Coroutine, started in InitiateKill, should stop, because otherwise it tries to destroy the target twice
    StopIfAlreadyRunning(i);

    Coroutine crt = StartCoroutine(TargetDie(i, 0));
    //Add to Dictionary
    dyingTarget.Add(i, crt);
}

void StopIfAlreadyRunning(int i)
{
    Coroutine crtOut;
    //Retrieve and stop old coroutine if it exist then removes it
    if (dyingTarget.TryGetValue(i, out crtOut))
    {
        StopCoroutine(crtOut);
        dyingTarget.Remove(i);
    }
}

新的 TargetDie 函数在杀死它后将其从 Dictionary 中删除。它还会在销毁它之前检查 null

IEnumerator TargetDie(int i, float delayTime)
{
    yield return new WaitForSeconds(delayTime);
    if (targets != null)
        Destroy(targets[i]);
    //Remove from Dictionary 
    dyingTarget.Remove(i);
}