【问题标题】:My Countdown Timer is Stuck and Game doesn't stop我的倒数计时器卡住了,游戏没有停止
【发布时间】:2018-08-03 19:40:59
【问题描述】:

我正在尝试创建一个倒计时计时器,用于当我的玩家在游戏再次开始前 3 秒购买第二条生命时。我不确定我需要在下面修复什么才能使其正常工作。目前,所有的 UI 都会在应有的时候弹出,倒数计时器文本也确实会弹出,但游戏继续进行,并且计时器停留在 3。

public static bool GameOver = false;
public static bool CountDown = false;

public GameObject deathMenuUI;
public GameObject countDownUI;

public int timeLeft = 3;
public Text countDownText;

public float slowness = 10f;

public void Start()
{
    PlayerPrefs.SetInt("Score", 0);
    Time.timeScale = 1f;
}

public void EndGame()
{
    StartCoroutine(DeathScreen());
}
//on death, slow time for one second and open deathscreen UI
IEnumerator DeathScreen()
{
    Time.timeScale = 1f / slowness;
    Time.fixedDeltaTime = Time.fixedDeltaTime / slowness;

    yield return new WaitForSeconds(1f / slowness);

    Time.timeScale = 1f;
    Time.fixedDeltaTime = Time.fixedDeltaTime * slowness;

    deathMenuUI.SetActive(true);
    Time.timeScale = 0f;
    GameOver = true;
}
//if game is continued, close deathUI and start timer
public void continueGame()
{
    deathMenuUI.SetActive(false);
    Time.timeScale = 1f;
    GameOver = false;
    StartCoroutine(LoseTime());
}
private void Update()
{
    countDownText.text = ("" + timeLeft);
    if (timeLeft <= 0)
    {
        StopCoroutine(LoseTime());
    }
}
IEnumerator LoseTime()
{
    while (true)
    {
        countDownUI.SetActive(true);
        CountDown = true;
        yield return new WaitForSeconds(1);
        timeLeft--;
    }
}

}

【问题讨论】:

  • 你的Deathscreen只等待100ms然后GameOver...这是故意的吗?
  • 实际上是 1 秒。它会在死亡时产生子弹时间效果,从而减慢时间:)
  • 试着把 Debug.Log 放到你的 IEnumerator LoseTime() 里面看看协程是否真的被触发了
  • 而且我没有看到您在代码中的任何位置重置 timeLeft 变量,您应该在 continueGame() 函数中执行此操作,以便在您第一次调用 continueGame() 后您的倒计时获胜'不要像你想要的那样从小于或等于 0 而不是 3 的数字开始
  • 如果你想同时使用waitForSeconds和TimeScale 0,你应该使用“yield return new WaitForSecondsRealtime(time);”。 WaitForSecondsRealtime 不依赖于 timeScale,它依赖于计算机的时钟。

标签: c# unity3d


【解决方案1】:

既然你设置了Time.timeScale = 0 来暂停你的游戏,那么你需要使用WaitForSecondsRealtime 而不是WaitForSeconds(就像@Prodian 在评论部分建议的那样)因为WaitForSecondsRealtime 使用未缩放的时间,无论什么值都不会受到影响您将Time.timeScale 设置为。

我在这里对您的代码进行了一些修改:

//if game is continued, close deathUI and start timer
public void continueGame()
{
    // Add this line to prevent accident like double click... which will start multiple coroutine and cause unexpected result
    if (CountDown) return;
    CountDown = true;
    deathMenuUI.SetActive(false);
    // Since you want your game to still being paused for 3 seconds before resuming
    Time.timeScale = 0;
    StartCoroutine(LoseTime());
}

private void AfterCountdownFinished()
{
    // important. You must set your Time.timeScale back to its default value
    // because even if you reload your scene the timeScale remain the same which can cause you to encounter freeze error which you might spend time to search for the problem

    Time.timeScale = 1;
    GameOver = CountDown = false;
    countDownUI.SetActive(false);
    // You want to write your restart/continue logic here
    // Example:
    // reload the level
    // SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}

IEnumerator LoseTime()
{
    // I forgot this part (which you pointed out)
    countDownUI.SetActive(true);
    // Here is how you can improve performance

    // It seems you can't create and reuse it like WaitForSeconds
    // var delay = new WaitForSecondsRealtime(1);
    // Set this the text here so it will display (3 in your case) for 1 second before start decreasing
    countDownText.text = timeLeft.ToString();

    // If your level will restart after the countdown ends then you don't need to create another variable like below. You can just use timeLeft directly
    int time = timeLeft;
    while (time > 0)
    {
        // Edited here
        yield return new WaitForSecondsRealtime(1);
        time--;
        // Here you don't set your UI text every frame in the update but you only set it only when there is change on timeLeft
        countDownText.text = time.ToString();
    }
    // When countdown ended. You don't need to call StopCoroutine
    AfterCountdownFinished();
}

如果您的 UI 有某种使用 Time.deltaTime 进行动画处理的动画,那么您需要将其更改为使用 Time.unscaledDeltaTime。与WaitForSecondsWaitForSecondsRealtime 的思路相同,一个受Time.timeScale 值影响,另一个不受。

PS:我完全删除了你的Update 函数,因为如果你按照我的方式实现你就不需要它了。而且您无需在任何地方致电StopCoroutine,因为倒计时结束时会自动停止

【讨论】:

  • 非常感谢您!我刚刚对其进行了测试,我刚刚添加了 countDownUI.SetActive(true);在 LoseTime 开始时调出 UI。它可以工作,但是倒计时非常快,不是实时的 3 秒。它在大约 1 秒内倒计时到 0 :(
  • 哦,我明白了。看来我无法像WaitForSeconds那样创建延迟并重用它,我将编辑答案
  • @BrendonSon 我在答案中编辑了代码。这应该可以解决问题
  • 成功了!非常感谢:D 你不知道有多少倒数计时器教程和咖啡杯来尝试解决这个问题!你是救生员。感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 2017-07-28
相关资源
最近更新 更多