协程协同处理

时间:2018-09-29 17:41:45

标签: c# unity3d

我已经用4 GameObjects (Rockgroup_x)制作了4个动画,我想在2秒后随机开始一个动画,然后在2秒后随机开始下一个随机动画,等等。所有动画都经过测试并可以工作。首先,我将所有这些GameObjects设置为非活动状态,这样一开始您就不会看到它们,当我需要它们时,我将它们在功能Rocksplants()中设置为活动状态并等待2秒钟,然后重新开始。但是coroutine无法正常工作。我只看到游戏在循环播放RockGroup_2 GameObject的动画。我在做什么错?如何使coroutine正常工作? 有人可以帮我吗。

错误消息:

  

NullReferenceException:对象引用未设置为对象的实例   RocksPlants + c__Iterator0.MoveNext()(在Assets / ChosenAssets / Scripts / RocksPlants.cs:25)

(第25行:GameObject Rockgroup_02;)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RocksPlants : MonoBehaviour {
    IEnumerator Rocksplants(){

        GameObject Rockgroup_01;
        GameObject Rockgroup_02;
        GameObject Rockgroup_03;
        GameObject Rockgroup_04;

        Rockgroup_01 = GameObject.Find("RockGroup_1");
        Rockgroup_02 = GameObject.Find("RockGroup_2");
        Rockgroup_03 = GameObject.Find("RockGroup_3");
        Rockgroup_04 = GameObject.Find("RockGroup_4");

        Rockgroup_01.SetActive(false);
        Rockgroup_02.SetActive(false); //line 25
        Rockgroup_03.SetActive(false);
        Rockgroup_04.SetActive(false);

        int rndrockgroupright = Random.Range (1, 5);

        if (rndrockgroupright == 1) {
            Rockgroup_01.SetActive (true);
            yield return new WaitForSeconds (2);
        } else if (rndrockgroupright == 2) {
            Rockgroup_02.SetActive (true);
            yield return new WaitForSeconds (2);
        } else if (rndrockgroupright == 3) {
            Rockgroup_03.SetActive (true);
            yield return new WaitForSeconds (2);
        } else if (rndrockgroupright == 4) {  
            Rockgroup_04.SetActive (true);
            yield return new WaitForSeconds (2);
        }   
    }

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        StartCoroutine (Rocksplants());
    }
}

3 个答案:

答案 0 :(得分:1)

我认为游戏对象的分配不应该在协程方法中完成。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RocksPlants : MonoBehaviour {

        GameObject Rockgroup_01;
        GameObject Rockgroup_02;
        GameObject Rockgroup_03;
        GameObject Rockgroup_04;

    IEnumerator Rocksplants(){





        Rockgroup_01.SetActive(false);
        Rockgroup_02.SetActive(false); //line 25
        Rockgroup_03.SetActive(false);
        Rockgroup_04.SetActive(false);

        int rndrockgroupright = Random.Range (1, 5);

        if (rndrockgroupright == 1) {
            Rockgroup_01.SetActive (true);
            yield return new WaitForSeconds (2);
        } else if (rndrockgroupright == 2) {
            Rockgroup_02.SetActive (true);
            yield return new WaitForSeconds (2);
        } else if (rndrockgroupright == 3) {
            Rockgroup_03.SetActive (true);
            yield return new WaitForSeconds (2);
        } else if (rndrockgroupright == 4) {  
            Rockgroup_04.SetActive (true);
            yield return new WaitForSeconds (2);
        }   
    }

    // Use this for initialization
    void Start () {
        Rockgroup_01 = GameObject.Find("RockGroup_1");
        Rockgroup_02 = GameObject.Find("RockGroup_2");
        Rockgroup_03 = GameObject.Find("RockGroup_3");
        Rockgroup_04 = GameObject.Find("RockGroup_4");
    }

    // Update is called once per frame
    void Update () {
        StartCoroutine (Rocksplants());
    }
}

答案 1 :(得分:1)

我读到在更新函数中启动协程会引起问题,因为它将在每一帧中启动协程,等待2秒,因此我使用了MonoBehaviour.InvokeRepeating函数来达到我的目标,并且它有效:-> !。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RocksPlants : MonoBehaviour {

    GameObject Rockgroup_01;
    GameObject Rockgroup_02;
    GameObject Rockgroup_03;
    GameObject Rockgroup_04;


    // Use this for initialization
    void Start () {

        Rockgroup_01 = GameObject.Find("RockGroup_1");
        Rockgroup_02 = GameObject.Find("RockGroup_2");
        Rockgroup_03 = GameObject.Find("RockGroup_3");
        Rockgroup_04 = GameObject.Find("RockGroup_4");

        InvokeRepeating ("Rocksplants", 0.5f, 2.0f);

    }

    void Rocksplants() {

        Rockgroup_01.SetActive(false);
        Rockgroup_02.SetActive(false);
        Rockgroup_03.SetActive(false);
        Rockgroup_04.SetActive(false);


        int rndrockgroupright = Random.Range (1, 5);

        if        (rndrockgroupright == 1) {
            Rockgroup_01.SetActive (true);

        } else if (rndrockgroupright == 2) {
            Rockgroup_02.SetActive (true);

        } else if (rndrockgroupright == 3) {
            Rockgroup_03.SetActive (true);

        } else if (rndrockgroupright == 4) {  
            Rockgroup_04.SetActive (true);

        }   
    }

答案 2 :(得分:0)

每帧在Update函数中调用您的协程。您可能想要缓存Coroutine Rocksplant并进行更新检查,例如thag例程是否为null,因此当其无效时,您可以再次调用该例程。这是yoi缓存它的方式。

例如

private Coroutine MyRocksplantRoutine = null;

将其设为全局。 现在,在更新功能上,您可以执行此操作

Void Update()
{
    If(MyRocksplantRoutine == null)
    {
        MyRocksplantRoutine = StartCoroutine(Rocksplant());
    }
}

这样,您可以将其保留在更新功能中,而无需对其进行重复调用。之后,像这样,在Rocksplant Coroutine的末尾将变量MyRocksplantRoutine设置为空。

void IEnumerator Rocksplant()
{
    //your code
    yield return new WaitForEndOfFrame();
    MyRocksplantRoutine = null;
}