New to timers in c++, keep getting an error

Hello, I am currently trying to set up a dodgeroll function for my character, I am currently using timers to set the movement speed. The logic is that when the Dodgeroll button is pressed, movement speed is set to 1000 for a second, then afterwards it is set back to 600, with the timer being reset.

Here’s the error:
error LNK2019: unresolved external symbol “protected: void __cdecl ACPPHeroCharacter::CheckPriorityRefresh(void)” (?CheckPriorityRefresh@ACPPHeroCharacter@@IEAAXXZ) referenced in function “protected: void __cdecl ACPPHeroCharacter::DodgeRoll(void)” (?DodgeRoll@ACPPHeroCharacter@@IEAAXXZ)

Here is the .h file where the function is stored…

protected:

	//Moves the Player Forward
	void MoveForward(float Value);

    //Moves the Player Right
	void MoveRight(float Value);

	//Moves camera right
	void MoveCamRight(float Value);

	//Moves Camera up
	void MoveCamUp(float Value);

	//DodgeRoll
	void DodgeRoll();

	//Attacks
	void LightAttack();
	void HeavyAttack();

	//Timers
	void CheckPriorityRefresh();

And here is the Cpp file that I am using.

void ACPPHeroCharacter::DodgeRoll()
{
	FTimerHandle time_handler;

	GetCharacterMovement()->MaxWalkSpeed = 1000.0f;
	GetWorldTimerManager().SetTimer(time_handler, this, &ACPPHeroCharacter::CheckPriorityRefresh, 1.0f, false);
	GetCharacterMovement()->MaxWalkSpeed = 600.0f;
	GetWorld()->GetTimerManager().ClearTimer(time_handler);
}

Any why this error is occurring? Does it have to do something about the DodgeRoll() and CheckPriorityRefresh() being void? Any advice would be appreciated.

I don’t see any obvious syntactical errors. Did you create the implementation of CheckPriorityRefresh()?

As for the logic, this will not give you the desired behaviour. You should move the last two lines into the CheckPriorityRefresh() function, otherwise your character’s speed will just be set to 1000 and a millisecond later it will be set back to 600, and the timer will be cleared, causing it not to fire at all. The code won’t wait for the timer to fire before executing the last two lines.

Secondly, if you want to clear the timer, you’ll need a class level reference to it in your HEADER, e.g.

FTimerHandle time_handler;

This is because the timer you declare above is just a local variable which will go out of scope as soon as the function finishes executing.

P.S. Another thing to check, which I always forget is whether in your cpp file you’ve declared the function implementation properly as

void ACPPHeroCharacter::CheckPriorityRefresh()
{
...
}

instead of just

void CheckPriorityRefresh()
{
...
}

Heyo, thanks, I forgot to add CheckPriorityRefresh(). But it’s still not reseting the characters speed back to 600, even if I moved those last to lines of code to CheckPriorityRefresh().

Yup and Yup, the current code looks like this when it comes to dodge rolling.

void ACPPHeroCharacter::CheckPriorityRefresh()
{
	GetCharacterMovement()->MaxWalkSpeed = 1.0f; //Currently set to 1 so that way I can noticeably see a slowdown.
	GetWorld()->GetTimerManager().ClearTimer(time_handler);
}

void ACPPHeroCharacter::DodgeRoll()
{
	GetCharacterMovement()->MaxWalkSpeed = 800.0f;
	GetWorldTimerManager().SetTimer(time_handler, this, &ACPPHeroCharacter::CheckPriorityRefresh, 1.0f, false);
}

Did you remove the following line from the start of DodgeRoll():

FTimerHandle time_handler;

?

Are you sure the timer is actually executing (calling CheckPriorityRefresh())?

You can use UE_LOG macro to log out a message when that function executes or set a breakpoint.

That is quite a conundrum. If CheckPriorityRefresh() is in fact being called as you say, I honestly have no idea why the MaxWalkSpeed wouldn’t be set properly.

I can put the entire code for the character if you need to see the whole thing. I may not be catching something, I’ll put it as an answer.

The Whole code so everyone can see what is going on.

The CPP file:

#include "CPPCharacter.h"
#include "CPPHeroCharacter.h"

ACPPHeroCharacter::ACPPHeroCharacter()
{

	// Set size for collision capsule
	GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);


	BaseTurnRate = 45.f;
	BaseLookUpRate = 45.f;
	bool isInAir = false;

	// Don't rotate when the controller rotates. Let that just affect the camera.
	bUseControllerRotationPitch = false;
	bUseControllerRotationYaw = false;
	bUseControllerRotationRoll = false;

	// Configure character movement
	GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...	
	GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
	GetCharacterMovement()->JumpZVelocity = 600.f;
	GetCharacterMovement()->AirControl = 0.2f;

	// Create a camera boom (pulls in towards the player if there is a collision)
	CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
	CameraBoom->AttachTo(RootComponent);
	CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character	
	CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller

	// Create a follow camera
	FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
	FollowCamera->AttachTo(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
	FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm

	// Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
	// are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)

}

void ACPPHeroCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
		
	//Axis
	InputComponent->BindAxis("MoveForward", this, &ACPPHeroCharacter::MoveForward);
	InputComponent->BindAxis("MoveRight", this, &ACPPHeroCharacter::MoveRight);
	InputComponent->BindAxis("MoveCamRight", this, &ACPPHeroCharacter::MoveCamRight);
	InputComponent->BindAxis("MoveCamUp", this, &ACPPHeroCharacter::MoveCamUp);

	//Actions
	InputComponent->BindAction("DodgeRoll", IE_Pressed, this, &ACPPHeroCharacter::DodgeRoll);
	InputComponent->BindAction("LightAttack", IE_Pressed, this, &ACPPHeroCharacter::LightAttack);
	InputComponent->BindAction("HeavyAttack", IE_Pressed, this, &ACPPHeroCharacter::HeavyAttack);

}



void ACPPHeroCharacter::MoveForward(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// find out which way is forward
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get forward vector
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, Value);
	}
}

void ACPPHeroCharacter::MoveRight(float Value)
{
	if ((Controller != NULL) && (Value != 0.0f))
	{
		// find out which way is right
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator YawRotation(0, Rotation.Yaw, 0);

		// get right vector 
		const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
		// add movement in that direction
		AddMovementInput(Direction, Value);
	}
}

void ACPPHeroCharacter::MoveCamRight(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds());
}

void ACPPHeroCharacter::MoveCamUp(float Rate)
{
	// calculate delta for this frame from the rate information
	AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds());
}

void ACPPHeroCharacter::CheckPriorityRefresh()
{
	GetCharacterMovement()->MaxWalkSpeed = 1.0f; //Currently set to 1 so that way I can noticeablly see a slowdown.
	GetWorld()->GetTimerManager().ClearTimer(Dodge_Timer);
}

void ACPPHeroCharacter::DodgeRoll()
{
	GetCharacterMovement()->MaxWalkSpeed = 800.0f;
	GetWorldTimerManager().SetTimer(Dodge_Timer, this, &ACPPHeroCharacter::CheckPriorityRefresh, 1.0f, false);
}

void ACPPHeroCharacter::LightAttack()
{

}

void ACPPHeroCharacter::HeavyAttack()
{

}

void ACPPHeroCharacter::MagicAttack()
{

}

The header:

#pragma once

#include "BaseCharacter.h"
#include "CPPHeroCharacter.generated.h"

/**
 * 
 */
UCLASS(config = Game)
class CPPCHARACTER_API ACPPHeroCharacter : public ABaseCharacter
{
	GENERATED_BODY()
	
public:
	
	ACPPHeroCharacter();

	/** Camera boom positioning the camera behind the character */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class USpringArmComponent* CameraBoom;

	/** Follow camera */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
	class UCameraComponent* FollowCamera;

	/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
	float BaseTurnRate;

	/** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
	float BaseLookUpRate;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
	bool isDodging;

	FTimerHandle Dodge_Timer;

protected:

	//Moves the Player Forward
	void MoveForward(float Value);

    //Moves the Player Right
	void MoveRight(float Value);

	//Moves camera right
	void MoveCamRight(float Value);

	//Moves Camera up
	void MoveCamUp(float Value);

	//DodgeRoll
	void DodgeRoll();

	//Attacks
	void LightAttack();
	void HeavyAttack();
	void MagicAttack();

	//Timers
	virtual void CheckPriorityRefresh();


	void TurnAtRate(float Rate);

	void LookUpAtRate(float Rate);

protected:
	// APawn interface
	virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;
	// End of APawn interface
	
	
};

Edit: It now decided to work for some odd reason, thanks for the help!