Creating a Camera Shake in Unreal Engine 5 with C++
Let's go over how to shake the camera using C++ in Unreal Engine 5.
Game Engine
Unreal Engine 5.5.1
IDE
Rider 2024.3.2
Project Name
MyProject
To start we need to add EngineCameras
to the project's build script's PublicDependencyModuleNames
. Below is the snippet. Here is the link to project's build script.
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput", "UMG", "Niagara", "EngineCameras" });
Next, let's create our own camera shake class that inherits UCameraShakeBase
. In this example I called it MyCameraShake
, the only thing we need to add is the constructor, it does not come by default like AActors
or other Unreal classes. Below is the header file.
MyCameraShake.h
#pragma once
#include "CoreMinimal.h"
#include "Camera/CameraShakeBase.h"
#include "MyCameraShake.generated.h"
UCLASS()
class MYPROJECT_API UMyCameraShake : public UCameraShakeBase
{
GENERATED_BODY()
public:
// Constructor, set up and set defaults for the camera shake
UMyCameraShake();
};
Next, inside the .cpp
file the constructor is slightly different than other Unreal classes because it requires the FObjectInitializer
with UCameraShakeBase(FObjectInitializer::Get())
because it doesn't have. constructor by default.
Camera shakes can accept one of four different patterns, Composite
, Perlin
, Sequence
, or Wave
. Visit Epic's official camera shake documentation to learn more. In this example we'll use the Perlin
pattern. We first need to include the Perlin class with #include "Shakes/PerlinNoiseCameraShakePattern.h"
. Then, we create the Perlin class and set it's variables. The setup is very repetitive, most of the variables we want to edit are FPerlinNoiseShaker
structs and they each have an Amplitude
and Frequency
float
value. I set all values to 10.0f
to exaggerate the effect. Finally, I set the duration value. All the variables default to 1.0f
is not set.
MyCameraShake.cpp
#include "MyCameraShake.h"
#include "Shakes/PerlinNoiseCameraShakePattern.h"
// Sets default values
UMyCameraShake::UMyCameraShake()
: UCameraShakeBase(FObjectInitializer::Get())
{
// only shake the camera if it's not already shaking
bSingleInstance = true;
UPerlinNoiseCameraShakePattern* MyPerlinPattern = CreateDefaultSubobject<UPerlinNoiseCameraShakePattern>(TEXT("MyPerlinPattern"));
MyPerlinPattern->X.Amplitude = 10.f;
MyPerlinPattern->X.Frequency = 10.f;
MyPerlinPattern->Y.Amplitude = 10.f;
MyPerlinPattern->Y.Frequency = 10.f;
MyPerlinPattern->Z.Amplitude = 10.f;
MyPerlinPattern->Z.Frequency = 10.f;
MyPerlinPattern->Pitch.Amplitude = 10.f;
MyPerlinPattern->Pitch.Frequency = 10.f;
MyPerlinPattern->Yaw.Amplitude = 10.f;
MyPerlinPattern->Yaw.Frequency = 10.f;
MyPerlinPattern->Roll.Amplitude = 10.f;
MyPerlinPattern->Roll.Frequency = 10.f;
MyPerlinPattern->FOV.Amplitude = 10.f;
MyPerlinPattern->FOV.Frequency = 10.f;
MyPerlinPattern->Duration = 2.f;
SetRootShakePattern(MyPerlinPattern);
}
To showcase the camera shake I created a fairly basic trigger box that shakes the players camera on overlap. We first get the player controller via APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
and then create a subclass of our newly created camera shake class with TSubclassOf<UMyCameraShake> CameraShakeClass = UMyCameraShake::StaticClass();
. Finally, we can shake the camera with PlayerController->ClientStartCameraShake(CameraShakeClass);
. Below is the trigger's .cpp
file.
MyCameraShakeTrigger.cpp
#include "MyCameraShakeTrigger.h"
#include "MyCameraShake.h"
#include "Components/BoxComponent.h"
#include "Kismet/GameplayStatics.h"
// Sets default values
AMyCameraShakeTrigger::AMyCameraShakeTrigger()
{
MyRoot = CreateDefaultSubobject<USceneComponent>(TEXT("MyRoot"));
MyRoot->bVisualizeComponent = true;
RootComponent = MyRoot;
MyBoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("MyBoxComponent"));
MyBoxComponent->SetHiddenInGame(false);
MyBoxComponent->SetupAttachment(RootComponent);
MyBoxComponent->OnComponentBeginOverlap.AddDynamic(this, &AMyCameraShakeTrigger::OnBeginOverlap);
}
void AMyCameraShakeTrigger::OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor != nullptr && OtherActor != this)
{
// Get the player controller
APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
if (PlayerController)
{
// Specify the Camera Shake class
TSubclassOf<UMyCameraShake> CameraShakeClass = UMyCameraShake::StaticClass();
if (CameraShakeClass)
{
// Play the camera shake
PlayerController->ClientStartCameraShake(CameraShakeClass);
}
}
}
}
After compiling the code, the MyCameraShakeTrigger
can dragged directly into the game. Below is the final effect in the gym.
Hopefully this helps, when programming this feature I got tripped up in a few places.
Harrison McGuire