How do I add a delay to each iteration of a foreachloop?
I have an array of actors that I would like to set visible with a 1 second delay between each visibility when the player enters a trigger box.
Here's the non-array version of what I want to happen. This works fine. Bigger version here.
Here's the array version, which doesn't work. The delay at the end seems to execute once, but never again. The loop does continue to execute per element of the array, with the exception of the delay. Very perplexing! Bigger version here.
If I move the delay before Set Visibility, then only the first loop iteratation executes, but then it seems like it breaks out of the loop.
What can I do to make my first image's logic use an array instead? Why doesn't a delay work with a foreach loop?
Thanks for your time!
If you double-click the for-each loop you get into the macro it represents.
With one really small modification you have exactly what you need.
Add an exec as input, remove the sequence at the end pulling that line directly into the output node and replacing the line to the bottom by the new exec input.
Then you only have to pull a line after the body is finished back to the loop.
Here's a picture of how the macro looks modified:
answered Sep 29 '14 at 02:36 AM
i have made a simply mod in the for loop macro. I break up the exe line in the macro an get it out to put a delay.
answered May 08 '16 at 05:35 PM
You should make the loop manually, create a Variable of type int called "myindex" with default value of 0, Use a GET node on your array, and plug myarray in "Index", Set visibility for the result of the GET node, Add 1 to myindex.
Use a Branch node to compare Myindex with the length of the array, if myindex is < than the array length, plug it back to the beginning of the sequence, else set myindex to 0 and that's it.
you can now insert the delay wherever you want inside the loop, and it will work, maybe not the best way of doing it, but a lot easier than the first picture^^
answered Jun 01 '14 at 08:22 AM
The loop fires in a sequence that goes like this:
When the loop body hits a delay it sets up a timer and delegate to execute the rest of the body when the timer elapses. This effectively ends the execution of the loop body as far as the loop is concerned and so it goes on to the next loop body. The delay node that you call in all subsequent loop bodies is the same node you called in the first and so execution ends so that the global tick can continue and only a single loop body is evaluated when the timer finishes.
Why doesn't a delay register a new event every time it is called? It's intended to delay the execution of some logic a set amount of time. If set up new events every time it was hit then it would just cause a flood of delayed calls at the end of its timer but without actually spacing them apart. In effect it is a DoOnceInXSecondsThenReset node. Just like DoOnce it ends the execution path until it is reset.
Delays and standard foreach loops just can't get along because the loop doesn't know that you ended execution of the loop body with a delay. It must finish execution within a single tick because the loop state is not saved between ticks.
The answer as stated by others is to duplicate the logic of a foreach loop but to store the index so that you can continue the next loop body after the delay has finished.
I would also suggest that setting up a Timer would be cleaner and more straight forward at this point because you don't have to loop the wires back to the start.
You can do this do this by creating a custom event and name it relevant do whatever it is you need to do such as "TrySpawnNextActor" then At the end of the loop place a timer that will call your event. This is the fire and forget way of doing it. The loop will end when you reach the last index of the array because no more timers will be set up.
You should guard the loop with a branch/if statement so that outside calls can't call your loop again while it is executing possibly causing duplication or premature completion or lead to the loop completion being called twice. Not a problem with normal loops because they execute all at once.
I created two new macros called "For Each Loop With Delay" and "For Loop With Delay"
The Macros can be downloaded here:
Key thing was that the Macro library had to be based off of "Actor" and not "Object" as you cannot add a Delay node to Object Macros.
This means that if you want these nodes in your UMG or Animation Blueprints you will need to create local macros or derive the macro from another source than actor.
Here is the "For Loop With Delay" Logic:
Here is the "For Each Loop With Delay" Logic:
answered Aug 08 '17 at 08:09 AM
This looks complicated haha I dunno if the engine had major revisions since the time this post started regarding this macro BUT as of 4.18 it is super simple.
Here is a tutorial showing how to do this for those of you who prefer that instead.
Simple and now you have a custom "Loop with Delay" that you can set when calling the macro itself.
I encountered this "do once" behavior of the Delay node in a different context and solved it by using a Task Wait Delay node instead. Maybe that might solve this problem, too?
The difference between these is that while a Delay node simply drops any further incoming activations if it is already activated, a Task Wait Delay remembers all activations and sets up separate timers for each.
answered Feb 01 '17 at 10:20 AM
You can use "set timer by event" for less messy graph
answered Apr 05 '18 at 10:01 AM
Another way is to put everything you want to do in an event, and put in a delay node there, passing on a 'delay' float and any other parameters you need.
This way you also have control over the delay per loop step, ie you can do any stuff with index before you pass it to delay input, or not to do it immediately. (not just delay * index)
answered Apr 08 '18 at 02:39 PM
Follow this question
Once you sign in you will be able to subscribe for any updates here