How to make a custom event system framerate friendly?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












I have a simple event system:



class GameEvent
float executionTime;
Action action;


class EventMgr : MonoBehaviour

List<GameEvent> events = new List<GameEvent>();

void Update()

float timeNow = Time.time;

for(int i=events.Count - 1; i >= 0; i--)

if(events[i].executionTime >= timeNow)

exents[i].action();
events.RemoveAt(i);





public void ScheduleEvent(float delay, Action action)
events.Add(new GameEvent()
action = action,
executionTime = Time.time + delay;
);




Then,



I schedule events like this:



eventMgr.ScheduleEvent(0.1f, () => 
// EVENT A - should be fired first
;

eventMgr.ScheduleEvent(0.15f, () =>
// EVENT B - should be fired second
;


Everything works fine when I play on 60 FPS. Update() is fired once every ~0.016s. When I play the game on a device with 20-40FPS - things got a little bit tricky. Events seem to run in an incorrect order (Event B fired before event A).



The only possible cause is of course the framerate itself.
If the game runs at 20FPS, Update() would be called less frequently and both of these events would be fired in the same frame - and then, the order of their execution depends on the list itself.



What to do here?
Is there any trick to prevent this, is there any pattern for accurate, ordered event system in games which is FPS friendly?










share|improve this question





























    up vote
    1
    down vote

    favorite












    I have a simple event system:



    class GameEvent
    float executionTime;
    Action action;


    class EventMgr : MonoBehaviour

    List<GameEvent> events = new List<GameEvent>();

    void Update()

    float timeNow = Time.time;

    for(int i=events.Count - 1; i >= 0; i--)

    if(events[i].executionTime >= timeNow)

    exents[i].action();
    events.RemoveAt(i);





    public void ScheduleEvent(float delay, Action action)
    events.Add(new GameEvent()
    action = action,
    executionTime = Time.time + delay;
    );




    Then,



    I schedule events like this:



    eventMgr.ScheduleEvent(0.1f, () => 
    // EVENT A - should be fired first
    ;

    eventMgr.ScheduleEvent(0.15f, () =>
    // EVENT B - should be fired second
    ;


    Everything works fine when I play on 60 FPS. Update() is fired once every ~0.016s. When I play the game on a device with 20-40FPS - things got a little bit tricky. Events seem to run in an incorrect order (Event B fired before event A).



    The only possible cause is of course the framerate itself.
    If the game runs at 20FPS, Update() would be called less frequently and both of these events would be fired in the same frame - and then, the order of their execution depends on the list itself.



    What to do here?
    Is there any trick to prevent this, is there any pattern for accurate, ordered event system in games which is FPS friendly?










    share|improve this question

























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      I have a simple event system:



      class GameEvent
      float executionTime;
      Action action;


      class EventMgr : MonoBehaviour

      List<GameEvent> events = new List<GameEvent>();

      void Update()

      float timeNow = Time.time;

      for(int i=events.Count - 1; i >= 0; i--)

      if(events[i].executionTime >= timeNow)

      exents[i].action();
      events.RemoveAt(i);





      public void ScheduleEvent(float delay, Action action)
      events.Add(new GameEvent()
      action = action,
      executionTime = Time.time + delay;
      );




      Then,



      I schedule events like this:



      eventMgr.ScheduleEvent(0.1f, () => 
      // EVENT A - should be fired first
      ;

      eventMgr.ScheduleEvent(0.15f, () =>
      // EVENT B - should be fired second
      ;


      Everything works fine when I play on 60 FPS. Update() is fired once every ~0.016s. When I play the game on a device with 20-40FPS - things got a little bit tricky. Events seem to run in an incorrect order (Event B fired before event A).



      The only possible cause is of course the framerate itself.
      If the game runs at 20FPS, Update() would be called less frequently and both of these events would be fired in the same frame - and then, the order of their execution depends on the list itself.



      What to do here?
      Is there any trick to prevent this, is there any pattern for accurate, ordered event system in games which is FPS friendly?










      share|improve this question















      I have a simple event system:



      class GameEvent
      float executionTime;
      Action action;


      class EventMgr : MonoBehaviour

      List<GameEvent> events = new List<GameEvent>();

      void Update()

      float timeNow = Time.time;

      for(int i=events.Count - 1; i >= 0; i--)

      if(events[i].executionTime >= timeNow)

      exents[i].action();
      events.RemoveAt(i);





      public void ScheduleEvent(float delay, Action action)
      events.Add(new GameEvent()
      action = action,
      executionTime = Time.time + delay;
      );




      Then,



      I schedule events like this:



      eventMgr.ScheduleEvent(0.1f, () => 
      // EVENT A - should be fired first
      ;

      eventMgr.ScheduleEvent(0.15f, () =>
      // EVENT B - should be fired second
      ;


      Everything works fine when I play on 60 FPS. Update() is fired once every ~0.016s. When I play the game on a device with 20-40FPS - things got a little bit tricky. Events seem to run in an incorrect order (Event B fired before event A).



      The only possible cause is of course the framerate itself.
      If the game runs at 20FPS, Update() would be called less frequently and both of these events would be fired in the same frame - and then, the order of their execution depends on the list itself.



      What to do here?
      Is there any trick to prevent this, is there any pattern for accurate, ordered event system in games which is FPS friendly?







      unity events frame-rate






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited 1 hour ago

























      asked 1 hour ago









      Spectre

      1,8402733




      1,8402733




















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          3
          down vote



          accepted










          This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:



          while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time) 
          eventQueue.Dequeue().action();



          This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.



          The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime.



          Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.






          share|improve this answer




















          • Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
            – Spectre
            16 mins ago










          • It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
            – DMGregory♦
            14 mins ago

















          up vote
          2
          down vote













          If sufficient time passes between Update calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.



          If you want your events to create an implicit dependency through their firing time (e.g., an event A with an absolute time Ta must fire before any events with absolute time Tn > Ta), then you need to ensure you process them in that order.



          In your case, you could just sort the list by absolute time, either before you process it in Update or by ensuring during scheduling you put new events in the proper sorted position.



          Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).






          share|improve this answer






















            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "53"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fgamedev.stackexchange.com%2fquestions%2f164561%2fhow-to-make-a-custom-event-system-framerate-friendly%23new-answer', 'question_page');

            );

            Post as a guest






























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            3
            down vote



            accepted










            This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:



            while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time) 
            eventQueue.Dequeue().action();



            This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.



            The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime.



            Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.






            share|improve this answer




















            • Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
              – Spectre
              16 mins ago










            • It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
              – DMGregory♦
              14 mins ago














            up vote
            3
            down vote



            accepted










            This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:



            while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time) 
            eventQueue.Dequeue().action();



            This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.



            The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime.



            Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.






            share|improve this answer




















            • Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
              – Spectre
              16 mins ago










            • It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
              – DMGregory♦
              14 mins ago












            up vote
            3
            down vote



            accepted







            up vote
            3
            down vote



            accepted






            This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:



            while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time) 
            eventQueue.Dequeue().action();



            This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.



            The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime.



            Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.






            share|improve this answer












            This looks like you could solve it with a priority queue or min-heap. The code to process the queue would look something like this:



            while(eventQueue.Count > 0 && eventQueue.Peek().executionTime < Time.time) 
            eventQueue.Dequeue().action();



            This means you have only one check to do on frames when no events happen - you don't have to scan the whole list.



            The nature of the priority data structure ensures that the next event to fire is always the first one you check, and when multiple events fire in the same frame, you process them in non-decreasing order of executionTime.



            Insertion and removal from such a data structure are typically logarithmic, so they remain reasonable even for large collections of events.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 34 mins ago









            DMGregory♦

            53.8k1199153




            53.8k1199153











            • Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
              – Spectre
              16 mins ago










            • It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
              – DMGregory♦
              14 mins ago
















            • Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
              – Spectre
              16 mins ago










            • It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
              – DMGregory♦
              14 mins ago















            Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
            – Spectre
            16 mins ago




            Are these any ready-to-go data structures like a priority queue available in Unity, .NET 4.5?
            – Spectre
            16 mins ago












            It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
            – DMGregory♦
            14 mins ago




            It's absent from the standards .NET collections, but easy to whip up your own custom-suited to your needs. It's also a popular enough dara structure that you can find implementations in several third-party libraries you could include too, if you want something battle-tested without writing it from scratch yourself.
            – DMGregory♦
            14 mins ago












            up vote
            2
            down vote













            If sufficient time passes between Update calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.



            If you want your events to create an implicit dependency through their firing time (e.g., an event A with an absolute time Ta must fire before any events with absolute time Tn > Ta), then you need to ensure you process them in that order.



            In your case, you could just sort the list by absolute time, either before you process it in Update or by ensuring during scheduling you put new events in the proper sorted position.



            Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).






            share|improve this answer


























              up vote
              2
              down vote













              If sufficient time passes between Update calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.



              If you want your events to create an implicit dependency through their firing time (e.g., an event A with an absolute time Ta must fire before any events with absolute time Tn > Ta), then you need to ensure you process them in that order.



              In your case, you could just sort the list by absolute time, either before you process it in Update or by ensuring during scheduling you put new events in the proper sorted position.



              Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).






              share|improve this answer
























                up vote
                2
                down vote










                up vote
                2
                down vote









                If sufficient time passes between Update calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.



                If you want your events to create an implicit dependency through their firing time (e.g., an event A with an absolute time Ta must fire before any events with absolute time Tn > Ta), then you need to ensure you process them in that order.



                In your case, you could just sort the list by absolute time, either before you process it in Update or by ensuring during scheduling you put new events in the proper sorted position.



                Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).






                share|improve this answer














                If sufficient time passes between Update calls to trigger multiple events, then as you note the actual firing order depends on the order in which you process the list. Since you process the list backwards you will evaluate and thus potentially fire "later" events sooner.



                If you want your events to create an implicit dependency through their firing time (e.g., an event A with an absolute time Ta must fire before any events with absolute time Tn > Ta), then you need to ensure you process them in that order.



                In your case, you could just sort the list by absolute time, either before you process it in Update or by ensuring during scheduling you put new events in the proper sorted position.



                Sorting the list backwards by absolute time means you can continue to process it backwards and rely on the efficiency of removing items from the end of the list (versus from the beginning, which would require moving the remaining items down).







                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited 1 hour ago

























                answered 1 hour ago









                Josh♦

                90.7k16203316




                90.7k16203316



























                     

                    draft saved


                    draft discarded















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fgamedev.stackexchange.com%2fquestions%2f164561%2fhow-to-make-a-custom-event-system-framerate-friendly%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Comments

                    Popular posts from this blog

                    What does second last employer means? [closed]

                    Installing NextGIS Connect into QGIS 3?

                    One-line joke