How do I add a delay to each iteration of a foreachloop?

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^^

1 Like

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!

1 Like

Why do we still have to do that? Is there a reason for not being able to perform a delay in a loop’s body?

1 Like

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:

8 Likes

The loop fires in a sequence that goes like this:

  1. Initialize the index variable.
  2. If the length of the array is greater than current index do the loop body of index else go to #4
  3. When the body finishes Increment the index go to #2
  4. Complete

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.

4 Likes

I should add delays are no longer supported in macros that can be run inside functions as of the 4.7 preview.

Got the same problem, this is very annoying. A delay is just a delay and nothing else. Would really be nice if it would behave like it should everytime it is called. I can’t believe that I’m fiddeling around this now for one hour!

1 Like

Didn’t answers so far help?

Even though they are all not beautiful solutions and this certainly should work like that by default it they should fix your issue.

Yes, it’s just that. Another dirty workaround for such a simple task like ‘do nothing for x seconds’. Don’t wanted to sound harsh, but sometimes I wonder myself why everything has to be so complicated in UE4, sorry.

2 Likes

Honestly… that is the fault of visual scripting.

The compiler just works differently and isn’t built to create complex things. Those should still be made in C++. Blueprint is an awesome tool for some quick tests and for implementing the final logic inside of your level, stuff you most likely want to be able to change later on in the development and stuff like that.

Pure BP development reaches borders like this fast.

1 Like

Yes, I see. But it’s pretty perplexing, that even dead-simple thinks like a delay (!) becomes rocket science with Blueprint, which was originally created to simplify stuff. And C++ - no thanks. Java, C# or even JavaScript - why not, but not C++, not for scripting.

In my loop I just call another method or event and pass in the delay there. So my loop calls method( index * delay ) which my method has a Delay node. So basically every subsequent call to the method get’s a higher delay. Works exactly the way you would want. Say you have a 1 second delay, it would call 01 = 0, then 11=1, then 2*1=2, etc. Those delays are all building up instantly.

1 Like

You don’t even need a method honestly. Just do a Delay node like you normally would but make the delay a constant # * THE INDEX.

Any news on this? Delay still is ignored inside a for-each node inside an event for no apparent reason…

thanks.
now how do i reset the foreachloop to the default?

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.

Don’t mess with the defaults, always make your own personal macro library and copy default macros to it before messing with them.

1 Like

----------Update: 08/24/2016 -------------
Engine Version: 4.12.5

Epic has still not fixed this issue. But there is an elegant solution to this problem. Check out this article by “iRYO400”. They offer a simple and straightforward approach that works.

The only addition I would suggest to make it cleaner is to create your own Blueprint Macro Library and add what he has done inside a macro in your library rather than in the individual blueprints themselves to make it more reusable.

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.

I was attempting to use a delay in an asset BP (which is not an actor, and thus can’t call a delay node) and used a “Set Timer by Function Name” node and a corresponding “clear timer by event” node to stop it from looping. In my case, I have a second timer by event which doesn’t loop, so that it will clear the timer after a set time. You could easily use a counter and compare it to the number of times you want to repeat the action and call the clear timer that way as well.

1 Like