Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to execute a code X times a second

Discussion in 'Scripting' started by Shorkieboyo, Jun 22, 2017.

  1. Shorkieboyo

    Shorkieboyo

    Joined:
    Mar 10, 2017
    Posts:
    14
    Hello, I'm trying to code a Metronome but I have no idea where to start.
    I looked at InvokeRepeating but I didn't quite get it.

    Any ideas?

    Thanks
     
  2. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    InvokeRepeating will execute a method that you supply as a string (of the method name) and a float value for a delay for the first time it starts, and its 3rd parameter is each "repeat" after the first.
    Coroutines are another way you might use to repeat code x times per second.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    Since unity has a variable framerate there's no way to guarantee X times a second, especially as that number rises above the framerate.

    InvokeRepeating will have issues since it just executes at the nearest time to the delay. If you want 10 times a second, or every 0.1 seconds... and 0.12 seconds has passed. It just calls it and waits another 0.1 seconds. Causing a slight drift over time.

    Your best bet is to use a Coroutine, or the Update method. And compare the amount of time that changes each frame, and call your method the appropriate time.

    Like so:
    Code (csharp):
    1.  
    2. public class Metronome : MonoBehaviour
    3. {
    4.  
    5.     public int TicksPerSecond = 30;
    6.  
    7.     private float _t;
    8.  
    9.     void OnEnable()
    10.     {
    11.         _t = 0f;
    12.     }
    13.  
    14.     void Update()
    15.     {
    16.         float dur = 1f / this.TicksPerSecond;
    17.         _t += Time.deltaTime;
    18.         while(_t >= dur)
    19.         {
    20.             _t -= dur;
    21.             this.CodeToRun();
    22.         }
    23.     }
    24.  
    25.     public void CodeToRun()
    26.     {
    27.         //do your stuff
    28.     }
    29.  
    30. }
    31.  
    Note... if the framerate gets so slow that an entire frame takes longer than one simulated tick... you'll get 2 simulated ticks on the same frame.

    There's no way around that since the game is single threaded and can only run code at the rate of the framerate.

    This is a very naive implementation of how FixedUpdate works in Unity. Where it attempts to run it at a fixed amount of ticks per second. Of course there's is probably a little more robust, since this naive version here will have huge issues if the amount of time to run 'CodeToRun' is longer than the amount of time TicksPerSecond takes.

    Basically if you run it every 0.1 seconds, and it takes 0.2 seconds to do the work... you'll constantly be falling behind. And your simulation with spiral downward and lock your system up. You should have safety measure in place if CodeToRun is non-trivial.

    A simple safety check would be like this:
    Code (csharp):
    1.  
    2.     void Update()
    3.     {
    4.         float dur = 1f / this.TicksPerSecond;
    5.         _t += Time.deltaTime;
    6.         int cnt = 3;
    7.         while(_t > dur && cnt > 0)
    8.         {
    9.             _t -= dur;
    10.             cnt--;
    11.             this.CodeToRun();
    12.         }
    13.     }
    14.  
    You allow a max of 3 ticks per frame. You accept drift over the system locking. But again, this is still a naive implementation. You can get more robust than this. Just demonstrating the concept.
     
    Last edited: Jun 22, 2017
    INeatFreak likes this.
  4. Shorkieboyo

    Shorkieboyo

    Joined:
    Mar 10, 2017
    Posts:
    14
    Thanks, that's quite helpful.
     
  5. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Metronomes and rhythm can be difficult in Unity, especially at higher beat frequencies. The human ear can frequently detect the errors unity's frame rate produces. Our ears don't naturally blend consecutive sounds the way our eyes blend multiple images.

    Its not just about Unity not being fast enough or not having a fixed framerate. Even if you got both of these right, if the frequency of the beat doesn't match the frequency that Unity updates at, you'll have beats late or early enough to mess things up.

    There was a good Unite video on procedural rhythm games that I can't find right now. From memory they had to manually push sounds into an audio buffer a half or second or so in advance, that way they weren't subject to Unity's fame rate.
     
    cstooch and lordofduct like this.