Third-person camera and movement
Three rotations are in play: the controller's (where you're looking), the camera boom's (follows the controller) and the character's (turns toward where you're walking). Your settings keep the character out of the controller's rotation, so the camera orbits freely while he turns to face his movement direction.
The components
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
CameraBoom->SetupAttachment(GetRootComponent());
CameraBoom->TargetArmLength = 200.0f;
CameraBoom->SocketOffset = FVector(0.0f, 55.0f, 65.0f);
CameraBoom->bUsePawnControlRotation = true;
FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
FollowCamera->SetupAttachment(CameraBoom, USpringArmComponent::SocketName);
FollowCamera->bUsePawnControlRotation = false;
CreateDefaultSubobjectonly works in the constructor. It creates the component as part of the class's default object, so every Blueprint child gets it and can tweak it.SetupAttachment(constructor) vsAttachToComponent(at runtime). Use the right one for where you are.- Spring arm: a stick from the character to the camera. When something is in the way, it pulls the camera in (collision test), so the camera doesn't clip through walls.
SocketOffset (0, 55, 65): shifts the end of the stick 55 right and 65 up. That's the over-the-shoulder look from the recent God of War games, instead of a camera centred behind the head.- The boom uses the control rotation; the camera doesn't, so it just rides on the end of the boom.
Who turns the character?
bUseControllerRotationYaw = false; // don't snap to the camera
GetCharacterMovement()->bOrientRotationToMovement = true; // turn toward movement
GetCharacterMovement()->RotationRate = FRotator(0.f, 500.f, 0.f); // 500°/s yaw
| Setting | Feels like |
|---|---|
| Yaw from controller off, orient to movement on | Free camera; he runs toward what you press. Exploring. (What you have.) |
| Yaw from controller on | He always faces where the camera looks and strafes. Aiming / locked on. |
Kratos switches between these: free while exploring, facing the target when you lock on or aim the axe. Expect a lesson
that flips these flags (or uses bUseControllerDesiredRotation) at runtime.
Input_Move, line by line
const FVector2D MovementVector = InputActionValue.Get<FVector2D>();
const FRotator MovementRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
if (MovementVector.Y != 0.f) {
const FVector ForwardDirection = MovementRotation.RotateVector(FVector::ForwardVector);
AddMovementInput(ForwardDirection, MovementVector.Y);
}
if (MovementVector.X != 0.f) {
const FVector RightDirection = MovementRotation.RotateVector(FVector::RightVector);
AddMovementInput(RightDirection, MovementVector.X);
}
Get<FVector2D>(): the stick/WASD value. Y is forward/back, X is right/left. That only works because the action's value type is Vector2D.- Keep only the yaw. If you used the full control rotation, looking down would push "forward" into the floor and he'd move slower. Zeroing pitch and roll gives a flat direction.
RotateVector(ForwardVector): world forward (X) turned to match the camera's heading. That's "forward relative to the camera", the standard third-person feel.AddMovementInput(dir, scale): this doesn't move anything itself. It adds to a request the Character Movement Component uses on its tick, together with speed, acceleration, friction andBrakingDecelerationWalking.
Input_Look is simpler: AddControllerYawInput / AddControllerPitchInput rotate the
controller. The boom follows because of bUsePawnControlRotation. If looking up and down feels inverted, the
fix is a Negate modifier on the mapping, not code.
Quiz yourself
Why build MovementRotation from only the yaw?
With pitch included, looking down tilts "forward" into the ground, so movement slows down or goes wrong. Yaw-only gives a flat heading.
What does bOrientRotationToMovement = true plus bUseControllerRotationYaw = false feel like in game?
The camera orbits freely, and the character turns (at RotationRate) to face the direction he's moving.
What does SocketOffset = (0, 55, 65) achieve?
It moves the camera right and up from the end of the arm: an over-the-shoulder framing.
SetupAttachment vs AttachToComponent?
SetupAttachment is for the constructor, before the component is registered. AttachToComponent is for runtime (e.g. attaching a spawned weapon to a hand socket).
Does AddMovementInput move the character straight away?
No. It accumulates an input vector that the Character Movement Component consumes on its tick, applying acceleration, max speed and friction.
A wall comes between the character and the camera. What stops the camera from clipping through it?
The spring arm's collision test (bDoCollisionTest, on by default). It sweeps from the character to the camera and shortens the arm to the hit point.
Which component actually swings around when you move the mouse: the boom, the camera, or the character?
Mouse input rotates the controller. The boom follows it (bUsePawnControlRotation = true), and the camera rides on the end of the boom. The character doesn't turn, because controller yaw is off.