Delay not working while game is paused

Hello, I’m trying to add a widget to viewport right before opening a level; The thing is that if I add the widget and then open the level, the widget doesn’t show, so I added a delay between adding the widget and opening the level and now the widget shows but the level never opens because the delay never completes. All this is done while the game is paused. I thought delays were supposed to work while paused? Is it a bug or what am i doing wrong?

I’m using 4.8.3.

1 Like

Ordinary blueprint actors have an option to “Tick Even when Paused”, which you can enable in the Details Panel after pressing the Class Defaults button in the BP editor.

Widget blueprints however do not have this option.

Use this information to your advantage.

1 Like

Thanks, added the logic inside another actor’s function and called that function from within the widget and it worked.

and the mystery about delays not working on pause stills lives on and on…

1 Like

Solving the mystery. Warning: Engine Code Details (and modifications) follow:

Calling Delay creates a Latent Action owned by the blueprint that is calling Delay. (1)

If the owner is an Actor, that Actor’s tick function will update its own Latent Actions (2)

All other Latent Actions are updated by the general update - but only if not paused (3)

So, as currently implemented:

  • Delays (and other latent actions) in Actor blueprints will work as expected with pause / set tickable when paused.
  • Latent actions in any other types of blueprints (Actor components, widgets, etc) will not execute when paused.

** To allow paused ticking for ActorComponents (which fixes a huge majority of the other blueprintables where this might occur), I edited
ActorComponent.cpp ::TickComponent to add

// Update any latent actions we have for this actor
GetWorld()->GetLatentActionManager().ProcessLatentActions(this, DeltaTime);

For UI:

UserWidget in UserWidget.cpp ::TickActionsAndAnimation() also updates its own Latent Actions (and is the only other place where that is already being called)

Because of the way UserWidgets are implemented, however, there’s no place to go to the class settings to set the Tickable when Paused flag. The User Widget itself is not an ActorComponent at all, so doesn’t have access to that variable. It is contained by a WidgetComponent - which is the actual component added to the Actor - and there’s no way that I know of to change the class settings on a member component.

** Instead, the owner actor blueprint needs to get the WidgetComponent object, and use the “Set Tickable when Paused” blueprint node from Event BeginPlay (or whenever)


For Skeletal Animation:

Skeletal Mesh Components actually are set by default to be ticked while paused. There’s a followup issue, for actually animating, though.

SkeletalMeshComponent::ShouldTickPose() checks if the pose has already been ticked this frame. Among other things, it does this by testing LastPoseTickTime == GetWorld()->TimeSeconds via PoseTickedThisFrame()
However, World :: TimeSeconds is not getting updated while paused, so even with the above fixes, ShouldTickPose will always return false!

A fix for this is to replace the usage of LastPoseTickTime - instead of using GetWorld()->TimeSeconds, change to use the global GFrameNumber. This gets incremented regardless of pause timing. I did note that there are several other uses of World::TimeSeconds in the same manner. ie UWidgetComponent has similar comparison logic in ::ShouldDrawWidget()

SkeletalMeshComponent.h
-	float LastPoseTickTime;
+	uint32 LastPoseTickFrame;
SkeletalMeshComponent.cpp
::USkeletalMeshComponent()
-	LastPoseTickTime = -1.f;
+	LastPoseTickFrame = 0;
::TickPose()
-		LastPoseTickTime = GetWorld()->TimeSeconds;
+		LastPoseTickFrame = GFrameNumber;
::PoseTickedThisFrame()
-	return LastPoseTickTime == GetWorld()->TimeSeconds; 
+	return LastPoseTickFrame == GFrameNumber;

For FX:

Spawn Emitter Attached will have a similar problem.
Quick fix is to get the returned object, and use the Set Tickable when Paused blueprint node.
A probably best fix is to have any spawned emitters inherit the attached object’s tickable when paused. (This would probably be a nice, separate flag to implement for all actors: Tick all children when paused)


(1) - see KismetSystemLibrary.cpp ::Delay(…)

(2) - Actor.cpp :: Tick(…) “…ProcessLatentActions(this, DeltaSeconds);”

(3) - LevelTick.cpp ::Tick(…) " if(!bIsPaused) …ProcessLatentActions(NULL, DeltaSeconds);"

2 Likes

Hey guys,
Just found this post in looking for answer why my GameState doesn’t tick delay while paused, even with TickEvenWhenPaused set to True.
What actually fixed the issue for me was when I put print string on Event Tick, and suddenly it started working.
Works even without any exec going from EventTick now.

I Hope it’s not random ^^

2 Likes

I noticed this on UE 5.1.1 too.

What’s weird, is that the simple fact of having “Event Tick” in your graph makes your delay nodes work even when the game is paused.

3 Likes

For me none of these workarounds worked in a widget blueprint. Had to make my own “manual timer” with a tick event and then recording the real time seconds when constructed and then comparing this to when the event should fire in tick. Not the most efficient way, but it works for simple things that aren’t going to be on-screen forever.

Did verify via “Print String” that widgets tick when paused even if the actor that spawns them does not tick if paused. Though to actually interact with them the Player Controller will need to tick when paused (the default).