Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Object movement speed in 2d depends on FPS

Discussion in 'Scripting' started by daibutsu, May 20, 2021.

  1. daibutsu

    daibutsu

    Joined:
    Nov 28, 2017
    Posts:
    42
    Hello everyone!

    A project on a smartphone in 2D, it is necessary that in a strictly limited time (2 minutes) the game object changes its position a specific number of times.

    With a high FPS, everything goes smoothly, but if the FPS falls below 30, then the object does not have time to make the required number of position changes during this time.

    The change of position is embedded in the coroutine, which is launched in Start (), then there is a cycle until the set time expires. There is an intersection with the function of changing the color of the object, which changes color depending on the number of positions passed.

    How can you make sure that the number of position changes is always the same regardless of FPS?

    Code (CSharp):
    1.  DateTime timerEnd;
    2.     TimeSpan delta;
    3.     Text gameTimer;
    4.  
    5.     void FixedUpdate()
    6.     {
    7.         Timer();  
    8.     }
    9.  
    10. void Timer()
    11.     {
    12.         if (delta.TotalSeconds >= 0)
    13.         {
    14.             delta = timerEnd - DateTime.Now;
    15.             gameTimer.text = $"{delta.Minutes} : {delta.Seconds}";
    16.         }
    17.         if (delta.TotalSeconds <= 0)
    18.         {
    19.             playGame = false;
    20.         }
    21.     }
    Tried to launch via Time.fixedDeltaTime

    Code (CSharp):
    1. StartCoroutine(FlowerRespawn(TTLFlower * Time.fixedDeltaTime * 50));
    Here is movement part

    Code (CSharp):
    1.  private IEnumerator FlowerRespawn(float timer)
    2.     {
    3.         if (playGame)
    4.         {
    5.             if (!flower.GetComponent<Image>().enabled) flower.GetComponent<Image>().enabled = true;
    6.  
    7.             int rand = UnityEngine.Random.Range(0, pointPosition.Length);
    8.             flower.transform.position = pointPosition[rand].position;
    9.             if (nowPos == rand)
    10.             {
    11.                 rand = UnityEngine.Random.Range(0, pointPosition.Length);
    12.                 flower.transform.position = pointPosition[rand].position;
    13.                 yield return new WaitForSeconds(0f);
    14.             }
    15.             nowPos = rand;
    16.             yield return new WaitForSeconds(timer * Time.fixedDeltaTime * 50);
    17.  
    18.             Invoke("ColorChange", 0f);
    19.         }
    20.     }
    So, the main problem is that in 2 minutes i need to show 180 objects with different colors and see if person will tap on it.

    But sometimes, number of objects are changing )159, 171, 178 and so on. Not sure if it depends on the FPS, since i tested on the 12 pro max and 1mln% sure that my fps is high enough.
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    When you do your yield statement, it's always going to wait for at least one (rendered) frame. If this is slower than your fixedDeltaTime (by default 0.02 sec, or 50fps) then it will be waiting longer than that, just because it's always waiting a frame. And most likely, even with fast framerates, you'll end up waiting slightly longer because Time.deltaTime will never perfectly align with your desired time interval.

    If you need something to happen exactly X times in Y amount of time, a better approach than "trying to make it happen at the exact right times", would be "expect that you'll miss a 'right time', and plan to catch up the next time". This is basically how FixedUpdate works (in slower framerates, it runs several FixedUpdate cycles immediately - it does not run exactly every 0.02 seconds in real-world time, but it does ultimately run 50 times every second, and the value of Time.time is simulated so that it appears to happen at regular intervals).

    Try keeping a "lastChangeTime" variable. Each time you change position, add the time interval to this value (do NOT set it to the current time, because the extra fraction of a second from Time.deltaTime will make you slow down, and slow down more at slower framerates). Then check the current time against lastChangeTime + interval to determine when to do the next change, and increment it again.