0
\$\begingroup\$

Hi I am making a digital speedometer and I want it to change like a normal meter like: if speed is 10 on meter and the new speed is 50 it does not just show 50 on text instead gradually increase it.

here is what I have done:

    int speed;
    int textSpeed;
    int speedfinal;

    public Text text;

    // Update is called once per frame
    void Update()
    {
        speed = GameObject.Find("gamePlayManager").GetComponent<gamePlayManagerScript>().userSpeed;
        textSpeed = int.Parse(text.text);

        speedfinal = (int)Mathf.Lerp(textSpeed, speed, 0.1f);

        text.text = speedfinal.ToString();
    }

I am not sure if lerp is a good choice here to change text but that is what I know but it is adding 9 less then the orignal speed. Any idea how to do this. thanks.

\$\endgroup\$
2
  • \$\begingroup\$ It's a digital value, it can go from 10 to 50 as soon as the new value is known. It does not have to match the needle position, which is mechanical and takes some time to move. \$\endgroup\$
    – Vaillancourt
    Jul 11, 2019 at 15:22
  • \$\begingroup\$ yes but I want it to change like 10,11,12..50 instead of 10 to 50. \$\endgroup\$ Jul 11, 2019 at 15:24

2 Answers 2

2
\$\begingroup\$

If you use Lerp with a constant interpolation value of 0.1f, you are reducing the difference between current value and end value in increments of 10% per update, but you will never reach it. Add the precision loss due to rounding it to an integer, and you have no change anymore when you are 9.0 away from the end value.

A simple solution to this problem is to forget about Lerp and simply move the current value one closer to the destination value with each update:

  if (textSpeed < speed) {
       textSpeed++;
  } else if (textSpeed > speed) {
       textSpeed--;
  }

This solution might be sufficient, but has two cosmetic shortcommings:

  • It might take a while to process really large changes in speed
  • It isn't deltaTime-adjusted

If you want to fix these problems, then integer-arithmetic won't do. Stop keeping track of the currently displayed value by parsing the text. Use a private float variable to keep track of the value you want to display and don't convert it to an integer until you pass it to the text field on the UI.

Instead of adding or subtracting 1 to textSpeed, add or subtract the difference between speed and textSpeed multiplied with Time.deltaTime and a desired speed factor, but if the change is too small, change it by a fixed minimum value instead.

\$\endgroup\$
1
  • \$\begingroup\$ The ++ and -- solution worked. But I want to avoid any possible glitches. Can you please tell me what should I use a private float var for? \$\endgroup\$ Jul 11, 2019 at 17:35
3
\$\begingroup\$

The improvement achieved with the solution below are:

  1. You avoid calling GameObject.Find and int.Parse in the Update loop.
  2. You use Late Update instead of Update. Not a big deal, but I see this more as a graphical feature, so it's better LateUpdate (it works also if you want to use Update)
  3. I see you are trying to Lerp but I do not see this as the best approach, as you need still to have some kind of counter for the interpolation parameter. To make it simple you might just do the counting directly.
  4. In the answer I increment it 1 by 1. If you want to see something different (similar to lerp) you may just change the increment to a different formula, to have a different gradual change.
  5. With the _changeIntervalInSecond you may directly decide how fast you want the change to happen (_changeIntervalInSecond requires to be > than 0, otherwise you will change it at each loop)

Code solution

public Text text;
//define a speed for the change
public float _changeIntervalInSecond;

//used to store the previous speed instead of taking it from the text
int _speedOnText = 0;
float _lastCountedTime = 0f;

//cache manager at awake
private void Awake()
=> _manager = GameObject.Find("gamePlayManager").GetComponent<gamePlayManagerScript>();

// this is more a graphical feature, so you may use Late Update
void LateUpdate()
{
    //get the current speed
    var currentSpeed = _manager.userSpeed;

    //ignore if we have no changes
    if(_speedOnText == currentSpeed) return;

    _lastCountedTime += Time.deltaTime;
    //if your interval has passed change the speed
    if(_lastCountedTime > _changeIntervalInSecond)
    {
        if(_speedOnText< currentSpeed) _speedOnText++;
        else _speedOnText--;
        text.text = _speedOnText.ToString();
        _lastCountedTime = 0;
    }
}
\$\endgroup\$
3
  • \$\begingroup\$ Welcome to Game Development Stack Exchange. This is a good first answer, but you could make it even better by explaining how your are approaching the problem in your answer and why it works better than the code from the question. We don't want to be a code-on-demand delivery service. We want to help people to learn. \$\endgroup\$
    – Philipp
    Jul 11, 2019 at 15:47
  • \$\begingroup\$ Thanks for the heads up. I added a few explanation. \$\endgroup\$ Jul 11, 2019 at 15:57
  • \$\begingroup\$ And btw, now that I read your answer, mine seems much a follow up with a concrete implementation of time counting :). \$\endgroup\$ Jul 11, 2019 at 16:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .