我正在尝试创建一个倒数计时器,以便玩家在游戏重新开始之前购买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--;
}
}
}
答案 0 :(得分:3)
由于您将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();
}
如果您的用户界面具有使用Time.deltaTime
进行动画处理的某种动画,那么您需要将其更改为使用Time.unscaledDeltaTime
进行动画处理。这与WaitForSeconds
和WaitForSecondsRealtime
的想法相同,一个受Time.timeScale
值影响,而另一个则不受。
PS:我完全删除了Update
函数,因为如果按照我的方式实现,则不需要它。而且您无需在任何地方致电StopCoroutine
,因为倒数结束时倒计时会自动停止