Мне было интересно, почему мой таймер обратного отсчета, как я опишу - PullRequest
1 голос
/ 28 сентября 2019

Это только часть моего кода, и я надеюсь, что это будет достаточно легко понять.Я нашел способ «исправить» это, но я все еще не понимаю этого:

Я установил свой float countDownTime в 2f.В DisplayTime () я думал, что цикл do-while будет считать от 2 до 0, но вместо этого начинает обратный отсчет от 0 до отрицательных чисел.Я думал, что это будет обратный отсчет и остановка, когда countDownTime достигнет 0, как назначено в то время (countDownTime> = 0), но это будет продолжаться после этого.Спасибо за любые отзывы или помощь.

   // Update is called once per frame
void Update()
{
    if (Input.GetKeyDown(KeyCode.Space) && !hasStarted)
    {
        hasStarted = true;
        StartGame();            
    }

    DisplayTime();        
}

void DisplayTime()
{        
    if (timerStart)
    {
        do
        {
            countDownTime -= Time.deltaTime;
        } while (countDownTime >= 0);

        timer2.text = Math.Round(countDownTime, 2).ToString();
    }        

}

Я внес в нее изменения, и это мое исправление:

   // Update is called once per frame
void Update()
{
    if (Input.GetKeyDown(KeyCode.Space) && !hasStarted)
    {
        hasStarted = true;
        StartGame();            
    }

    DisplayTime();        
}

void DisplayTime()
{        
    if (timerStart && countDownTime >= 0)
    {
        do
        {
            countDownTime -= Time.deltaTime;
        } while (countDownTime >= 2);

        timer2.text = Math.Round(countDownTime, 2).ToString();
    }        

}

Ответы [ 2 ]

0 голосов
/ 28 сентября 2019

Необходимо учитывать 2 фактора.

  1. Update() Метод вызывается в каждом кадре.Вы выполняете цикл do-while в DisplayTime(), который вызывается из Update (), поэтому цикл do будет выполняться много раз (один раз на кадр).
  2. цикл do-while работает иначе, чем обычный цикл while.Цикл do-while сначала выполняет код внутри do {} и только после проверки условия и прерывает цикл, если условие ложно.поэтому (даже если условие ложно) код внутри do {} будет запускаться хотя бы один раз.В случае нормального времени, если условие ложно, код внутри цикла не будет выполняться.

Таким образом, в вашем случае на первый кадр подписывается countDownTime до тех пор, пока он не станет меньше 0. (Так на экраневы сразу видите 0 вместо 2, потому что после первого кадра его уже 0).после 1-го кадра в каждом кадре при выполнении do-while код внутри do выполняется только один раз, а затем цикл немедленно прерывается, поскольку условие countDownTime> = уже ложно.Таким образом, после 1-го кадра countDownTime -= Time.deltaTime; этот код выполняется один раз за кадр (без многократного повторения в do-while), поэтому впоследствии он работает «правильно».

0 голосов
/ 28 сентября 2019

Во-первых, я не вижу, где вы изначально устанавливаете countDownTime на 2.

Во-вторых, countDownTime скорее остановится на отрицательном числе, чем на нуле.Это связано с тем, что deltaTime является мерой количества мс, прошедших с момента последнего обновления, и сильно варьируется.Поэтому вы должны округлить его обратно до 0, если вы не хотите, чтобы его отображали как отрицательный.

Наконец, я думаю, что вы хотите выполнить этот код как сопрограмму, иначе весь цикл будет выполняться в одном кадре, что, скорее всего, не то, что вам нужно.

IEnumerator DisplayTime() {  
     countDownTime = 2;
     while (countDownTime > 0) {
         countDownTime -= Time.deltaTime;
         timer2.text = Math.Round(countDownTime, 2).ToString();
         yield return new WaitForEndOfFrame();
     }
}

void Start() {
    // start coroutine
    StartCoroutine(DisplayTime);
}

Если вы не хотели сопрограмму и хотели вызывать ее каждый кадр из вашего метода Update, вы можете просто отбросить цикл while.

void DisplayTime() {        
    if (timerStart) {
        if (countDownTime > 0) {
            countDownTime -= Time.deltaTime;
        }
    }
    timer2.text = Math.Round(countDownTime, 2).ToString();
}

Преимущество метода Coroutine заключается в том, что им обычно легче управлять.Вместо того, чтобы вызывать метод каждый раз из Update, вы можете вызвать его один раз и просто запустить.Поскольку зацикливание ограничивается самим методом, вы можете использовать DisplayTime для установки начального значения countDownTime в 2.

...