Set Timer function not calling delegate

Hello everyone :slight_smile:

I am trying to implement a simple slap functionality using a timer. It happens that when I try to run the SetTimer function, the delegate that I passed to the argument isn’t executing what is inside it.

Here is my .h file


UCLASS()
class PRACTICE_API ABP_FirstPersonCharacter : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	ABP_FirstPersonCharacter();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Enhanced Input")
	UInputMappingContext* InputMappingContext;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Enhanced Input")
	UInputAction* SlapAction;


public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	void TriggerSlap(const FInputActionValue& Value);
	
	UFUNCTION(BlueprintCallable)
	void StartHittingTimer();
	
	UFUNCTION(BlueprintCallable)
	void StopHittingTimer();

	UFUNCTION()
	void HitPlayer();
	
	FTimerHandle TimerHandle;
	
	UPROPERTY(EditAnywhere, Category="Slap")
	float SlapDelay;

	UPROPERTY(EditAnywhere, Category="Slap")
	UAnimMontage* SlapAnimMontage;
};

And here is my .cpp file

ABP_FirstPersonCharacter::ABP_FirstPersonCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void ABP_FirstPersonCharacter::BeginPlay()
{
	Super::BeginPlay();

	if (APlayerController* PC = Cast<APlayerController>(GetController()))
	{
		if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
		{
			Subsystem->AddMappingContext(InputMappingContext, 0);
		}
	}
}

// Called every frame
void ABP_FirstPersonCharacter::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void ABP_FirstPersonCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
	{
		EnhancedInputComponent->BindAction(SlapAction, ETriggerEvent::Triggered, this, &ABP_FirstPersonCharacter::TriggerSlap);
	}
}

void ABP_FirstPersonCharacter::TriggerSlap(const FInputActionValue& Value)
{
	PlayAnimMontage(SlapAnimMontage, 0.8f);
}

void ABP_FirstPersonCharacter::HitPlayer()
{
	FHitResult Hit;
	
	FVector start = GetMesh()->GetSocketLocation("clavicle_r");
	FVector end = GetMesh()->GetSocketLocation("RightHandMiddle4");

	UE_LOG(LogTemp, Display, TEXT("Loop"));
	
	FCollisionQueryParams TraceParams;
	GetWorld()->LineTraceSingleByChannel(Hit, start, end, ECC_Visibility, TraceParams);

	DrawDebugLine(GetWorld(), start, end, FColor::Red, false, 2.0f);
}

void ABP_FirstPersonCharacter::StartHittingTimer()
{
	GetWorldTimerManager().SetTimer(TimerHandle, this, &ABP_FirstPersonCharacter::HitPlayer, 1.0f,  true);

	UE_LOG(LogTemp, Display, TEXT("Test"))
}

void ABP_FirstPersonCharacter::StopHittingTimer()
{
	GetWorldTimerManager().ClearTimer(TimerHandle);
}

I tried adding some logs to see exactly what is executing, and the log within the HitPlayer function is not executing while the log after calling set timer is executing properly.

I’m kinda new to cpp programming in unreal engine so I am kind of lost and have literally no idea what should be wrong.

Thank you all guys in advance, I’m hoping that you could give me some help here :slight_smile:

I presume that in BP, you are calling StartHittingTimer.

One possibility is that the StopHittingTimer (apparently also called from BP), is being called prior to the HitPlayer timer firing off. Might put a UE_Log in StopHittingTimer and see if it’s being called immediately after Timer is set. If so, the problem is in the BP.

Thank you for your response!
Yes you are right I am calling it from a play anim montage using AnimNotifyState BP.
I tried removing the call of StopHittingtimer and the delegate is still not being called. Also tried to add the timer in the BeginPlay event and still had no success on making the delegate being called.

I might be tempted to put a GetTimerElapsed somewhere (like in Tick) to just see what’s happening with it. Like check if the TimerHandle is valid and log a “not valid” if not, or if it is, print out the current elapsed time. If it’s actually kicking off, you would get a string of non-valids, followed by the timer countdown, then return to non-valids after it’s done.

Edit: I was actually thinking of GetTimerRemaining rather than elapsed, but either might suffice to see how the timer is running.

Thank you for the idea.

I did what you said and the time remaining value that i am getting is -1.000000

Also tried to check if timer handle is valid all over the code and seems that it is not so I assume that the problem might be on the TImerHandle that is not being validated somehow

This probably won’t help but I do recall in the distant past, the recommendation to clear the timer handle immediately prior to the SetTimer:

    GetWorldTimerManager().ClearTimer(TimerHandle);

Also just for testing, I’d comment out the ClearTimer in StopHittingTimer() until you’ve determined why your delegate isn’t firing.

Yeah I’m trying to debug with the ClearTimer commented on the StopHittingTimer.

Tried to clear timer right before setting the timer and it doesn’t seem to make my TimerHandle valid. I am probably missing something that I have no idea what it is, as this is my first time making a Timer on c++.

After you hit the key to start your timer (or however you are initiating it), press ~ and type listtimers. See if your timer is in the list.

I was also curious that you show no includes in either your .h or .cpp files. That should produce compile errors so I’m sure you just didn’t show those. Normally I’d expect to see a .generated.h in the h file and the actual name .h in the cpp file.

It makes no sense, but I would superstitiously use a name other than TimerHandle since that is extremely common in the engine. I call it something related to it’s function, like TriggerDownTimer etc.

It’s going to be something I’m not seeing in your attachments so I’m just tossing out debugging ideas.

1 Like

Oh maaaan thank you so so much!
I’ve been struggling on this throughout the whole day. It really was a naming problem. I changed to SlapTimerHandle and worked instantly. Again thank you so much!

That’s a surprise, but glad it worked. The timermanager.cpp as such identical naming, maybe something about that.

Yeah, its kinda strange for me as I think that never happened to me in 3 years of coding experience

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.