Can't Make My Character Move

Hey, everyone! How are you doing? I was trying to make a function that moves my Paper2D Character, but with no result. I really think that everything on my code is right, and os it is my axis mapping, but for some reason I’ve not been able to make it work. Can anyone help me with this?

// Header File

#pragma once

#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "PaperCharacter.h"
#include "PaperFlipbook.h"
#include "PaperFlipbookComponent.h"
#include "SpriteCharacter.generated.h"
/**
 * 
 */
UCLASS()
class WEAPONGIRLS_API ASpriteCharacter : public APaperCharacter
{
	GENERATED_BODY()
		
private:

	void MoveHorizontal(float AxisValue);
	void Jump(float AxisValue);
	void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent);

public:

	UPROPERTY(Category = CharacterStats, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	int maxHealth{};

	ASpriteCharacter(const FObjectInitializer& ObjectInitializer);
};

// CPP file

#include "SpriteCharacter.h"

//Constructor
ASpriteCharacter::ASpriteCharacter(const FObjectInitializer& ObjectInitializer) :
	Super(ObjectInitializer), maxHealth{ 100 }
{
	this->GetSprite()->SetPlayRate(0.7f);
}

//Makes the character move to the right/left
void ASpriteCharacter::MoveHorizontal(float AxisValue)
{
	AddMovementInput(GetActorRightVector() * AxisValue);
}

//Makes the character jump
void ASpriteCharacter::Jump(float AxisValue)
{
}

void ASpriteCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis(TEXT("MoveHorizontal"), this, &ASpriteCharacter::MoveHorizontal);
	
}

to start with what version of the Engine are you working with (namely 5.2 or after), and is this supposed to be using the EnhancedInputSubsystem

your SetupPlayerInputComponent should be marked override right before the semi-colon (as APaperCharacter inherits from ACharacter which already defines that function, so we need to override it or you should get C++ syntax errors)

if this is using the EnhancedInputSubsystem then you need to have pointers to UInputAction (and probably the UInputMappingContext), that are used to bind your functions in the SetupPlayerInputComponent and the argument to your bound input functions should be FInputActionValue& which will have the axis values as members that were defined in the InputMappingContext

if this is in an Engine Version before 5.2, and you are using the Project Settings bindings then are you sure you bound the keys/buttons in the Project Settings.

if this is in 5.2 or later then the Project Settings Input method has been fully deprecated and the best native option is to use the EnhancedInputSubsystem.

Hey, Gardian. Thanks for the response.

I’m using Unreal version 5.0.3.
I didn’t get a syntax error for not writing the keyword override. I tried to include it in my last test, but it also didn’t work.
I’m pretty sure that I bind the axis correctly. I have two axis binding for the “A” and “D” keys, under the group “MoveHorizontal”. I did this on Project Settings → Engine → Input → Axis Mappings

which perspective are you going for with this project “top down” or “side scroller”
if this is top down then right vector should be left and right
if this is a side scroller then right vector is into and out of the screen.
so If this is a Side scroller your issue is perspective

when you hit the Play button before clicking into the game window select the PlayerCharacter in the Level Outliner
pay attention to the Transform
when you click into the game window and use the “A” and “D” do any of the values change in the transform?
if the Y-Value is changing but the character is not moving then in your MoveHorizontal() change the GetActorRightVector() to GetActorForwardVector() (yes I know it is left and right relative to the screen, but it is forward and back relative to the character)

Just tried GetActorForwardVector() with no luck, unfortunately. Something that I’m trying it out to see the results is to call the GetActorRightVector() on a BeginPlay overrode function:

void ASpriteCharacter::BeginPlay()
{
	Super::BeginPlay();
	UE_LOG(LogTemp, Warning, TEXT("IM HERE"));
	this->AddMovementInput(GetActorRightVector() * 2.0f);
}

Even tough I’m gettint the “I’m Here” message in the log, the character isn’t moving by an inch. I tried GetActorForwardVector(), and even GetActorUpVector(), but it doesn’t move. So the problem may not be the axis per se, but the function call somehow (?)

unless you are dealing with a passed in variable that just so happens to have the same name as a local variable this-> is almost never needed (even then the this-> is just a stop gap “practice” for bad naming convention that is reinforced by Java and a begrudging cary over to C#.

the first argument to the AddMovementInput is the direction of the movement, and it is mostly expected to be normalized (have a magnitude of 1, so feeding something with a magnitude of greater then 1 in the best case has no impact, and in the worst is bad math leading to inconsistent behavior

putting the code in BeginPlay() means it will happen instantly when you hit Play, and before the first frame is even rendered, so you will never see it happening

  • eveny actor that exists at the Start of the level will have its BeginPlay() called before the first Pre-Physics Tick() and before the first Render-Step.
  • So unless you have an absolute point of reference noticing a movement of 2 units is going to be hard.

the second argument to AddMovementInput() is the magnitude of the movement.

so the log message showing up means the code is being compiled through the toolchain. if you put a similar Log message in your MoveHorizontal() does that show up when you hit either of the bound inputs, and maybe include the value of the Axis

//where we are using keyboad in this example the result should be "close" to 1 or -1
UE_LOG(LogTemp, Warning, TEXT("MoveHorizontal: %s"), *FString::SanitizeFloat(AxisValue));
AddMovementInput(GetActorForwardVector(), AxisValue);

after hitting play, before clicking into the game window, if you have the character selected (the one with yellow/gold text) in the level, then click into the running game instance you should see only the X value of the Character changing when you hit “A” or “D”

Tried this

void ASpriteCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	UE_LOG(LogTemp, Warning, TEXT("Hello2"));
	PlayerInputComponent->BindAxis(TEXT("MoveHorizontal"), this, &ASpriteCharacter::MoveHorizontal);
	
}
void ASpriteCharacter::MoveHorizontal(float AxisValue)
{
	UE_LOG(LogTemp, Warning, TEXT("MoveHorizontal: %s"), *FString::SanitizeFloat(AxisValue));
	AddMovementInput(GetActorRightVector() * AxisValue);
}

No sign of output on the log, unfortunately

its partly on me for not noticing it when I was pointing to the SetupPlayerInputComponent() not having override. the reason you never got a C++ syntax error was because you never declared the function as virtual (adding it to the virtual function table for dynamic runtime resolution.

the full signature should be

// if you already have PlayerInput recognized as a type then you can omit the "class keyword"
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

what is happening is the engine is calling SetupPlayerInputComponent on Pawn, but because the one for your class is not indexed into the virtual function table the highest in the hierarchy it goes is the one for ACharacter so yours is never called through the virtual function table, and the engine is designed not to cast to resolve these type of issue (namely because it doesn’t know the type to cast to in order to call the right one), and dynamic_cast is more “expensive” then using the virtual function table of C++

My code looks like this at the moment:

// Header

#pragma once

#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "PaperCharacter.h"
#include "PaperFlipbook.h"
#include "PaperFlipbookComponent.h"
#include "SpriteCharacter.generated.h"
/**
 * 
 */
UCLASS()
class WEAPONGIRLS_API ASpriteCharacter : public APaperCharacter
{
	GENERATED_BODY()

private:

	void MoveHorizontal(float AxisValue);
	void Jump(float AxisValue);
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

public:

	UPROPERTY(Category = CharacterStats, VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
	int maxHealth{};

	ASpriteCharacter(const FObjectInitializer& ObjectInitializer);
};

// cpp

#include "SpriteCharacter.h"

//Constructor
ASpriteCharacter::ASpriteCharacter(const FObjectInitializer& ObjectInitializer) :
	Super(ObjectInitializer), maxHealth{ 100 }
{
	UE_LOG(LogTemp, Warning, TEXT("Hello"));
	this->GetSprite()->SetPlayRate(1.0f);
}

//Makes the character move to the right/left
void ASpriteCharacter::MoveHorizontal(float AxisValue)
{
	UE_LOG(LogTemp, Warning, TEXT("MoveHorizontal: %s"), *FString::SanitizeFloat(AxisValue));
	AddMovementInput(GetActorRightVector() * AxisValue);
}

//Makes the character jump
void ASpriteCharacter::Jump(float AxisValue)
{
}

void ASpriteCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);
	
	UE_LOG(LogTemp, Warning, TEXT("Hello2"));
	PlayerInputComponent->BindAxis(TEXT("MoveHorizontal"), this, &ASpriteCharacter::MoveHorizontal);
	
}

It dindn’t work as well :sweat_smile:

Hi, were you able to see any logs output from MoveHorizontal? If not, then there is probably some issue with the axis binding. If the bindings are correct, maybe you can try to create a new blueprint class from your c++ class? In some rare cases the changes in c++ don’t propagate to the blueprint.

If the logs are working but the character is not moving, maybe you can check the cached input vector:

void ASpriteCharacter::MoveHorizontal(float AxisValue)
{
	//...
	AddMovementInput(GetActorRightVector() * AxisValue);
	UE_LOG(LogTemp, Display, TEXT("%s"), *Internal_GetPendingMovementInputVector().ToString());
}

If the input is handled properly, it should produce some log like the screenshot below:
image

If the character still doesn’t move, you can probably check the movement component in the BP, or try to put the character on a flat surface, etc.

I tried to create a BluePrint based on my C++ class but it didn’t carry over my functios or my variables (don’t know if I did correctly tbh, just right clicked on my c++ class and on “Create BluePrint Class Based on SpriteCharacter”). And no, I’m not getting any logs from MoveHorizontal function.

Were you able to see any log from SetupPlayerInputComponent?

If not, it is possible that your character is not possessed by any player controller. Here is a simple test: create an empty map, drop in a plane and your blueprint character, and select your character. In the details panel, set Pawn->Auto Possess Player to be Player 0, and play in the viewport. This should at least trigger the log in SetupPlayerInputComponent().

image

Hey, @SimonJ96 ! Ty so much, it worked! When I turned on the Auto Possess to Player0 I could move perfectly fine, but I got into “first person mode”, if that makes sense. I imagine that if I properly setup a camera, it should fix this problem, right?

P.s.: Btw, @gardian206, even tough it wasn’t the reason of the problem, you were right about the perspective stuff. When I finally got the control of the character with GetActorRightVector( ), it walked not to the sides, but front/back. I changed to GetActorForwardVector( ) and now it’s going towards the intended direction.

Your are right, setting up the camera should fix it.

Usually if you put a Player Start in the map, and in the game mode set the default pawn to be your character BP, your character will automatically spawn and get possessed.

1 Like

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