每次发生冲突时如何继续协程功能?

时间:2019-04-09 12:33:52

标签: unity3d

我正在游戏中使用Health Bar。当我的玩家被子弹击中时,其生命会减少1,而Im会启动一个协程,在该协程中,Im会打开/关闭运行状况条的可见性。 但是我想要的是,当玩家连续被子弹击中时,不应禁用健康栏。它应该打开。 到目前为止,我在这里所做的是:

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();
        }
    }
}

我想在子弹不断击中玩家时暂停协程功能,以便在整个时间段内都可以看到我的健康条,并且它只是显示生命的减少。

1 个答案:

答案 0 :(得分:0)

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

// 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();
        }
    }
}