Skip to content

Instantly share code, notes, and snippets.

@iUltimateLP
Last active July 28, 2022 10:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iUltimateLP/d1f9c0408f84086401d909b38054db3c to your computer and use it in GitHub Desktop.
Save iUltimateLP/d1f9c0408f84086401d909b38054db3c to your computer and use it in GitHub Desktop.
Adds a flexible Head Bobbing component to the Unreal Engine. Supports three different camera shake states (idle, walk, run).
// Copyright 2019-2021 Jonathan Verbeek. All Rights Reserved.
#include "Player/HeadBobComponent.h"
UHeadBobComponent::UHeadBobComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
// Activate by default
SetAutoActivate(true);
}
void UHeadBobComponent::BeginPlay()
{
Super::BeginPlay();
}
void UHeadBobComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// Don't do anything if not active
if (!IsActive()) return;
// Get the owner's velocity
FVector Velocity = GetOwner()->GetVelocity();
// Whether the character is moving, based on the owner's velocity
bool bIsMoving = Velocity.Size() != 0.f;
// If the character is not moving, and not in idle state
if (!bIsMoving && State != EHeadBobState::Idle)
{
// Transition to idle state
State = EHeadBobState::Idle;
StartCameraShake(IdleCameraShake);
}
// If the character is walking normally, but is not in walk state
else if (bIsMoving && !bIsSprinting && State != EHeadBobState::Walk)
{
// Transition to walk state
State = EHeadBobState::Walk;
StartCameraShake(WalkCameraShake);
}
// If the character is running, but is not in run state
else if (bIsMoving && bIsSprinting && State != EHeadBobState::Run)
{
// Transition to run state
State = EHeadBobState::Run;
StartCameraShake(RunCameraShake);
}
}
void UHeadBobComponent::SetIsSprinting(bool bSprinting)
{
bIsSprinting = bSprinting;
}
APlayerController* UHeadBobComponent::GetPlayerController()
{
// Cast the owner to a pawn
APawn* OwnerAsPawn = Cast<APawn>(GetOwner());
// Make sure that worked
if (OwnerAsPawn)
{
// Get the pawn's controller
APlayerController* PC = Cast<APlayerController>(OwnerAsPawn->GetController());
// Check if that PC has a camera manager
if (!PC->PlayerCameraManager)
{
UE_LOG(LogTemp, Error, TEXT("%s's owner does NOT have a camera manager!"), *GetName());
return nullptr;
}
// Return the PC
return PC;
}
else
{
UE_LOG(LogTemp, Error, TEXT("%s can't cast owner to pawn! HeadBobComponents only work on pawns!"), *GetName());
return nullptr;
}
}
void UHeadBobComponent::StartCameraShake(TSubclassOf<UMatineeCameraShake> Class)
{
// Get the player controller
APlayerController* PC = GetPlayerController();
check(PC);
// Stop any camera shake currently playing
StopCameraShake();
// Make sure the given class is valid
if (!Class)
{
UE_LOG(LogTemp, Error, TEXT("Cannot start empty camera shake"));
return;
}
// Start the new one
CurrentCameraShake = PC->PlayerCameraManager->StartCameraShake(Class, 1.f, ECameraShakePlaySpace::CameraLocal);
UE_LOG(LogTemp, Log, TEXT("Started %s"), *Class->GetName());
// Flag that we started a camera shake
bCameraShakeActive = true;
}
void UHeadBobComponent::StopCameraShake()
{
// Get the player controller
APlayerController* PC = GetPlayerController();
check(PC);
// Really a CS playing?
if (bCameraShakeActive)
{
// Not anymore
bCameraShakeActive = false;
// Stop the current camera shake
UE_LOG(LogTemp, Log, TEXT("Stopped %s"), *CurrentCameraShake->GetClass()->GetName());
PC->PlayerCameraManager->StopCameraShake(CurrentCameraShake, false);
}
}
// Copyright 2019-2021 Jonathan Verbeek. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/SceneComponent.h"
#include "Camera/CameraShake.h"
#include "HeadBobComponent.generated.h"
// Current state of the shake state machine. Used to switch between shakes
UENUM(BlueprintType, Blueprintable)
enum EHeadBobState
{
Idle,
Walk,
Run
};
// This component provides head bobbing to any pawn with a camera manager attached to it.
UCLASS(ClassGroup=(Nexus), meta=(BlueprintSpawnableComponent))
class NEXUS_API UHeadBobComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UHeadBobComponent();
public:
// The idle camera shake to use
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Head Bob Component")
TSubclassOf<UMatineeCameraShake> IdleCameraShake;
// The walk camera shake to use
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Head Bob Component")
TSubclassOf<UMatineeCameraShake> WalkCameraShake;
// The run camera shake to use
UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "Head Bob Component")
TSubclassOf<UMatineeCameraShake> RunCameraShake;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
public:
UFUNCTION(BlueprintCallable, Category = "Head Bob Component")
void SetIsSprinting(bool bSprinting);
private:
// Get the player controller
APlayerController* GetPlayerController();
// Starts a camera shake
void StartCameraShake(TSubclassOf<UMatineeCameraShake> Class);
// Stops the current camera shake
void StopCameraShake();
private:
// Whether any camera shake is currently active
bool bCameraShakeActive = false;
// The camera shake currently active
UCameraShakeBase* CurrentCameraShake;
// Whether the sprinting flag is set
bool bIsSprinting = false;
// Current state of the state machine
TEnumAsByte<EHeadBobState> State = EHeadBobState::Idle;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment