Search Unity

Event Management

Discussion in 'Scripting' started by Abended, Aug 7, 2020.

  1. Abended

    Abended

    Joined:
    Oct 9, 2018
    Posts:
    142
    I have a bunch of objects that all have an action that fires on an event they are listening for. When they all fire at once I get a spike. I would like to have them all fire consecutively/sequentially and wait for the previous one to finish first, what they do is not apparent to the player, so there isn't a need for them to all be finished at once.

    They don't know about each other.
    I would like to make the solution reusable.

    I am thinking that I would have to add the actions to a queue and then send them through a coroutine...? Just noodling how to approach this. Any suggestions?
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    A coroutine is unnecessary, you can just process the queue in Update. One important thing to note here is that you can't use the "event" keyword for events here - you'll have to have a list of delegates that you manage yourself.
    Code (csharp):
    1. private Queue<Action> actionQueue = new Queue<Action>();
    2. public void QueueAction(Action someEventFunction) {
    3. actionQueue.Enqueue(someEventFunction);
    4. }
    5. public int actionsPerFrame = 10;
    6. void Update() {
    7. int actionsLeft = actionsPerFrame;
    8. while (actionQueue.Count > 0 && actionsLeft > 0) {
    9. var act = actionQueue.Dequeue();
    10. act?.Invoke();
    11. actionsLeft--;
    12. }
    13. }
    You could also use the Stopwatch class to limit the number of actions based on how long they take to run, allowing no more than 10 milliseconds of queued actions per frame or whatever.
     
  3. Abended

    Abended

    Joined:
    Oct 9, 2018
    Posts:
    142
    Interesting! I have not messed around with queues or actions! This should set me down the right path, Thanks!
     
  4. Abended

    Abended

    Joined:
    Oct 9, 2018
    Posts:
    142
    @StarManta I've been messing with this today, I seemed to have just moved the spike to a later time in the cycle. I've moved the actionsPerFrame down to 1. What about adding a loop count so that I can be sure that each action is fired say after every 10 frames to get some distance between each action as I don't know how long each action takes. Is that a lot of wasted cycles just counting to 10 over and over?
     
  5. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    If you're seeing this, you most likely just have one callback that is taking a particularly long time; if you're not able to split that up into multiple callbacks, then you're gonna have a spike when it's called.
     
  6. Abended

    Abended

    Joined:
    Oct 9, 2018
    Posts:
    142
    @StarManta I have a handful of render textures 1024x1024 that I am pushing to in memory textures to save the passes from the shader since the procedural part is finished. I have manual buttons in the editor, if I do them one at a time, I don't take a hit. they are more or less uniform calls. I'm not super proficient with the profiler as yet. But the transition is the same image underneath, so no visual change is happening. The change is a blit, I don't know if that is a one frame thing or not. If they all blit at the same time, I think that is what is dragging me down. What about instead of update if I have a coroutine fire every second? that would be less checks overall, and like I said I don't need it to be an instant change.
     
  7. Abended

    Abended

    Joined:
    Oct 9, 2018
    Posts:
    142
    Coroutine with a 1-sec yield smoothed it out! Thanks for the help on that one! Glad to put it to bed!