I really don't like when 3P games don't let you swap shoulders, so I added it

It drives me crazy when certain games don’t add any Q/E leaning or the ability to swap your shoulder manually, and this is the first time in my life I’ve ever been in a position or remotely had the knowledge to actually do something about this haha.

I was moving the Spring Arm’s socket offset back and forth trying to find a nice over-the-shoulder view, and noticed that as long as I center the spring arm itself, the offsets on the Y axis are more or less a mirror. So I thought I could probably make a swap toggle. But then it’s pretty jarring if you don’t smooth it out, so I tried to interpolate it as well.

Header declarations:

	// ----------------------------------
	// Camera.
	UPROPERTY()
	USpringArmComponent* CameraSpringArm;

	void SwapShoulder();
	void MoveToShoulder(float DeltaTime);

	bool bRightShoulder = true;
	float RightShoulderOffset;
	float LeftShoulderOffset;
	UPROPERTY(EditAnywhere, Category="View")
	float ShoulderSwapSpeed = 10;

Then we start implementing. First we’ll get the spring arm, and set the two target offsets we want.

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

	// Get reference to the spring arm so we can shoulder swap.
	CameraSpringArm = Cast<USpringArmComponent>(GetComponentByClass(USpringArmComponent::StaticClass()));
	// As long as the spring arm in the BP is centered around the player,
	// we can just multiply it's existing offset by -1 to swap it.
	RightShoulderOffset = CameraSpringArm->SocketOffset.Y;
	LeftShoulderOffset = RightShoulderOffset * -1;
}

Add input binding for the toggle:

PlayerInputComponent->BindAction(TEXT("SwapShoulder"), IE_Pressed, this, &AShooterCharacter::SwapShoulder);

A method to handle swapping our boolean back and forth when we hit our keybind:

// --------------------------------------------------------------
/// Swap over-the-shoulder view between left and right, toggled by input.
void AShooterCharacter::SwapShoulder()
{
	if (bRightShoulder) {
		bRightShoulder = false;
	}
	else {
		bRightShoulder = true;
	}
}

Then the function that’s called on Tick so it’s smooth:

// --------------------------------------------------------------
/// Interpolate towards desired shoulder offset.
void AShooterCharacter::MoveToShoulder(float DeltaTime)
{
	float CurrentPos = CameraSpringArm->SocketOffset.Y;

	if (bRightShoulder) {
		CameraSpringArm->SocketOffset.Y = FMath::FInterpTo(CurrentPos, RightShoulderOffset, DeltaTime, ShoulderSwapSpeed);
	}
	else {
		CameraSpringArm->SocketOffset.Y = FMath::FInterpTo(CurrentPos, LeftShoulderOffset, DeltaTime, ShoulderSwapSpeed);
	}
}

And that’s it!

I don’t know if setting the SocketOffset every frame like that would be a performance consideration or not. If it were, I’m not sure how to selectively call it. Maybe every time you hit toggle, a timer starts and calls MoveToShoulder() every frame until the timer stops, once the transition has been made. Something like that?

3 Likes

Thank you for sharing this and I agree I hate when you can’t swap shoudlers!

1 Like

Privacy & Terms