动态协同程序名称

时间:2017-12-07 11:35:08

标签: c# unity3d coroutine

如何让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));
}

2 个答案:

答案 0 :(得分:1)

所以最简单的方法就是在协议本身上移动协同程序。

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可以将对象保持到帧结束,这样就可以了。

但是这是后来失败的厄运。有一个控制器做任何事情都有点反对编程概念。您应该将其视为信息旁路。

答案 1 :(得分:0)

您可以在销毁之前检查null,这样您就不会收到任何错误:

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