我是新来的。是否可以保存协同线的当前状态并加载它,然后继续协同线?我的项目中有几个合作项目,我想把它全部保存下来。
发布于 2021-05-12 01:34:09
当你定义一个协同线时,例如;
using System.Collections;
public class C {
private void before() { }
private void after() { }
public IEnumerator MyCoroutine()
{
before();
yield return null;
after();
}
}
编译器定义一个新类型来跟踪方法的状态,包括任何局部变量。您可以通过使用反编译器看到这一点。
虽然它更多工作,也更复杂,但是您可以实现自己的IEnumerable
类型。
public class MyCoroutine : IEnumerator
{
private int state = 0;
public object Current { get; private set; }
private void before() { }
private void after() { }
public bool MoveNext()
{
switch (state)
{
case 0:
before();
state++;
Current = null;
return true;
case 1:
after();
state++;
break;
}
return false;
}
public void Reset() => throw new System.NotImplementedException();
}
然后,这取决于您希望如何保存/加载和恢复您的协作。
发布于 2021-05-11 06:53:03
团结没有任何东西支持这一点。那么,让我们来看看拯救一条协同线所需要的东西。
开始的&不完全的协同线有局部变量,这是它们目前所处的产量指令。它们目前的产量可能会实例化匿名YieldInstruction
。
所以,如果你想要保存一个协同线,你需要保存这些东西。所以,你需要拯救一群当地人,并回答如何在正确的指令下恢复菜谱的问题。这是一项复杂的任务,如果不进行大量的努力和重构,结果可能会非常混乱。
因此,我建议您接受这样一个事实:您需要进行一些重构。与其保持协同线不变,这里更简单的路径是将协同线“展开”到各种更新方法中:
Update
,使用yield return null
,WaitForSeconds
,WaitUntil
,WaitForSecondsRealtime
FixedUpdate
,如果使用不常用的WaitForFixedUpdate
LateUpdate
,当使用WaitForEndOfFrame
时并将协同线的局部变量移动到字段中,以及跟踪时间通道所需的任何额外的必要字段,而不是WaitForSeconds
之类的。并使这些字段能够正确地序列化。
由于问题中没有给出具体的例子,我将提供一个前后示例,这可能有助于:
使用Coroutine (状态不可序列化):
void Update()
{
DoStuff();
}
void StartMoveTowards(Transform target, Vector3 destination, float duration)
{
StartCoroutine(DoMoveTowards(target, destination, duration));
}
IEnumerator DoMoveTowards(Transform target, Vector3 destination, float duration)
{
float v = Vector3.Distance(target.position, destination) / duration;
while( target.position != destination)
{
yield return null;
target.position = Vector3.MoveTowards(target.position, destination, v * Time.deltaTime);
}
DoFirstThing();
yield return new WaitForSeconds(3f);
DoSecondThing();
}
不使用coroutine (可序列化状态):
enum MoveTowardsState
{
NotRunning,
Starting,
MovingTowards,
DoingFirstThing,
Waiting
}
// serializable coroutine locals, timers, and instruction state
[SerializeField] MoveTowardsState currentMoveTowardsState;
[SerializeReference]
[SerializeField] Transform moveTowardsTarget;
[SerializeField] Vector3 moveTowardsDestination;
[SerializeField] float moveTowardsDuration;
[SerializeField] float waitT;
[SerializeField] float v;
void Update()
{
DoStuff();
HandleDoMoveTowards();
}
void StartMoveTowards(Transform target, Vector3 destination, float duration)
{
moveTowardsTarget = target;
moveTowardsDestination = destination;
moveTowardsDuration = duration;
currentMoveTowardsState = MoveTowardsState.Starting;
}
void HandleDoMoveTowards()
{
bool continuing = true;
while(continuing)
{
continuing = false;
switch (currentMoveTowardsState)
{
case MoveTowardsState.NotRunning:
break;
case MoveTowardsState.Starting:
v = Vector3.Distance(target.position, destination) / duration;
if (target.position != destination)
{
currentMoveTowardsState = MoveTowardsState.MovingTowards;
}
else
{
currentMoveTowardsState = MoveTowardsState.DoingFirstThing;
continuing = true;
}
break;
case MoveTowardsState.MovingTowards:
target.position = Vector3.MoveTowards(moveTowardsTarget.position,
moveTowardsDestination, v * Time.deltaTime);
if (target.position == destination)
{
currentMoveTowardsState = MoveTowardsState.DoingFirstThing;
continuing = true;
}
break;
case MoveTowardsState.DoingFirstThing:
DoFirstThing();
waitT = 3f;
currentMoveTowardsState = MoveTowardsState.Waiting;
break;
case MoveTowardsState.Waiting:
waitT -= Time.deltaTime;
if (waitT <= 0f)
{
DoSecondThing();
currentMoveTowardsState = MoveTowardsState.NotRunning;
}
break;
}
}
}
如果需要多个并行实例,您可以为coroutine创建一个新的单行为,并为每个运行实例创建一个实例。
注意:我现在不能检查语法,所以请注意任何语法错误。希望这个想法能被接受。如果有任何地方不合理,请在评论中告诉我。
https://stackoverflow.com/questions/67480960
复制相似问题