【问题标题】:Start coroutine on an inactive/de-activated GameObject在非活动/停用的游戏对象上启动协程
【发布时间】:2018-10-25 23:35:48
【问题描述】:

我有以下代码:

void Start()
{
    gameObject.SetActive(false);
    StartCoroutine(Load());
}

IEnumerator Load()
{
    yield return new WaitForSeconds(waitTime);
    gameObject.SetActive(true);
}

这给了我一个错误,上面写着:

无法启动协程,因为游戏对象“NameOfObj” 处于非活动状态!

这是有道理的,因为游戏对象已设置为在运行脚本之前停用。即便如此,那我该怎么办?我尝试在WaitForSeconds() 之前将gameObject.SetActive(false) 移动到协程。这样做完全停止了游戏对象的加载。

据我了解,当执行gameObject.SetActive(false) 行时,脚本会停止运行,直到重新激活游戏对象。但是,如果是这种情况,是否不可能重新激活游戏对象(因为脚本已禁用)?

无论如何,我如何将我的游戏对象从加载延迟到游戏开始后的 2-3(或任意时间长度)?

【问题讨论】:

  • 将脚本移动到不同的游戏对象并引用您要激活的对象?
  • 哪个函数? Load()?
  • 它是一样的,只是附加到一个不同的空游戏对象上。然后,您要停用的游戏对象与脚本分开,因此脚本将继续运行。
  • 我有很多游戏对象(都是一样的);这是否意味着在这个游戏对象中引用所有这些对象,或者为我想要延迟的每个对象创建一个单独的游戏对象?

标签: c# unity3d


【解决方案1】:

您不能从取消激活游戏对象的脚本启动协程函数。

StartCoroutine 函数是MonoBehaviour 类下的函数。当您必须在已停用的 GameObject 上启动协程时,您需要对具有活动 GameObject 的 MonoBehaviour 对象的引用。

两种方法

1。使用不太可能被停用的现有游戏对象。就我而言,我通常使用相机。我访问相机的MonoBehaviour,因为它可能已被激活,然后使用它来启动协程功能。

我建议你使用这种方法。

Start 函数中的代码替换为以下代码:

//De-activate this GameObject
gameObject.SetActive(false);
//Get camera's MonoBehaviour
MonoBehaviour camMono = Camera.main.GetComponent<MonoBehaviour>();
//Use it to start your coroutine function
camMono.StartCoroutine(Load());

2。将脚本附加到一个空的 GameObject 上,空 GameObject 上的脚本将控制或能够激活/停用另一个 GameObject。

您希望在停用的游戏对象上运行的具有协程功能的脚本(将其附加到您希望停用的游戏对象):

public class YourDeactivatableScript: MonoBehaviour
{
    public IEnumerator Load()
    {
        yield return new WaitForSeconds(waitTime);
        gameObject.SetActive(true);
    }
}

现在,假设您要停用一个名为 "Cube" 的游戏对象,该游戏对象附加了 YourDeactivatableScript 脚本,但仍能够启动其 Load 协程函数,创建一个使用新脚本清空 GameObject,然后从中启动 Load 函数。

创建一个空的游戏对象,然后将此脚本附加到它:

public class LoadFuncCallerScript: MonoBehaviour
{
    GameObject targetObject;

    public void Start()
    {
         //Find the GameObject you want to de-activate
        targetObject = GameObject.Find("Cube");
        //De-activate it
        targetObject.SetActive(false);
        //Get it's component/script
        YourDeactivatableScript script = targetObject.GetComponent<YourDeactivatableScript>();
        //Start coroutine on the other script with this MonoBehaviour
        StartCoroutine(script.Load());
    }
}

协程现在从另一个名为 LoadFuncCallerScript 的脚本启动。

【讨论】:

  • 假设我有多个这样的游戏对象,从技术上讲,我可以通过相机控制所有这些对象(使用不同的功能)对吧?
  • 是的,相机的 MonoBehaviour 应该可以随心所欲地控制或启动许多协程。如果您停用相机,您将杀死它启动的所有协程。
  • 是的,但我并没有这样做。我在附加到相机的脚本中调用了一个函数,该脚本引用了类似于建议 2 的游戏对象。尽管如此,我会接受这个答案,因为它确实解决了我的问题
  • 你不需要附加任何东西来做相机。您可以像我一样使用主摄像头并使用它的 MonoBehaviour 来启动和停止协程,但使用适合您的任何方法。
【解决方案2】:

为了避免停止协程,我要做的是让游戏对象不会被停用。

public class CoroutineHandler : MonoBehaviour
{
    private static CoroutineHandler instance = null;
    public static CoroutineHandler Instance
    {
        get
        {
            if(instance == null)
            {
                GameObject inst = new GameObject("CoroutineHandler");
                DontDestroyOnLoad(inst);
                instance = inst.AddComponent<CoroutineHandler>();
            }
            return instance;
        }
    }
}

然后通过 CoroutineHandler.Instance.StartCoroutine(RoutineMethodHere()); 将其用于此类协程。

如果您不想要这样的东西,因为如果处理不当可能会出错或导致泄漏,您可以尝试使用Invoke("MethodName", delay);

【讨论】:

  • Invoke 在我的情况下不起作用,因为我需要延迟 OnMouseOver()
  • 那么你可以使用拥有一个单独的游戏对象/单声道的概念来处理协程。只要您在协程被破坏或卸载时停止协程,就可以了
  • 这对我很有效。我在一个预制件中有一个协程,它总是触发那个错误,这对我有用。
猜你喜欢
  • 2017-12-21
  • 2017-11-14
  • 2022-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多