[REQUEST] New 'Wait For New Tick' Blueprint Node

Could you post a screenshot of a couple blueprints where you are using your macro, and how you would like it to work? Like what do they look like in a couple of your enemy blueprints?

Edit: It just seems like there may be some misconceptions about how things are built to work.

Just to clarify, at the moment I want to add it into a custom ‘ForEachLoop’ and ‘ForEachLoopWithBreak’ loop that I call ‘ForEachLoopWithDelay’ and ‘ForEachLoopWithBreakAndDelay’

In both of these if I’m checking an array I can specify a time between checks in seconds…

… but I want to do every tick, there is a place holder delay of 0.05 seconds (1/30th of a second) mimicking for now.

The reason why a delay is a problem is that it results in wasted ticks at high framerates and can make slow framerates slower.

Alos, my LoS check runs as a Service every 0.033 seconds (~30 times a second) and will suffer from the same problem when I’m dealing with maps with hundreds of active characters.

Posting pics of what I’m doing with my arrays is pointless because of their size and complexity.

Now, I can’t create a function to do alone because the function won’t accept the Event Recieve Tick.

I can only see myself getting new Node if anyone that does work with AI in code or any other Level Designers are used to being able to wait for the current frame to end before progressing in order to optimise their work as efficient as possible can validate approach.

can you get closer in on the second blueprint, I cant see much of anything. Oh and what blueprint is that? A few pictures of that second blueprint would help.

Edit: and yeah I knew what you were doing in that first blueprint, I was more wondering where you were using that macro. I am guessing it’s in that second blueprint that i can’t really see.

Edit: also from here it looks like you are making that view cone check is much more complicated than need be. That’s if it’s doing what I think it is haha

I may have a way that is much faster than what you are doing. When you re post that blueprint I will take a look and see if it will help.

Yup, that’s my first pass of a view cone. It’s an odd way that uses the ‘Get Actor Rotation’ and ‘Find Look At Rotation’ and includes a work around for Rotators giving results outside of the -180~180 range. I’ve seen a simpler version on these forums and also Epic’s perception system and will be investigating both of these options soon.

There will be many different ways I can optimise alot of my AI as tis is my first attempt, and the Tick distribution method doesn’t mean I’m not going to look into any other optimisations. Nor will any optimisations I do make the Tick optimisations pointless. I admit I am thinking ahead with request, but it’s such a commonly used command in scripting that I’m suprised it’s not already in Blueprints and that noone else has requested it yet.

The current work around is labour intensive and would involve sequences in AI and Level Blueprints coming from Ticks with alot of Nodes on them, nor could it be condensed into a single Macro because it requires the use of the Recieve Tick Event, whether you use Gates or count Ints to determine if the current tick has ended.

I think the reason is that most people are using the tick event. Could you please post a few screen shots of that second blueprint so I see where you are using your forloop. Also what blueprint is in, your enemy parent blueprint, AI,…?

I think you want ? has a heartbeat technique that can be used for any type of cyclic event you need. Basically… IS how Wait for Specific Duration Tick should be done.
You can also save your info as well.

Persistent Time (many uses for persistent data) FREE! - Blueprint - Epic Developer Community Forums!

Here is how I get the array of actors in range of the character. It is much faster than calling get actors in range every tick. Instead you already have the array of actors in range. Then the only time the array changes is if one of the characters is destroyed, or end’s overlap. The overlap sphere is a spherecomponent I have added to the components.

The first part of the sequence is setting up the actors that are in range when the character first spawns. For some reason I am not sure why that part wasn’t needed when I first created it. Instead the characters that were overlapping would get the overlap function at the start. Not sure why it changed as I didn’t change anything. I might change the order so it adds the characters in range last, and clears the array before that just to make sure it works as intended.

Then in the tick event I can access that array and if needed and loop through it. removes the need to call get all actors in range every frame which is much slower.

That is in my parent character blueprint. Then I can post what I do in the parent character tick event also, but if you post what you are doing in your blueprint I can explain it so it works for yours also.

1 Like

DarkHorror. That is awesome. Basically a high performance Perceive Event. Thank You for posting !

I will leave the question as to if is the best solution to other people, but if you want a blue print node that will delay a action until the next tick/frame, then it is quite easy to do using c++. As you said you use c++, I’m taking it that you don’t need a solution for a blueprint only project.

If you look at the code for the Delay node then it is quite simple.





class FDelayAction : public FPendingLatentAction
{
public:
	float TimeRemaining;
	FName ExecutionFunction;
	int32 OutputLink;
	FWeakObjectPtr CallbackTarget;

	FDelayAction(float Duration, const FLatentActionInfo& LatentInfo)
		: TimeRemaining(Duration)
		, ExecutionFunction(LatentInfo.ExecutionFunction)
		, OutputLink(LatentInfo.Linkage)
		, CallbackTarget(LatentInfo.CallbackTarget)
	{
	}

	virtual void UpdateOperation(FLatentResponse& Response)
	{
		TimeRemaining -= Response.ElapsedTime();
		Response.FinishAndTriggerIf(TimeRemaining <= 0.0f, ExecutionFunction, OutputLink, CallbackTarget);
	}

#if WITH_EDITOR
	// Returns a human readable description of the latent operation's current state
	virtual FString GetDescription() const OVERRIDE
	{
		return FString::Printf( *NSLOCTEXT("DelayAction", "DelayActionTime", "Delay (%.3f seconds left)").ToString(), TimeRemaining);
	}
#endif
};


The UpdateOperation method is called every frame/tick, and then triggers when the delay time has elapsed. If you wanted it to trigger on the next tick, in principle you would just need to change the


Response.FinishAndTriggerIf(TimeRemaining <= 0.0f, ExecutionFunction, OutputLink, CallbackTarget);

to


Response.FinishAndTriggerIf(true, ExecutionFunction, OutputLink, CallbackTarget);

However that doesn’t always quite work, as it seems that the UpdateOperation is sometimes called (later) in the same frame as the delay was added. For example happens if the delay was called from the “Receive Tick” event, because the LatentActions are ticked after the “Receive Tick” event is called.

Anyway that would be easily fixed by just waiting for two calls to the UpdateOperation method when used in a Received Tick event. Or if you wanted the callback to be called on every tick, then change the Response.FinishAndTriggerIf line to :


Response.TriggerLink(ExecutionFunction, OutputLink, CallbackTarget);

However one problem with is there would be no way to ever stop it from triggering on every tick. Still that might be what you want.

Of course you don’t need to change the actual delay node, but can rather add a new node. The following two files included in a standard project will add a “RepeatEveryTick” node that triggers on every tick, and a “DelayForTicks” node, that allows the number of ticks to wait to be set. If you want it to wait for the next tick, then you would normally set 1, unless you called it from the “Receive Tick” event.



////////LatentBlueprintLibrary.h////////
#include "LatentActions.h"
#include "DelayAction.h"
#include "LatentBlueprintLibrary.generated.h"

#pragma once

/**
 * 
 */
UCLASS()
class  ULatentBlueprintLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_UCLASS_BODY()

public:

	UFUNCTION(BlueprintCallable, Category = "Utilities|FlowControl", meta = (Latent, HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject", LatentInfo = "LatentInfo"))
		static void	RepeatEveryTick(UObject* WorldContextObject, struct FLatentActionInfo LatentInfo);

	UFUNCTION(BlueprintCallable, Category = "Utilities|FlowControl", meta = (Latent, HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject", LatentInfo = "LatentInfo", Ticks = "1"))
		static void	DelayForTicks(UObject* WorldContextObject, int32 Ticks,  struct FLatentActionInfo LatentInfo);
};


class FRepeatTickAction : public FPendingLatentAction
{
public:
	FName ExecutionFunction;
	int32 OutputLink;
	FWeakObjectPtr CallbackTarget;

	FRepeatTickAction( const FLatentActionInfo& LatentInfo)
		: ExecutionFunction(LatentInfo.ExecutionFunction)
		, OutputLink(LatentInfo.Linkage)
		, CallbackTarget(LatentInfo.CallbackTarget)
	{
	}

	virtual void UpdateOperation(FLatentResponse& Response)
	{
		Response.TriggerLink( ExecutionFunction, OutputLink, CallbackTarget);
	}

#if WITH_EDITOR
	// Returns a human readable description of the latent operation's current state
	virtual FString GetDescription() const OVERRIDE
	{
		return FString::Printf(*NSLOCTEXT("RepeatAction", "RepeatActionTime", "Repeat").ToString(), 0);
	}
#endif
};

class FDelayTicksAction : public FPendingLatentAction
{
public:
	int32 TimeRemaining;
	FName ExecutionFunction;
	int32 OutputLink;
	FWeakObjectPtr CallbackTarget;

	FDelayTicksAction(int32 Duration, const FLatentActionInfo& LatentInfo)
		: TimeRemaining(Duration)
		, ExecutionFunction(LatentInfo.ExecutionFunction)
		, OutputLink(LatentInfo.Linkage)
		, CallbackTarget(LatentInfo.CallbackTarget)
	{
	}

	virtual void UpdateOperation(FLatentResponse& Response)
	{
		TimeRemaining -= 1;
		Response.FinishAndTriggerIf(TimeRemaining <= 0, ExecutionFunction, OutputLink, CallbackTarget);
	}

#if WITH_EDITOR
	// Returns a human readable description of the latent operation's current state
	virtual FString GetDescription() const OVERRIDE
	{
		return FString::Printf(*NSLOCTEXT("DelayTicksAction", "DelayActionTicks", "Delay (%d ticks left)").ToString(), TimeRemaining);
	}
#endif
};




////////LatentBlueprintLibrary.cpp////////
#include "Myprojectheader.h" //change to the standard header for your project
#include "LatentBlueprintLibrary.h"



ULatentBlueprintLibrary::ULatentBlueprintLibrary(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{

}

void ULatentBlueprintLibrary::RepeatEveryTick(UObject* WorldContextObject,  FLatentActionInfo LatentInfo)
{
	if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject))
	{
		FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
		if (LatentActionManager.FindExistingAction<FRepeatTickAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == NULL)
		{
			LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FRepeatTickAction( LatentInfo));
		}
	}
}

void ULatentBlueprintLibrary::DelayForTicks(UObject* WorldContextObject, int32 Ticks, FLatentActionInfo LatentInfo)
{
	if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject))
	{
		FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
		if (LatentActionManager.FindExistingAction<FDelayTicksAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == NULL)
		{
			LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FDelayTicksAction(Ticks, LatentInfo));
		}
	}
}


Thanks Matt. I’ve not actually used C++ (see above) but some C# and don’t currently plan on starting with C++ anytime soon (Visual Studio). Any of getting the above new Node as a plug-in? If you’re in the UK then I will pay handsomely in booze :slight_smile:

DH, thank you, that radius check looks great. I’ll look into replacing my Vector Lengths with that. But it’s not the radius checks I’m worried about. The results of my radius checks would be put into an array and each of those would then go into view cone and line checks to see what’s visible. Line checks are where things start to get expensive when you’ve got alot of active characters.

Krixa, thanks for the link, but I can’t see how deals with individual ticks because all calculations are done from delays that you can set in time. To handle an individual wait for a tick you need something like :

The problem is that easily gets out of control when I’m referencing several 100 times in a Level Blueprint, nor is it possible to condense it down into a single macro.

What are you referencing several hundred times in the level blueprint, why are you using a level blueprint for things like ?

Here is a way to check what is in the view cone that though doesn’t tell you if they are being blocked by something does tell you if you may be able to see them. Once you get that the enemy is in the cone then you can do a line trace to the enemy to see if you can see them. You can ignore that line trace at the start there.

if that float value is equal to 1 it means it’s directly in front of you -1 means it’s directly behind you. Anywhere between is similar to the angle you want. So >= .3 gives me a reasonably wide but not 180 degree view cone. If I wanted 180 degrees, I would see if the value is >= 0. is in the same creature parent blueprint.

Is there some reason you can’t post a closer in view of what you are doing? It just sounds to me that you may be setting things up in a way different than how they should be setup in UE4.

Edit: oh one other thing you can do is rather than setting up a sphere radius that goes all around the character you can put it in front of the character in the area you are looking. Then all you need to do is line trace for visibility as you already know you might be able to see those actors. You are then simply checking if something else is blocking them.

Hi Jimmy_Jazz.

I shall explain a little better. In logic controllers and some other specialized controllers there is no such thing as events and real time clocks. So basically you have to create your own ‘ticks’ and events based upon some amount of time. In our case UE4 has a time capsule of 1 frame that is dependent upon the performance of the computer…and changes depending upon loading. Update Rate or Frame Time can be specifically used to create very dependable Events/Ticks.

So the method I proposed is simply a 50ms Tick which is quite fast in the normals of a game. If you need faster then you could do a 25 or 30ms tick but then you may end up running into RAM and HDD issues or when your computer is getting laden you could not catch up to the Tick.

It appears that the frame time (Delta Seconds) is the previous frame length…no matter…we simply add that in the current frame and then again and again until that eclipses Your set Tick (in my case 50ms) which happens at or near the end of the frame. There you have it, throw to stones in one toss. Cyclic Events and End of Frame Tick.

In any case use what you think is best. I am just giving a very good option that works in other things besides gaming platforms.

Cheers
K

As I’ve said multiple times before, one of the ways I’ll using the node is to space out spawns over ticks and I will be spawning alot of enemies in my levels. I need to investigate how many I can spawn per tick first though.

There is no right or wrong way, but some will be more efficient than others and I’m going through that learning process at the moment. But none of that stops makes tick optimisations worthless.

Line traces are generally an expensive thing to do so I would approach the LoS different from what you’re doing. If you’ve already got an array of targets based on radius then I would perform a view cone check on all of them and add everything in the view cone to a new array.

Then I would run that new array through a Loop that does a Line Trace to each target. And If I had the Node I requested I would put a tick delay between each Line trace because I know that there will be a substantial amount of characters running behaviour similtaneously.

Because I’m continually developing and improving things on a daily basis and until they’re better, I am going get caught up in kind of side tracking. I have been clear about why I want to tackle things on a tick by tick basis as opposed to use delays.

Krixa, you’ve got a great system there but it’s not quite what I’m after. You’re making sure that ticks fire at regular intervals, but if the framerate is higher than the tick rate then you’ve got ticks doing nothing and if the framerate is lower than the tick rate you’ve got ticks doing double the work.

50ms is 20 times a second. Assuming you’re running at 30fps then that’s 10 frames in which nothing is happening. And if you drop below 20fps then there will be at least one frame performing the check twice. And that’s also my problem with the time based Interval rate in the Behaviour Tree.

MattW has been kind enough to provide me with the Code for the Node and I now just have to find a way of getting it into my editor without relying on Visual Studio.

If my results for getting alot of characters to move around are a success in the long term then I will document the methods and turn them into guides for advice and scrutiny.

I will try to create a plugin at some point, but really have no idea when I will get the time. I haven’t created a separate plugin since version 4.0, and back then there was difficulty getting standalone plugins to work in the shipping builds and content only projects. I think there are ways to make it work now, but I would have to find those posts and read how to do it. Which I just don’t have the time for in the next few days at least.

Do you have Visual Studio installed ? Did you use it when you used C#?

The quickest way to get these working would be:

  • backup your project
  • install Visual Studio (the Express version will do).
  • Then in the UE4 editor, in the file menu, pick “Add code to project”.
  • In the Add code wizard that opens, leave the parent class as “None”. Click next.
  • Change the class name to “LatentBlueprintLibrary”. Click Create class.
  • After a few seconds or so, it will ask if you want to edit the files in visual studio. Select yes.
  • Once Visual Studio opens. Close the UE4 editor and Open the files “LatentBlueprintLibrary.h” and “LatentBlueprintLibrary.cpp” in visual studio (from right side window)
  • Delete everything that is in those two files.
  • Copy the two code sections from my above post to the corresponding file. [First big code section has ////////LatentBlueprintLibrary.h//////// as first line so that goes in the “LatentBlueprintLibrary.h” file. The next section of code goes in the “LatentBlueprintLibrary.cpp” file.
  • Now in the "LatentBlueprintLibrary.cpp, the second line is “include “Myprojectheader.h” //change to the standard header for your project”. You need to change the “Myprojectheader” part to whatever the name of your project is. In the right side window of Visual Studio, you should see a file named “WhatEverMyProjectIsCalled.h”, so that line should match that. [ex include “WhatEverMyProjectIsCalled.h”]
  • Then from the Build menu select “Build Solution”.
  • Once the build has finished and it says it has succeeded, then you can reopen the UE4 editor, and in your blueprints , you should be able to find the two new nodes.

Just use the tick event, you can create a method that you can put into that tick event. You could set it up with some variables like how many you want to spawn per tick, the class you want to spawn.

Like I said, ignore that line trace, in the actual code there is a branch statement before that which checks to see if character already has a target, if it does it does the line trace to see if it can still see, if it can’t then it does the Cone search. Instead of putting them in another array and going through a second loop all of which time. Instead you might want to do the line trace if that branch is true. Though on mine I simply break once the character finds a target it can see

These are just ideas that might help you out.

You have been clear about why you want to tackle a tick by tick basis. I am just trying to figure out how you are using so I can see why you don’t want to use tick event. That’s why I want to see the blueprint of where you want to do tick by tick behavior.

If I can only use a Tick event then I’m going going to be stuck with 100s of pins in my levels. Here’s an example of a simple wave spawner for 5 guys, with a wait for tick between each that uses the Tick Event and a Gate

Zoomed in:

Zoomed Out:

Now I do have a way of streamlining the spawning (which is why I didn’t want to get bogged down in my prototype methods) so that I only need 1 tick event per wave, but there will also be different wave variants depending on the difficulty setting and there will be alot of these per level.

It’s been suggested that I use a counter system, but as far as I can tell, such a system would be pointless because you’re always going to need a Recieve Tick event to drive the check or you’re stuck using time (and not frame based) delays to recheck the counter periodically.

055bea9db534b6a3b27584e461ef7ae8e6810776.jpeg

And I cannot incorporate an Event Recieve Tick into a Macro either, so if I want to add Tick delay between checks in an array then I am also dependant on a tick event

The only way I can see to remove the dependancy on an excess amount of Sequence Node outputs coming off after a Event Recieve Tick is to have a Wait For New Tick / Wait For Tick To End node.

When it comes to AI, I won’t need as many pins, but then a Node would slot easier into arrays.

So to use tick to do what you want and loop through all those items you have placed in the level. You would create a counter, you check to see if the counter is less than the length of the array of items you want to go through. If it is then get the item in that array index. Then do what ever you want to do with that item on that tick. Finally add one to the counter.

But what I would do is not put in the level blueprint and not do it that way at all. You have all these items in the level that you want to do . I would just have it’s parent class setup the AI for it’s self. Since it’s only happening once at the start I wouldn’t worry about the speed of it to much.

New Design Approach, Not a Single Node

I dont think a single node is the real solution here, what you need is a new design approach.

Your fundamental goal is to break up complex operations over several ticks!

Usually such operations involve a loop of some kind, or a series of ordered steps.

What you should do is create a BP Variable Int that tracks what phase of the process you are in, or what loop iteration you are doing out of a max count that you also store as a variable.

Then, in your tick function, you process a few “chunks” of your total operation, several loop cycles or several steps of your whole process, and increment your int that is tracking where you are.

Then, once you reach the max count / finished loop cycles / last step, you then end the operation and no longer tick it until the process starts again.

No single node can really do proper programming systems for you, you have to learn programming design structures, because Blueprints really are a programming language!

People using blueprints should realize they are actually programmers now, and there are basic design principles of programming that you can follow and translate into Blueprints to enable Blueprints to do amazing things

:slight_smile:

Rama