【问题标题】:SetActive(true) not working inside a coroutineSetActive(true) 在协程中不起作用
【发布时间】:2019-12-27 15:36:10
【问题描述】:

我正在使用协程来管理我游戏中通电的冷却时间。当玩家与加速道具发生碰撞时,他们将获得效果并开始冷却,因此他们在一定时间内无法再次使用它。

我正在使用协程来管理这些冷却时间 - 将 gameObject 设置为 false,等待冷却时间,然后将 gameObject 设置回 true。

我的代码:

IEnumerator RespawnTime ()
{
    gameObject.SetActive(false);
    Debug.Log("disabled");

    yield return new WaitForSeconds(3f);

    gameObject.SetActive(true);
    Debug.Log("enabled");
}

private void OnCollisionEnter2D (Collision2D collision)
{
    // Health stuff goes in here.
    Debug.Log("Health regen!");

    // Start cooldown
    StartCoroutine(RespawnTime());
}

然而,游戏对象一旦被禁用就再也不会被激活。我认为问题不在于产量,因为注释掉 SetActive 语句会导致两个调试消息都在正确的时间显示。

编辑:

对不起,我没有澄清。我知道协程不能在禁用的GameObjects 上运行。我制作了一个PowerUpManager 脚本,但它不起作用。代码:

PowerUp 脚本中,在OnCollisionEnter2D 方法中

StartCoroutines(PowerUpManager.RespawnTime(gameObject))

PowerUpManager 脚本中

public static IEnumerator RespawnTime(GameObject powerUp)
{
    powerUp.SetActive(false);

    yield return new WaitForSeconds(3f);

    powerUp.SetActive(true);
}

【问题讨论】:

  • coroutines 禁用对象也被禁用。你必须在其他游戏对象中运行这个协程。

标签: unity3d coroutine


【解决方案1】:

你打电话的那一刻

gameObject.SetActive(false);

此对象不再接收Update 消息,因此也不会进一步执行Coroutine

当 MonoBehaviour 被销毁或 当它附加到的 GameObject 被禁用时,协程也会停止。


您的第二次尝试不起作用的原因是:您仍然在同一个 GameObject 上调用 StartCoroutine,因此 PowerUpManager 类的协程现在在您的 GameObject 上执行 => 效果一样。

如果您真的想使用PowerUpManager,您需要一个单例实例并在该实例上调用StartCoroutine,例如

PowerUpManager

public static PowerUpManager Instance;

private void Awake()
{
    Instance = this;
}

然后你可以从你的脚本调用

PowerUpManager.Instance.StartCoroutine(PowerUpManager.RespawnTime(gameObject));

在您的简单情况下,不需要平滑移动等,但只需要一个简单的延迟,我建议您使用 Invoke 来满足您想要的延迟。这也将在禁用或不活动的GameObject 上执行。

private void EnableAfterCooldown()
{
    gameObject.SetActive(true);
    Debug.Log("enabled");
}

private void OnCollisionEnter2D (Collision2D collision)
{
    // Health stuff goes in here.
    Debug.Log("Health regen!");

    gameObject.SetActive(false);
    Invoke("EnableAfterCooldown", 3f);
}

【讨论】:

  • 太棒了!调用方法完美运行。非常感谢:)。
  • 另见关于静态协程的更新;)
  • 是的,我看到了。 Stackoverflow 很棒:D。谢谢你的帮助。
【解决方案2】:

如果您停用游戏对象,它的所有组件也会被禁用,因此协程停止被调用。

您可以做的是将用于冷却的协程和检查碰撞的脚本分开,放在 2 个单独的脚本中。

让我们调用Cooldown.csPowerup.cs。 然后,让它们相互交叉引用。 在 powerup.cs 你有

private void OnCollisionEnter2D (Collision2D collision)
{
    // Health stuff goes in here.
    Debug.Log("Health regen!");
    // Start cooldown
    Cooldown cd = gameObject.GetComponent<cooldown>();
    cd.CooldownCoroutine();
}

在 Cooldown.cs 中:

IEnumerator RespawnTime ()
{
     Powerup pu = gameObject.GetComponent<Powerup>()
     pu.SetActive(false);
     Debug.Log("disabled");
     yield return new WaitForSeconds(3f);
     pu.SetActive(true);
     Debug.Log("enabled");
}

public void CooldownCoroutine()
{
    // Health stuff goes in here.
    Debug.Log("Health regen!");
    // Start cooldown
    StartCoroutine(RespawnTime());
}

这样您不会禁用整个对象,而只会禁用检查碰撞的脚本。

【讨论】:

  • 啊,这就是你正确的做法!我现在正在使用调用,但感谢您澄清为什么我对 2 个游戏对象的尝试不起作用。祝你有个好的一天! :)
  • +1 一般来说,这确实是一个不错的选择如果您不想禁用整个GameObject。然而,在某些情况下可能会产生更多开销,例如,如果您需要禁用 MeshRendererColliderGameObject 上的 所有 其他组件 .. 因为 OP 的用例是永久重生的收藏品项目
【解决方案3】:

协程不会在禁用的游戏对象上运行!

你应该在另一个游戏对象上运行它。

【讨论】:

  • 对不起,我没有说明我试过这个 - 我的错。我已经更新了我的问题。
  • @Wzrd 我不认为你被允许拥有静态协程。您应该将 PowerUpManager 的一个实例传递给您想要从中运行它的脚本。或者让它成为一个单例。
  • 感谢 derHugo,我已经解决了这个问题,但我会仔细检查并牢记未来。谢谢,祝你有美好的一天。 :)。
猜你喜欢
  • 1970-01-01
  • 2014-08-14
  • 2019-05-27
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 2016-04-23
  • 2016-05-22
  • 2020-09-04
相关资源
最近更新 更多