简体   繁体   English

Unity倒数计时器跳到零并倒数为负数

[英]Unity countdown timer jumping to zero and counting down into negatives

Something strange is happening with my countdown timer and I'm stuck. 我的倒数计时器发生了一些奇怪的事情,我被困住了。 I'm passing a number to my timer (15 seconds) which starts at 15 but then jumps to 0 and then counts down from there: 0, -1, -2, -3... What am I doing incorrectly here? 我正在向计时器传递一个数字(15秒),该计时器从15开始,然后跳到0,然后从那里倒数:0,-1,-2,-3 ...我在这里做错了什么?

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class CountdownTimer : MonoBehaviour
{
    float seconds;
    public Text timerText;

    public void Update()
    {
        seconds -= Time.deltaTime;
        if (timerText != null)
        {
            timerText.text = Mathf.Round(seconds).ToString();
            Debug.Log (Mathf.Round(seconds));
        }
    }
}

I'm calling the countdown script from a function in another script like this: 我正在从另一个脚本中的函数调用倒计时脚本,如下所示:

void ShowRestartWarning()
    {
        //Debug.Log("Restart Warning Dialog");

        canvas = GameObject.FindGameObjectWithTag("Canvas");

        timerInstance = Instantiate(timeOutWarningDialog);
        timerInstance.transform.SetParent(canvas.transform, false);
        timerInstance.SetActive(true);

        CountdownTimer countdownTimer = timeOutWarningDialog.GetComponent<CountdownTimer>();
        countdownTimer.Update();                                                    

        CancelInvoke();
        Invoke("RestartGame", countdownLength);   
    }

Try using a coroutine instead of Update function, that way you can start it and stop it whenever you want. 尝试使用协程而不是Update函数,这样您就可以在需要时启动和停止它。

public Text timerText;

public void Start(int seconds)
{
    StartCoroutine("RunTimer", seconds);
}

IEnumerator RunTimer(int seconds)
{
    while (seconds > 0)
    {
        if (timerText != null)
        {
            timerText.text = seconds.ToString();
            Debug.Log (seconds);
        }
        yield return new WaitForSeconds(1);
        seconds -= 1;
    }
}
public class CountdownTimer : MonoBehaviour
{
    float seconds;
    public Text timerText;

    public void Update()
    {
        seconds -= Time.deltaTime;
        if (timerText != null)
        {
            timerText.text = Mathf.Round(seconds).ToString();
            Debug.Log (Mathf.Round(seconds));
        }
    }
}

First the Update() method in a MonoBehaviour that is activated it will be called every frame (More info about that here: Execution Order of Event Functions ) 首先,被激活的MonoBehaviour中的Update()方法将在每一帧中调用(有关此内容的更多信息,请参见事件函数的执行顺序

Now, in your script you have 2 variables. 现在,您的脚本中有2个变量。 First a private seconds and then a public timerText . 首先是私人seconds ,然后是公共timerText Why timerText is public? 为什么timerText是公共的? If that variable is not being used by another class should be private . 如果该变量未被另一个类使用,则应为private

Now is when you ask; 现在是时候您问了; But how I attach a Text component in the editor? 但是,如何在编辑器中附加Text组件? Well, you should use SerializeField instead. 好吧,您应该改为使用SerializeField

Now I think that the error is that you are assigning some value to the Text component. 现在,我认为错误是您正在为文本组件分配一些值。 But, your variable seconds is by default zero. 但是,您的可变seconds默认情况下为零。 (You are declaring a float without any value, by default it will be initialized as 0f ). (您声明的浮点数没有任何值,默认情况下它将initialized0f )。

So the first frame the Text component will display your initial value, let say 15 . 因此,Text组件的第一帧将显示您的初始值,假设15 But the first time that Update() is being called, the line seconds -= Time.deltaTime it will be something like seconds = 0f - Time.deltaTime; 但是,第一次调用Update() ,第二行seconds -= Time.deltaTime将类似于seconds = 0f - Time.deltaTime; , then timerText it will be updated with this new almost zero value. ,然后将使用此新的almost zero值更新timerText

What can you do? 你能做什么? You can use another Event Function, Awake to setup your variable with some value before the Update calls. 您可以使用另一个事件函数“ 唤醒”Update调用之前为变量设置一些值。

If you want to use the value of timerText you can do this: 如果要使用timerText的值,可以执行以下操作:

public class CountdownTimer : MonoBehaviour
{
    private float seconds;

    [SerializeField]
    private Text timerText;

    private void Awake()
    {
        if (!string.isNullOrEmpty(timerText))
        {
            seconds = float.Parse(timerText.text);          
        }
    }

    // Yep, Event Functions can be private and Unity will `call` them anyways
    private void Update() 
    {
        seconds -= Time.deltaTime;
        if (timerText != null)
        {
            timerText.text = Mathf.Round(seconds).ToString();
            Debug.Log (Mathf.Round(seconds));
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM