Download

Difference between movement functions with FVector and FRotator

I wrote some functions for my character to move forward/backward and right/left. Than I retargeted the Animation_Blueprint from the Animation Starter Pack to the Prototype Character so my char has some animations while walking and it doesn’t look dumb. I noticed a “bug” in the animation while walking backwards. The character/animation starts flickering when walking backwards so I went to the wiki and looked up in the First Person Shooter tutorial how the movement was coded there. So I noticed some differences from how I wrote the movement functions and how author of the wiki tutorial wrote them. So I tried using the method from the wiki article and the animation flickering was gone. My question is where is the difference between how I first coded my movement functions (See red color):

(Ignore the comments at MoveFwdBwd() and MoveRL())

Character.h



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Character.h"
#include "CharacterSimpl0S.generated.h"

UCLASS()
class UE4CPP_API ACharacterSimpl0S : public ACharacter
{
	GENERATED_BODY()

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

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

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

	// Function declaration to move fwd and bwd
	UFUNCTION()
		void MoveFwdBwd(float fAmount);
	// Function declaration to move right and left
	UFUNCTION()
		void MoveRL(float fAmount);
	
};



Character.cpp



// Fill out your copyright notice in the Description page of Project Settings.

#include "UE4Cpp.h"
#include "CharacterSimpl0S.h"


// Sets default values
ACharacterSimpl0S::ACharacterSimpl0S()
{
 	// 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;

	UE_LOG(Simpl0S_Log, Warning, TEXT("Character Class: CharacterSimpl0S"));

}

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

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

}

// Called to bind functionality to input
void ACharacterSimpl0S::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
	Super::SetupPlayerInputComponent(InputComponent);

	// Bind Axis

	// Bind Movement Axis
	InputComponent->BindAxis("MoveFwdBwd", this, &ACharacterSimpl0S::MoveFwdBwd);
	InputComponent->BindAxis("MoveRL", this, &ACharacterSimpl0S::MoveRL);

}

// Function definition to move fwd and bwd
void ACharacterSimpl0S::MoveFwdBwd(float fAmount)
{
	// Check if a controller is set up and fAmount != 0
	if (Controller && fAmount)
	{
		// We need to know which direction fwd is
		// Directions/Points in a 3-D space/environment are stored in 3-D Vectors
		// The UE4 Vector container is FVector
		// FVector stores X,Y,Z coordinates
		// In order to get the fwd direction of an actor we need to call a built in function
		// The function is called ==> GetActorForwardVector()
		// GetActorForwardVector() gets the forward (X-coordinate) direction of an actor
		FVector fwd = GetActorForwardVector();

		// After we know which direction fwd is we need to add movement 
		// in that direction by a certain amount
		// There is a built in function called: AddMovementInput()
		// AddMovementInput() adds movement in a certain direction by a certain amount
		// AddMovementInput() takes two arguments
		// AddMovementInput(Direction, Amount)
		AddMovementInput(fwd, fAmount);

	}

}

// Definition of function to move r and l
void ACharacterSimpl0S::MoveRL(float fAmount)
{
	// Check if controller is set up and fAmount != 0
	if (Controller && fAmount)
	{
		// We need to know which direction right is
		// Directions/Points in a 3-D space/environment are stored in 3-D Vectors
		// The UE4 Vector container is FVector
		// FVector stores X,Y,Z coordinates
		// In order to get the fwd direction of an actor we need to call a built in function
		// The function is called ==> GetActorRightVector()
		// GetActorRightVector() gets the forward (Y-coordinate) direction of an actor
		FVector right = GetActorRightVector();

		// After we know which direction right is we need to add movement 
		// in that direction by a certain amount
		// There is a built in function called: AddMovementInput()
		// AddMovementInput() adds movement in a certain direction by a certain amount
		// AddMovementInput() takes two arguments
		// AddMovementInput(Direction, Amount)
		AddMovementInput(right, fAmount);
	}
}


And how the wiki author wrote them (Blue Color):

Character.cpp




void AFPSCharacter::MoveFwdBwd(float fAmount)
    {
        if ( (Controller != NULL) && (fAmount!= 0.0f) )
        {
            // find out which way is forward
            FRotator Rotation = Controller->GetControlRotation();
            // Limit pitch when walking or falling
            if (GetCharacterMovement()->IsMovingOnGround() || GetCharacterMovement()->IsFalling() )
            {
                Rotation.Pitch = 0.0f;
            }
            // add movement in that direction
            const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X);
            AddMovementInput(Direction, fAmount);
        }
    }

void AFPSCharacter::MoveRL(float fAmount)
    {
        if ( (Controller != NULL) && (Value != 0.0f) )
        {
            // find out which way is right
            const FRotator Rotation = Controller->GetControlRotation();
            const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::Y);
            // add movement in that direction
            AddMovementInput(Direction, fAmount);
        }
    }



It’s simple. Your functions are taking the rotation from the Character instead of the Controller. The Controller is higher in the evaluation order, thus, sometimes the Controller can override whatever movement or rotation you are applying onto a certain actor. To put it short, the Actor’s forward vector isn’t the same as that actor’s controller foward vector.

Okay thanks for the explanation. So the Controller doesn’t have something like Controller->GetControlForwardVector();? That’s why we need to store it in an FRotator and use GetControlRotation(); instead? The part which I don’t really understand is this line here:


const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X);

Why isn’t it enough to say AddMovementInput(Rotation, fAmount) like when I was using the actors’ vector AddMovementInput(ForwardVector, fAmount)?

EDIT: Okay now I see. Me being dumb on this one haha.


const FVector Direction = FRotationMatrix(Rotation).GetScaledAxis(EAxis::X);

is essentially


FVector fwd = GetActorForwardVector();

Yeah, as I said, the only difference between your code and the one fro the Shooter Example is that they’re getting the actor rotation from the character controller instead of from the character itself.
And yes, the controller does have a forward vector getter function. Here an example:


APlayerController *Controller = GetWorld()->GetFirstPlayerController();
FVector FwdVc = Controller->GetActorForwardVector();