动态协程名称
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);
}
如何让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);
}