x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

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. alt text 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! alt text 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!

Product Version: Not Selected
Tags:
more ▼

asked Jun 01 '14 at 07:52 AM in Blueprint Scripting

avatar image

mandilorian
186 13 20 279

avatar image spyro May 28 '15 at 08:36 AM

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!

avatar image Erasio May 28 '15 at 11:22 AM

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.

avatar image spyro May 28 '15 at 11:34 AM

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.

avatar image Erasio May 28 '15 at 11:39 AM

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.

avatar image spyro May 28 '15 at 01:18 PM

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.

avatar image Mattapato Aug 24 '16 at 10:38 PM

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

avatar image dragonsomnolent Feb 25 '17 at 05:02 AM

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. alt text

capture.png (171.4 kB)
(comments are locked)
10|2000 characters needed characters left
Viewable by all users

10 answers: sort voted first

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: alt text

loop.png (255.6 kB)
more ▼

answered Sep 29 '14 at 02:36 AM

avatar image

Erasio
5.9k 291 86 293

avatar image HyperBolo Feb 11 '16 at 06:02 PM

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

avatar image so2gamemake May 13 '16 at 07:12 AM

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

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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. alt text

macro_delay1.png (165.7 kB)
macro_delay2.png (152.3 kB)
more ▼

answered May 08 '16 at 05:35 PM

avatar image

Gotcha000
71 1 2 6

avatar image Micke879 Apr 25 '17 at 10:03 PM

Brilliant solution! As long as people remember to create a new macro and not edit the standard ForLoop one!

avatar image Mighty Marcos Jun 01 '17 at 04:13 PM

Oh, thanks, really useful!! :D

avatar image RubiousOctopus Mar 31 '18 at 03:17 PM

Genius! Thanks, mate!

avatar image delcasda Jun 20 '18 at 05:54 PM

Perfect! Thanks

avatar image dieCuren Nov 27 '18 at 02:52 AM

Made my day

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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

more ▼

answered Jun 01 '14 at 08:22 AM

avatar image

Talus
179 34 35 43

avatar image raphu604 Sep 28 '14 at 10:26 PM

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?

avatar image spyro Dec 17 '15 at 02:16 PM

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

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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.

more ▼

answered Sep 29 '14 at 04:34 AM

avatar image

james0x0A
264 10 9 26

avatar image RumbleMonk Jan 22 '15 at 07:45 PM

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

avatar image jeffvoigt Jun 01 '15 at 07:53 PM

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 0*1 = 0, then 1*1=1, then 2*1=2, etc. Those delays are all building up instantly.

avatar image jeffvoigt Jun 01 '15 at 07:54 PM

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.

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

I created two new macros called "For Each Loop With Delay" and "For Loop With Delay"

The Macros can be downloaded here:

https://drive.google.com/open?id=0B7ELSXWU1omeMElwYmE2S1pKRHc

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:

alt text

Here is the "For Each Loop With Delay" Logic:

alt text

flwd.png (352.5 kB)
felwd.png (348.3 kB)
more ▼

answered Aug 08 '17 at 08:09 AM

avatar image

Miroac
718 20 25 108

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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.

  1. Create your own custom macro using the blueprint macro library

  2. Copy all the features of the "for each loop" or "for each loop with break" whatever you want to add a delay to

  3. Add 1 extra input (float) to be used as the delay

  4. Add a delay node following the "Assign" that loops back to the branch node

  5. Hook the input float into this delay

Here is a tutorial showing how to do this for those of you who prefer that instead.

https://youtu.be/zh8xx9abzZY

Simple and now you have a custom "Loop with Delay" that you can set when calling the macro itself.

alt text

more ▼

answered Apr 08 '18 at 02:58 PM

avatar image

Nebula Games Inc
4.9k 27 9 14

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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.

alt text

capture.png (287.1 kB)
more ▼

answered Feb 01 '17 at 10:20 AM

avatar image

hiili
205 15 24 37

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

You can use "set timer by event" for less messy graph alt text

loop-delay.png (127.7 kB)
more ▼

answered Apr 05 '18 at 10:01 AM

avatar image

laggyluk
111 13 18 29

avatar image laggyluk Apr 05 '18 at 10:03 AM

usable only on main graph tho

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

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)

more ▼

answered Apr 08 '18 at 02:39 PM

avatar image

FrederickD
96 2 5 9

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question