【问题标题】:How can I continue coroutine function when every time collision occurs?每次发生碰撞时如何继续协程功能?
【发布时间】:2019-08-30 18:11:12
【问题描述】:

我正在制作游戏中的健康栏。当我的玩家被子弹击中时,它的生命减少了 1 并且我开始了一个协程,在该协程中我设置了健康栏的可见性打开/关闭。 但我想要的是当玩家不断被子弹击中时,健康栏不应该被禁用。它应该开启。 到目前为止,我所做的是:

IEnumerator EnableAndDisableHealthBar()
{
    isHealthBarVisible = true;
    showIsHealthBarVisible = true;

    fillAmt -= 0.05f;

    if (fillAmt >= 0.6f && fillAmt <= 1.0f)
    {
        HealthBarFiller.color = Color.green;
    }
    else if (fillAmt >= 0.3f && fillAmt < 0.6f)
    {
        HealthBarFiller.color = Color.yellow;
    }
    else if (fillAmt < 0.3f)
    {
        HealthBarFiller.color = Color.red;
    }

    yield return new WaitForSeconds(healthBarVisibilityTime);

    showIsHealthBarVisible = false;
    isHealthBarVisible = false;
}

public void OnTriggerEnter(Collider obj)
{
    if (obj.tag == "EnemyBullets")
    {
        Debug.Log("Player Plane hit by Enemy Bullet");

        planeCurrentLife--;

        if (planeCurrentLife >= 1 && planeCurrentLife < 20)
        {
            StartCoroutine(EnableAndDisableHealthBar());
        }
        else if (planeCurrentLife <= 0)
        {
            Destroy(obj.gameObject);
            StartCoroutine(EnableAndDisableHealthBar());
            Explode();
        }
    }
}

我想在子弹连续击中玩家时暂停我的协程功能,以便我的生命条在整个时间段内都可见,它只是显示减少的生命。

【问题讨论】:

  • 所以改变协程,这样栏就不会走,除非在 x 时间内没有点击。
  • 嘿@BugFinder 这意味着我应该用正常功能替换协程吗?
  • 不是真的,你想从最后一次命中 + 延迟一段时间 > 现在,等等,再试一次.. 所以,你会想要一个协程,这样你就不会挂起统一
  • @BugFinder 对不起,我没听懂你能不能用代码和一点解释再次解释一下
  • 创建一个包含子弹击中时间的变量,如果健康栏不可见,则启动协程以关闭您希望它显示的任何延迟......在协程中,就在时间子弹击中+延迟>现在,产生返回null,然后隐藏栏..因为子弹不断进入的时间少于延迟栏会保持的时间..并在最后一个延迟后消失

标签: unity3d


【解决方案1】:

我更新了您的代码,以便将 EnableAndDisableHealthBar() 函数存储为全局字段,然后在 OnTriggerEnter() 函数中再次调用它时停止(在它完成并禁用健康栏之前)。我在我添加的代码上方添加了 cmets。

// Store the Coroutine as a global field
Coroutine enableDisableHealthBarCoroutine;

IEnumerator EnableAndDisableHealthBar()
{
    isHealthBarVisible = true;
    showIsHealthBarVisible = true;

    fillAmt -= 0.05f;

    if (fillAmt >= 0.6f && fillAmt <= 1.0f)
    {
        HealthBarFiller.color = Color.green;
    }
    else if (fillAmt >= 0.3f && fillAmt < 0.6f)
    {
        HealthBarFiller.color = Color.yellow;
    }
    else if (fillAmt < 0.3f)
    {
        HealthBarFiller.color = Color.red;
    }
    yield return new WaitForSeconds(healthBarVisibilityTime);

    showIsHealthBarVisible = false;
    isHealthBarVisible = false;
}

public void OnTriggerEnter(Collider obj)
{
    if (obj.tag == "EnemyBullets")
    {
        Debug.Log("Player Plane hit by Enemy Bullet");

        planeCurrentLife--;

        // Check if there was a previous coroutine running
        if(enableDisableHealthBarCoroutine != null) 
        {
            // If there was, then stop it
            // (this will leave the health bar enabled)
            enableDisableHealthBarCoroutine.StopCoroutine();
        }

        if (planeCurrentLife >= 1 && planeCurrentLife < 20)
        {
            // Set the current coroutine to the new instance we're creating here
            // This will keep the health bar enabled for another "healthBarVisibilityTime" seconds
            enableDisableHealthBarCoroutine = StartCoroutine(EnableAndDisableHealthBar());
        }
        else if (planeCurrentLife <= 0)
        {
            Destroy(obj.gameObject);
            // Set the current coroutine to the new instance we're creating here
            // This will keep the health bar enabled for another "healthBarVisibilityTime" seconds
            enableDisableHealthBarCoroutine = StartCoroutine(EnableAndDisableHealthBar());
            Explode();
        }
    }
}

这是因为StartCoroutine() 函数返回一个Coroutine 对象,您可以使用StopCoroutine() 阻止它运行。还有其他方法可以停止协程,例如调用StopAllCoroutines(),但存储对协程的引用通常是管理协程并且不引入错误的最安全方法。有关协程的更多信息,请查看文档here

下面的代码与我在此过程中看到的其他代码相同。我想展示两个版本,但它们应该做同样的事情。

// Store the Coroutine as a global field
Coroutine enableDisableHealthBarCoroutine;

IEnumerator EnableAndDisableHealthBar() {
    // could combine isHealthBarVisible and showIsHealthBarVisible as seen here, but I don't know what else they're doing in your code
    isHealthBarVisible = true;
    showIsHealthBarVisible = true;    

    fillAmt -= 0.05f;

    if (fillAmt >= 0.6f) { // it shouldn't matter if fillAmt is > 1
        HealthBarFiller.color = Color.green;
    }
    else if (fillAmt >= 0.3f) { // guaranteed that fillAmt < .6 because of the previous if statement
        HealthBarFiller.color = Color.yellow;
    }
    else { // guaranteed that fillAmt < .3 because of the previous if statements
        HealthBarFiller.color = Color.red;
    }

    yield return new WaitForSeconds(healthBarVisibilityTime);

    showIsHealthBarVisible = false;
    isHealthBarVisible = false;
}

public void OnTriggerEnter(Collider obj)
{
    if (obj.tag == "EnemyBullets") {
        Debug.Log("Player Plane hit by Enemy Bullet");

        planeCurrentLife--;

        // Check if there was a previous coroutine running
        if(enableDisableHealthBarCoroutine != null) {
            // If there was, then stop it
            // (this will leave the health bar enabled)
            enableDisableHealthBarCoroutine.StopCoroutine();
        }

        // Set the current coroutine to the new instance we're creating here
        // This will keep the health bar enabled for another "healthBarVisibilityTime" seconds
        enableDisableHealthBarCoroutine = StartCoroutine(EnableAndDisableHealthBar());

        if (planeCurrentLife <= 0) {
            Destroy(obj.gameObject);
            Explode();
        }
    }
}

【讨论】:

  • 嘿@NicholasBucher 这真的非常感谢它真正帮助我解决我的问题的解决方案。谢谢。
  • 很高兴我能帮上忙! :)
猜你喜欢
  • 2019-06-30
  • 1970-01-01
  • 2015-09-12
  • 1970-01-01
  • 2019-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多