SetTimer with parameters

I’m trying to call a function with a delay using GetWorldTimerManager().SetTimer(), but I’m having trouble figuring out the syntax for passing a parameter. This is what I have right now:




DECLARE_DELEGATE_OneParam( RespawnDelegate, APlayerController* )

void AMyGameMode::RespawnPlayerWithDelay(APlayerController * Player, float Delay)
{
	RespawnDelegate MyDelegate(???);
	GetWorldTimerManager().SetTimer(???, Delay, false);
}

void AMyGameMode::RespawnPlayer(APlayerController * Player)
{
	// Do stuff
}


After looking around a bit I found that I need to declare a delegate with one parameter and pass that to SetTimer, but I can’t figure out the syntax. Does anyone have a pointer or working example? Thanks!

1 Like

Does anyone have the answer? I currently jump from c++ to BP just to set the timer but I really want it working in c++…

SetTimer doesn’t take arbitrary delegates. The function signature that matches the call you’re trying to make takes a TimerDelegate and TimerDelegates don’t take parameters.

Here’s an approach that should do what you want. First, create a subclass of APlayerController. For example purposes I’m going to call it AMyPlayerController but you might want to call it something different. Inside of your new player controller class you will need to implement the respawn function. This can just call the function you’ve already got in AMyGameMode if you want.



class AMyPlayerController:: public APlayerController
{
	void Respawn();
	FTimerHandle RespawnTimerHandle;
}


Now you’ll need to update your RespawnPlayerWithDelay function to call AMyPlayerController::Respawn. It should look something like this:



void AMyGame::RespawnPlayerWithDelay(APlayerController* Player, float Delay)
{
	AMyPlayerController* MyPC = Cast<AMyPlayerController>(Player);
	GetWorldTimerManager().SetTimer(MyPC->RespawnTimerHandle, MyPC, &AMyPlayerController::Respawn, Delay);
}


In this version, the first parameter I gave to SetTimer is a TimerHandle. If you don’t need to use the timer handle later you could also use a temporary one instead of storing it in the player controller. The advantage of keeping it is that you can use it to ask the timer manager how much time is left on the counter and use this for things like displaying a countdown in the UI. The next parameter is a pointer to the object it is going to call the function on. In this case we want it to be on the player controller that is associated with the player we’re going to respawn. The next parameter is the function we’re going to call. Finally we have the delay until we call the function. I hope this clears things up.

But they do accept payloads, which should work in this case since the desired player controller is known at bind time:



void AMyGameMode::RespawnPlayerWithDelay(APlayerController * Player, float Delay)
{
	FTimerDelegate RespawnDelegate = FTimerDelegate::CreateUObject( this, &AMyGameMode::RespawnPlayer, Player );
	GetWorldTimerManager().SetTimer( RespawnDelegate, Delay, false );
}

2 Likes

Thanks for your answers, both of you. Sorry for not looking back sooner. , your code worked perfectly, thanks! I’m glad I can do this in C++ too now.

For others who find this thread looking to achieve a similar feature, in my final solution I’m also passing an FTimerHandle to ensure that rapid subsequent calls don’t reset the timer causing only one call to get through. Josh Markiewicz said here:

So my final code looks like this:



void AMyGameMode::RespawnPlayerWithDelay(APlayerController * Player, float Delay)
{
	FTimerHandle UniqueHandle;
	FTimerDelegate RespawnDelegate = FTimerDelegate::CreateUObject( this, &AMyGameMode::RespawnPlayer, Player );
	GetWorldTimerManager().SetTimer( UniqueHandle, RespawnDelegate, Delay, false );
}


2 Likes

Yeah, it turns out I was just bitten by this myself. Had multiple timers calling the same delegate with different payloads, but only the last one actually fired. Thankfully I remembered your follow-up so it didn’t take much time to figure out what was happening. :slight_smile:

Hello guys I have similar problem but a little different, I use this function and it’s working but i can change parameter from another functions it’s a loop timer and i want to change parameter in different states.

in .h :


FTimerHandle MyTestTimer;
FTimerDelegate MyTestDel;

void MyTestFunc(float NewVal);

float MyTestDynamicParam;

in .cpp:


MyTestDel.BindUFunction(this, FName("ModifyHunger"), MyTestDynamicParam);
GetWorldTimerManager().SetTimer(MyTestTimer, MyTestDel, 1.0f, true);

the problem is NewVal in MyTestFunc is always 0, but i changing MyTestDynamicParam continuously from other functions.

1 Like

This is a really old post but was relevant for me but I did find one minor issue with FTimerDelegate::CreateUObject with parameters when there are cv-qualifiers. The variadic template on this function does not perfect forward the arguments, so if you pass by reference or const-reference you will get a compiler error unless you explicitly specify the template arguments:

Example:

class MyUObjectClass
{
   void MyMethod(const FString& s);
}

Then when creating the timer delegate within a member function of MyUObjectClass, this won’t compile:

namespace
{
   const FString MyFileLocalStringVariable = "MyString";
}

/// .... In some other member function of MyUObjectClass:

    auto TimerDelegate = FTimerDelegate::CreateUObject(this, &ThisClass::MyMethod, MyStringVariable);

However, if you explicitly specify the template arguments, it will compile:

    auto TimerDelegate = FTimerDelegate::CreateUObject<ThisClass, const FString&>(this, &ThisClass::MyMethod, MyStringVariable);

Note for those unfamiliar ThisClass is a typedef for the current class which is a nice shortcut. Note, that you do need to be on the lookout for dangling references if you do pass things by reference to the UObject delegate; however, it is useful if you know the scope of that delegate will not outlive that of the UObject and you don’t want to pay for making a copy of the variable. In my case, I had the variable in an anonymous namespace in the C++ class which is a file-scoped variable that has static storage duration.

1 Like