Components added to a character in C++ do not appear to follow the character

Hi there,

Following various tutorials, I created camera control for a player character through blueprint. Now I’m trying to implement this through C++, but not finding the same success.

Character components in the blueprint method were:

  • RootComponent
  • SceneComponent (Axis Input → AddLocalRotation[Yaw])
  • SpringArm (Axis Input → AddLocalRotation[Pitch])
    - Camera

In this setup, the player could walk around, and the camera moved with the character.

But now that I have replicated the creation of these components through C++ instead of in blueprint, the camera no longer moves with the player character.

I have made the following observations:

  1. Nothing displays in the Details pane for the now-inherited components above (Capsule and Mesh do show details, I didn’t touch those in C++)
  2. I can use the inherited SceneComponent (PlayerCameraGimbalComponent) in Blueprint, by dragging the reference into a graph
  3. I cannot use the SpringArm or Camera in an event graph
  4. When Playing the game, the player camera view starts in the correct position, as defined in my C++, but doesn’t move with the character, or rotate from axis input

Been banging on this for a long time now… if someone can provide insight, it would be much appreciated!

Character setup from C++, also showing no Details:
282920-
Cannot use C++ components as blueprint references:

Input:

282922-input.png

Header:

protected:

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player Cam Control")
	USceneComponent* PlayerCameraGimbalComponent;
	USpringArmComponent* PlayerCameraSpringArmComponent;
	UCameraComponent* PlayerCameraComponent;

	FVector2D CameraInput;
	FVector2D MovementInput;

	void ArcadeCameraYaw(float AxisValue);
	void ArcadeCameraPitch(float AxisValue);
	void ArcadeMoveForward(float AxisValue);
	void ArcadeMoveRight(float AxisValue);
};

CPP

AArcadePlayerCharacter::AArcadePlayerCharacter()
{
	// 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;

	RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
	RootComponent->bEditableWhenInherited = true;

	PlayerCameraGimbalComponent = CreateDefaultSubobject<USceneComponent>(TEXT("PlayerCameraGimbalComponent"));
	PlayerCameraGimbalComponent->SetupAttachment(RootComponent);
	PlayerCameraGimbalComponent->bEditableWhenInherited = true;

	PlayerCameraSpringArmComponent = CreateDefaultSubobject<USpringArmComponent>(TEXT("PlayerCameraSpringArmComponent"));
	PlayerCameraSpringArmComponent->SetupAttachment(PlayerCameraGimbalComponent);
	PlayerCameraSpringArmComponent->bEditableWhenInherited = true;
	PlayerCameraSpringArmComponent->bInheritYaw = true;
	PlayerCameraSpringArmComponent->bInheritPitch = false;
	PlayerCameraSpringArmComponent->bInheritRoll = false;
	PlayerCameraSpringArmComponent->TargetArmLength = 800.0f;
	PlayerCameraSpringArmComponent->SetRelativeLocationAndRotation(FVector(0.0f, 5.0f, -30.0f),FRotator(-30.0f, 0.0f, 0.0f));
	
	PlayerCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("PlayerCameraComponent"));
	PlayerCameraComponent->SetupAttachment(PlayerCameraSpringArmComponent, USpringArmComponent::SocketName);
	PlayerCameraComponent->SetWorldRotation(FRotator(-20.0f, 0.0f, 0.0f));
	PlayerCameraComponent->bEditableWhenInherited = true;

	AutoPossessPlayer = EAutoReceiveInput::Player0;

}

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

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

	RotatePlayerCamera();

}

void AArcadePlayerCharacter::RotatePlayerCamera()
{
	if (!CameraInput.IsZero())
	{
		PlayerCameraGimbalComponent->AddLocalRotation(FRotator(0.0f,CameraInput.X,0.0f));
		PlayerCameraSpringArmComponent->AddLocalRotation(FRotator(CameraInput.Y,0.0f,0.0f));
	}
}

// Called to bind functionality to input
void AArcadePlayerCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis("ArcadeCameraYaw", this, &AArcadePlayerCharacter::ArcadeCameraYaw);
	PlayerInputComponent->BindAxis("ArcadeCameraPitch", this, &AArcadePlayerCharacter::ArcadeCameraPitch);
	PlayerInputComponent->BindAxis("ArcadeMoveForward", this, &AArcadePlayerCharacter::ArcadeMoveForward);
	PlayerInputComponent->BindAxis("ArcadeMoveRight", this, &AArcadePlayerCharacter::ArcadeMoveRight);

}

void AArcadePlayerCharacter::ArcadeCameraYaw(float AxisValue)
{
	CameraInput.X = AxisValue;
}

void AArcadePlayerCharacter::ArcadeCameraPitch(float AxisValue)
{
	CameraInput.Y = AxisValue;
}

void AArcadePlayerCharacter::ArcadeMoveForward(float AxisValue)
{
	MovementInput.Y = AxisValue;
}

void AArcadePlayerCharacter::ArcadeMoveRight(float AxisValue)
{
	MovementInput.X = AxisValue;
}

Found an answer in the Third Person CPP example. The behaviour I described for inherited components still occurs and seems to be unrelated.

If you too encountered the same problem following one of the Unreal C++ programming tutorials, do not include this line:

RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));

That was all apparently. Had thought I’d tried that, must have been mistaken.