多个协程的正确使用方法

问题描述 投票:0回答:2

我只是觉得有更好的方法。我有一个纹理需要调整大小,然后压缩。这两个函数都需要一些处理时间,因此我需要将每个函数放入一个协程中。我的方法是先调整大小,然后压缩,但事情似乎很快就会变得混乱。构造多个有序协程以逐个触发并将处理后的变量(在本例中为 Texture2D)从一个传递到下一个的推荐方法是什么?

[Client]
    public void PrepareServerData(Texture2D texToSend, string typeToSend)
    {
        StartCoroutine(DoGetTexToBytes(texToSend));

        playerObj.texWidth = texToSend.width;
        playerObj.texHeight = texToSend.height;
        playerObj.texFormat = texToSend.format;
        playerObj.tranX = tran.x;
        playerObj.tranY = tran.y;
        playerObj.tranZ = tran.z;
        playerObj.type = typeToSend;
        Player_ID id = GetComponent<Player_ID>();
        playerObj.id = id.MakeUniqueIdentity();
        playerObj.strength = strengthToSend;
        playerObj.hitpoints = hitPointsToSend;

        Network_Serializer serialize = GetComponent<Network_Serializer>();

        // Send Data from Client to Server as many small sequenced packets
        byte[] bytes = serialize.ObjectToByteArray(playerObj);

        StartCoroutine(Network_Transmitter.instance.DoSendBytes(0, bytes));
    }

    IEnumerator DoGetTexToBytes(Texture2D tex)
    {
        DoResizeTex(tex);

        byte[] texBytes = tex.GetRawTextureData();                      // convert texture to raw bytes
        byte[] compressedTexBytes = lzip.compressBuffer(texBytes, 9);   // compress texture byte array
        playerObj.texBytes = compressedTexBytes;                        // set compressed bytes to player object

        yield return new WaitForEndOfFrame();

        GameObject infoDisplayText = GameObject.Find("InfoDisplay");
        infoDisplayText.GetComponent<Text>().text += "Bytes to send : " + playerObj.texBytes.Length + "\n";
    }

    IEnumerator DoResizeTex(Texture2D tex)
    {
        tex.ResizePro(1280, 1024);
        tex.Apply();

        yield return new WaitForEndOfFrame();
    }
c# unity-game-engine coroutine
2个回答
4
投票

向您的协程添加回调过程。

private IEnumerator MyCoroutine(Action callback){
    yield return null;
    if (callback !=null){callback();}
}

用途:

void Start(){
    StartCoroutine(MyCoroutine(()=>
    { 
        StartCoroutine(OtherCoroutine());
    }
}

如果需要,您还可以使用 Action 从协程返回值。

 private IEnumerator MyCoroutine(Action<Texture2D> callback){
         yield return null; 
         Texture2D tex = GetTexture();
         if (callback !=null){callback(tex);}
  }

 void Start(){
        StartCoroutine(MyCoroutine((texParam)=>
       { 
            StartCoroutine(OtherCoroutine(texParam));
        }
  }

IEnumerator OtherCoroutine(Texture2D texture){
       yield return null;
       texture.DoSomething();
 }

编辑: 虽然回调可以很好地调用新的协程,但如果您有一系列协程,则可能会出现问题:

void Start(){
    StartCoroutine(MyCoroutine(()=>
    { 
        StartCoroutine(OtherCoroutine(()=>{
              StartCoroutine(ThirdCoroutine());
        }));
    }
}

在这种情况下,最好是分别产生它们。代码也变得更具可读性。

// Start can return void, IEnumerator or even Task for async
IEnumerator Start(){
    yield StartCoroutine(MyCoroutine();
    yield StartCoroutine(SecondCoroutine());
    yield StartCoroutine(ThirdCoroutine());
}

1
投票

如果您需要

DoResizeTex
DoGetTexToBytes
开始之前完成,那么您需要使用
DoGetTexToBytes
从内部
yield
调用它:

IEnumerator DoGetTexToBytes(Texture2D tex)
    {
        yield return StartCoroutine(DoResizeTex(tex));

        // Stuff done by DoGetTexToBytes after DoResizeTex has finished
    }

IEnumerator DoResizeTex(Texture2D tex)
    {
        tex.ResizePro(1280, 1024);
        tex.Apply();

        yield return new WaitForEndOfFrame();
    }

编辑:尚不清楚调整大小的纹理是否必须由

DoGetTexToBytes
使用,但我想是的。如果是这种情况,您需要使用数组通过引用传递纹理(修改上面的代码以添加纹理的引用传递)。基本上,您将使用仅包含一个元素的
Texture2D[]
,而
texToSend[0]
是旧的
texToSend

© www.soinside.com 2019 - 2024. All rights reserved.