Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Custom update rate?

Discussion in 'Scripting' started by nyanpath, Aug 21, 2019.

  1. nyanpath

    nyanpath

    Joined:
    Feb 9, 2018
    Posts:
    77
    The greetings.

    I am looking into ways of making a repeated action happen at slower intervals than the 60 specified by the Update() and the LateUpdate(), and whatever number FixedUpdate() feels like updating at.

    The ways I have found so far are:
    1. (timer > delay){ Action(); } // In Update()
    2. InvokeRepeating("ActionString", startTime, rate);
    The first option is included in a few examples and the way I have done most of it in the past. However it gets a little ugly to work around. InvokeRepeating() has some overhead, but is fine for some .NET-specific code.

    However, what I would like to see is something like:
    Code (CSharp):
    1. void Update(int updateRate, Action action);
    So in updateRate I can specify from 0 to 60 how many times I need the action to be updated per second. 0 means it will be updated only once, a bit like Start() would. Now, a few of you would probably tell me I can make something like this Update(updateRate, action) myself, but as far as I see it, it would still only be based on way 1. described above.

    There are infinitely many reasons for me to want to do less updates per second for a lot of the game logic I have, specifically also based on distance and priority, so this would help a lot if is possible in a way.

    Please help me, I'd like to know what to do. ;w;
     
    LearningProgramer likes this.
  2. nilsdr

    nilsdr

    Joined:
    Oct 24, 2017
    Posts:
    375
    Can't you use InvokeRepeating?
     
  3. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    Joe-Censored likes this.
  4. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    You should never rely on Update "rate". Update rate is undefined. It will try to keep up woth target framerate, but there's no guarantee it will succeed. Many times it will fail.It might call 60 times per secon and once right next second. It depends on device load and is totally out of your control.
     
    Ryiah likes this.
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Try coroutines.
     
  6. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,202
    @palex-nx 's answer is best so far, but maybe you can give some more information on how you'd expect your approach to behave if the player's system was busy for an extended period. For example, sometimes expensive operations will lock the game up for a noticeable period, such as when instantiating a new object or doing something complex. In that case, let's say the system was busy for 0.25 seconds. Meaning, no Update() calls (or Coroutine calls) were made for that entire 0.25 seconds. Would that be okay for your system? Or does your system strictly require that your method be called many times over those 0.25 seconds, even if the screen isn't updating?

    Coroutines don't fire every N seconds/frames. Instead, they fire no more often than every N seconds/frames. Meaning, if you tell a coroutine to wait 0.1 seconds between calls, then the coroutine won't execute more than once every 0.1 seconds, but it can easily be longer than 0.1 seconds between calls.

    FixedUpdate is special. With FixedUpdate, if the system locks up for an extended period of time, Unity will make multiple sequential calls to FixedUpdate in the same frame until it has "caught up" with the current time. That's very different than the way coroutines work. Also, in case you're not using the Physics engine for anything, you could put your code in FixedUpdate, and adjust the Physics Time Step to make Unity call FixedUpdate at a different rate. That's probably not advised, but it's possible.

    So anyway, you should explain how depend your system is on something happening a specific number of times per second, or whether it's okay if your method doesn't get called while the system is busy, as long as it's called before the next screen update.
     
  7. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    If Unity implemented it, how do you think they would do it that would be different from way 1? That's basically how FixedUpdate already works.

    Also, I can't figure out how you think this is supposed to work syntactically:
    void Update(int updateRate, Action action);

    Who calls this function, and from where? The normal Update() is a special function that Unity calls every frame. If Unity calls this function following similar rules, then "updateRate" and "action" would need to be passed into your function by Unity; they wouldn't be something your function gets to define for itself.

    And if you're imagining that you write a piece of code somewhere that says "do this action X times per second from now on", then how exactly is that different from InvokeRepeating?
     
    StarManta likes this.
  8. willemsenzo

    willemsenzo

    Joined:
    Nov 15, 2012
    Posts:
    585
    Could something like this work for you? It will only run every 4 frames (or whatever interval you specify)

    Code (CSharp):
    1. int timer = 0;
    2. int interval = 4;
    3.  
    4. void Update()
    5. {
    6.     if(timer%interval == 0)
    7.     {
    8.         DoStuff();
    9.     }
    10.     timer++
    11. }
    12.  
    13. void DoStuff()
    14. {
    15.  
    16. }
     
    Jufin and ElGirafo like this.
  9. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    If you don't need the main API and you're doing your own calculations for something you can start a new thread, you will be able to run it as fast as you want (with a cap on how long it takes the function to finish) with no interruptions from Unity.

    if you describe what you're actually doing like @dgoyette we can offer the most suitable solution (coroutine, threading, invoke repeating, etc.)
     
  10. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    Doing something every N frames is probably a bad idea, because frames can vary in length. Usually you'd rather do something every N seconds; e.g.
    Code (CSharp):
    1. void Update()
    2. {
    3.     timeElapsed += Time.deltaTime;
    4.     while (timeElapsed >= interval)
    5.     {
    6.         timeElapsed -= interval;
    7.         DoThing();
    8.     }
    9. }
    But there are subtle variations on that theme that you might want to think about:
    • If a large amount of time has passed since the previous frame, should you do the thing multiple times to "catch up", or just once?
    • If you are late doing a thing one time, should you delay the next thing by the same amount to maintain spacing, or keep the next thing at the original time to preserve average frequency?
    • If you are late doing a thing, should you give it a fraction-of-a-frame "head start" to compensate? For instance, if you were supposed to fire a bullet at time t = 10, but you actually get called at time t = 10.1, should you move the bullet forward based on how far it would have moved during that extra 0.1 sec?
    • Should you be using (scaled) game time or (unscaled) real-world time?
     
    ZeroCC likes this.
  11. nyanpath

    nyanpath

    Joined:
    Feb 9, 2018
    Posts:
    77
    I need something that can work with the Job System/ECS. The problem with coroutines is that they run on the main thread, and this is not good for splitting workloads.

    One example of work needed is calculating changes over time based on player and NPC interactions, but these changes happen slowly so it would not be good to calculate them per frame.
     
  12. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,202
    In that case, it sounds like you'd be fine with a system that just kept track of the last time you performed the calculation (such as by storing Time.timeSinceLevelLoad), so that you can tell how much time has elapsed, and adjust the outcome accordingly. In that case, it probably doesn't matter what mechanism you use to trigger the calculation, as long as you know how much time has passed.
     
  13. Nyanpas

    Nyanpas

    Joined:
    Dec 29, 2016
    Posts:
    406
    That sounds like probably the only way I'd go forward with this. It's generic enough so it probably scales well too.

    Thank you.

    (Sorry about the multiple accounts but both are my job accounts...)
     
  14. greglo

    greglo

    Joined:
    Aug 1, 2018
    Posts:
    13
    Hello,

    I don't know how applicable it is to you, but I use a timer that updates every frame with the amount of deltaTime. If deltaTime reaches 1 [1 second] or whatever time you want then it will do something, and the counter will reset. You can of course extend the time upwards. Because it's using deltaTime it is separate from the update-framerate.

    You can keep track of the number of 'ticks' that have been reached this way too.