Problem with writing a timer/starting-ending it/ showing it in UI

Hello! I’ve been trying to write a timer which measures the time it takes to move between to points, the start and the end. Both check via a collider whether the player has emtered and update the timer script.

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


public class Timing : MonoBehaviour
{
    public bool hasStarted= false;
    public bool hasEnded= false;
    public float t;
    public float startTime;
    public Text timeText;

   
    public void update()
    {
//checks if the start stop variables are right
    if(hasStarted == true && hasEnded == false)
    {
        startTime = Time.time;
        t =  Time.time - startTime;
        timeText.text = t.ToString();
    //updates the UI
    }
    else if(hasEnded == true)
    {
        timeText.text = t.ToString();
    //sets the UI to the last stored value
    }

    }

    public void setStart(bool set)
    {
        hasStarted = set;
    }
   
    public void setStop(bool tempSet)
    {
        hasEnded = tempSet;
    }
}

these are the end and start trigger:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class timerSetActiveScript : MonoBehaviour
{
    public GameObject timer;

    public void OnTriggerEnter()
    {
        timer.GetComponent<Timing>().setStart(true);
        Debug.Log("start has been triggered");
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class timerSetEndScript : MonoBehaviour
{
    public GameObject timer;

    public void OnTriggerEnter()
    {
        timer.GetComponent<Timing>().setStop(true);
        Debug.Log("end has been triggered");
    }
}

I can’t see the UI changing, but the Debugger claims it has been Triggered

Remember that ALL Unity Special methods must begin with a capital letter and match exactly what Unity requires to autorun. This is a good habit to get into for your own methods.

update will not autorun by Unity.
Update will. Fix the capitalization.

1 Like

Thanks, it is now updating the UI, but it won’t count past 0.

startTime = Time.time;
        t =  Time.time - startTime;

I mean, the amount of time between these two lines of code is going to be so small that you’ll never see it. If startTime = Time.time and then you subtract…you’ll get 0.

I guess you could change the order of them so it will update t at the start of the frame.

Hm, I see my problem, the start time only needs to be called once. like this it is being called every time.

I’m gonna make it so that the “Trigger” set’s the start time.

Cool, there ya go. Wasn’t sure if you were trying to measure time between frames. Glad you figured out a solution. Sometimes just walking through your code visually is enough to help figure out a solution.

1 Like

It looks like this now:

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


public class Timing : MonoBehaviour
{
    public bool hasStarted= false;
    public bool hasEnded= false;
    public float t;
    public float startTime;
    public Text timeText;

   
    public void Update()
    {
    if(hasStarted == true && hasEnded == false)
    {
        t =  Time.time - startTime;
        timeText.text = t.ToString();
    }
    else if(hasEnded == true)
    {
        timeText.text = t.ToString();
    }

    }
    //set's the start time, is being called when entering the Trigger
    public void setTime(float x)
    {
        startTime = x;
    }

    public void setStart(bool set)
    {
        hasStarted = set;
    }
   
    public void setStop(bool tempSet)
    {
        hasEnded = tempSet;
    }
}

it works and hurts my eyes

You probably don’t want to update UI text or do a ToString every frame.

A coroutine can act like an Update that only works when you want it to.

public void SetStart()
{
    if (!hasStarted)
    {
        StopAllCoroutines();
        StartCoroutine(Timer());
    }
}

public void SetStop()
{
    hasStarted = false;
}

IEnumerator Timer()
{
    // Start frame
    hasStarted = true;
    startTime = Time.time;

    // Update every frame until condition fails
    while(hasStarted)
    {
        t = Time.time - startTime;
        timeText.text = t.ToString();
        yield return null; // Wait for next frame
    }

    // End frame. Coroutine will stop running.
}
2 Likes

I would put the actual text updating into a separate function that you only call every X amount of time. Coroutines or InvokeRepeating() can do this.
Also, if you have two bools which are always opposite from each other (like hasStarted and hasEnded), you can often rework things to just use one (isRunning or something). Yes, hasStarted and hasEnded can both be true when it ends, but that’s just confusing imo.

1 Like

Thanks, but I actually want to update it this often, at least right now. And it is only for a small hobby project, no commercial game. I just want to learn, but this teaches me alot about different approaches. Thanks!

I didn’t know Unity had stuff like that. I’m learning alot about this language. I orignally come from barebone Java and I don’t knwo about this. Thanks for pointing this out!

1 Like

In case you do any fast printing to the Console for debugging, it can be a bottleneck on performance while testing in the Editor, so don’t believe any low framerates you might see while doing it. (Builds don’t have this issue as there’s no Console.) You can use on-screen UI text objects for debugging instead, just like your timer. This also means you don’t need your Console open, you can play in Maximized mode and see everything instead of just one line, etc. Of course, for just the occasional variable output, the Console makes sense. It’s easy to turn printing on and off with a keystroke too, whether to the Console or on-screen.