首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >保存和加载协同服务状态

保存和加载协同服务状态
EN

Stack Overflow用户
提问于 2021-05-11 05:21:50
回答 2查看 554关注 0票数 0

我是新来的。是否可以保存协同线的当前状态并加载它,然后继续协同线?我的项目中有几个合作项目,我想把它全部保存下来。

EN

回答 2

Stack Overflow用户

发布于 2021-05-12 01:34:09

当你定义一个协同线时,例如;

代码语言:javascript
运行
复制
using System.Collections;
public class C {
    private void before() { }
    private void after() { }
    public IEnumerator MyCoroutine()
    {
        before();
        yield return null;
        after();
    }
}

编译器定义一个新类型来跟踪方法的状态,包括任何局部变量。您可以通过使用反编译器看到这一点。

虽然它更多工作,也更复杂,但是您可以实现自己的IEnumerable类型。

代码语言:javascript
运行
复制
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();
}

然后,这取决于您希望如何保存/加载和恢复您的协作。

票数 1
EN

Stack Overflow用户

发布于 2021-05-11 06:53:03

团结没有任何东西支持这一点。那么,让我们来看看拯救一条协同线所需要的东西。

开始的&不完全的协同线有局部变量,这是它们目前所处的产量指令。它们目前的产量可能会实例化匿名YieldInstruction

所以,如果你想要保存一个协同线,你需要保存这些东西。所以,你需要拯救一群当地人,并回答如何在正确的指令下恢复菜谱的问题。这是一项复杂的任务,如果不进行大量的努力和重构,结果可能会非常混乱。

因此,我建议您接受这样一个事实:您需要进行一些重构。与其保持协同线不变,这里更简单的路径是将协同线“展开”到各种更新方法中:

  • Update,使用yield return nullWaitForSecondsWaitUntilWaitForSecondsRealtime
  • FixedUpdate,如果使用不常用的WaitForFixedUpdate
  • LateUpdate,当使用WaitForEndOfFrame

并将协同线的局部变量移动到字段中,以及跟踪时间通道所需的任何额外的必要字段,而不是WaitForSeconds之类的。并使这些字段能够正确地序列化。

由于问题中没有给出具体的例子,我将提供一个前后示例,这可能有助于:

使用Coroutine (状态不可序列化):

代码语言:javascript
运行
复制
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 (可序列化状态):

代码语言:javascript
运行
复制
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创建一个新的单行为,并为每个运行实例创建一个实例。

注意:我现在不能检查语法,所以请注意任何语法错误。希望这个想法能被接受。如果有任何地方不合理,请在评论中告诉我。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67480960

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档