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