How to get the movement direction angle of player character?

Hi everyone, I want to know how to get the angle based on the movement direction of my player character.

I want to use the angle to rotate the character based on the direction the player is moving.

I’ve seen in other posts which said we need to use dot product to find the angle between vectors, so i did the math and based my logic, i input the actor’s forward vector and the vector of the actor’s current location.

The problem is for example, instead of constantly getting a 90 degree angle when moving constantly to the right, the value keeps on increasing instead.

Am i using the wrong method or logic? Any help is appreciated. I have posted the code snippets below for the Tick() function and the function to calculate the angle between 2 vectors.

MyCharacter.cpp

void AMyCharacter::Tick(float DeltaTime)
{

Super::Tick(DeltaTime);

if (!movement.IsZero())
{
	//Calculate and update location of player
	FVector newLocation = GetActorLocation();
	newLocation.X += movement.X * DeltaTime;
	newLocation.Y += movement.Y * DeltaTime;

	holdAngle = angleBetween2Vectors(GetActorForwardVector(), newLocation);//Pass 2 vectors to calculate dot product
	FString str = FString::SanitizeFloat(holdAngle); //Convert angle value to string
	GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Yellow, str); //Print angle
	
	SetActorLocation(newLocation);
	
}

}

float AMyCharacter::angleBetween2Vectors(FVector test1, FVector test2)
{

//Normalize both vectors
test1 = test1.GetSafeNormal();
test2 = test2.GetSafeNormal();

float holdDotProduct = FVector::DotProduct(test1, test2);//Calculate dot product

float angle = UKismetMathLibrary::DegAcos(holdDotProduct);//Calculate inverse cosine of dot product

return angle;

}

My first problem when tackling this question was thinking of this in a standard 3d game context. I’m not sure what you plan on doing with this information but what you want to do is unrotate your forward vector based on the unit vector of your current relative velocity.

There is a handy tool for visualizing this: Dot Product

Which can help you wrap your head around dot product and vector math while acting as a useful accuracy checker.

Looking through your math, It looks like you are doing everything correctly. It is possible to get up to 180 degree difference between the two vectors, does your debug string stop at 180? The only other variable at play is the DeltaTime. Is your delta time being referenced correctly? Hold angle is not declared in your snippet, is it being assigned or changed elsewhere? Is the forward vector pointing where you think it is?

Hi Daxter154,

I’ll try to answer the questions you have with my problem and I also have a question from your statement.

Q1: “what you want to do is unrotate your forward vector based on the unit vector of your current relative velocity.”

A1: So do I have to pass 2 arguments into my AngleBetween2Vectors() function, one which is the unrotated forward vector, and second which is the current relative velocity of my character? Or do I have to do it in a different way?

Q2: “does your debug string stop at 180?”

A2: No, it doesn’t. As you can see in the image below, as i press a key to move down from a specific starting position , the debug string value is increasing instead of being a constant value

Q3 : “Is your delta time being referenced correctly?”

A3: I only used the delta time when calculating the movement of the character, so that the character moves in metres per second, rather than per frame. I’m not sure what you mean by whether its being referenced correctly.

Q4: “Hold angle is not declared in your snippet, is it being assigned or changed elsewhere?”

A4: I declared holdAngle in my header file. holdAngle is only used to store the value returned from the angleBetween2Vectors() function and convert the stored value to string (as shown in code snippet). It is not used anywhere else in my code.

Q5: “Is the forward vector pointing where you think it is?”

A5: According to the UE4 documentation, getting the forward vector is essentially getting the X component of the unit vector, which is the red arrow. So i think i the forward vector is pointing to where it should based on the image below

Hey,

GetActorLocation gives you World Position Vector of this Actor. So when you move your Actor then this vector also change and your forward vector doesn’t change (I see you don’t rotate this Actor) and this causes changing your angle.

In the images:

Triangle is Actor

Blue vector is your Actor position

Red is a forward vector.

249032-one-pic.png

249033-one-angle.png

now you move your actor to the right [movement = FVector(0.0, 1.0, 0.0)], so Position Vector change and also your angle change.

249034-two-pic.png

249035-two-angle.png

Let’s try to put your movement vector (direction of moving) to the angleBetween2Vectors() instead of newLocation.

Cheers,

Shaggy41

Hi Shaggy41,

Sorry for the late response. I tried your solution and it works after replacing newLocation with movement as the 2nd function argument.

The last thing i need is to get the negative values of the angles, since now it only shows the angle value between 0 and 180. Can I know how to get the negative values for the angles?

Thanks in advance.

Hey,

you want it to work like this:

  • Move in the right - positive angle

  • Move in the left - negative angle

If yes, then you can use again dot production, but instead of GetActorForwardVector() set GetActorRightVector().
Now if your angle is < 90 degrees that means you move in the right, but if the angle is >= 90 degrees then you move in the left:

SignAngle = angleBetween2Vectors(GetActorRightVector(), movement);
SignAngle = (SignAngle < 90.0f) ? 1.0f : -1.0f;
holdAngle *= SignAngle;

I’ve not tested this solution, but it should work.

Cheers,

Shaggy41

Hi,

Thank you very much for your solution. It works as intended.

Can I know your explanation for the lines of code you provided? I’m still trying to understand it.

Hey,

I hope you understand my explanation :smiley:

if we click on the right side of the actor then the angle between movement and right vector will be from 0 to 90 degrees.

if we click forward or back then the angle between movement and right vector will be 90 degrees.

if we click on the left side of the actor then the angle between movement and right vector will be from 90 to 180 degrees.

First line calculate angle between movement and right vector.

Next lines are:

if(SignAngle > 90.0f) // Turn to Left
{
	signAngle = -1.0f;
}
else // turn to Right
{
	signAngle = 1.0f;
}

// change sign of the angle
holdAngle *= SignAngle;

you can also write it like that (instead of code from my previous post):

if(angleBetween2Vectors(GetActorRightVector(), movement) > 90.0f) 
{
	// We turn to Left so change the angle sign to a negative
	holdAngle = -holdAngle;
}

Cheers,

Shaggy41