Loading...
Loading...
Use this skill when working with Sequencer, LevelSequence, cutscene, cinematic, camera, movie scene, sequencer event, or Movie Render Queue in Unreal Engine. See references/sequencer-patterns.md for dialogue cutscene, in-game camera, and scripted event patterns. For animation playback, see ue-animation-system.
npx skill4agent add quodsoler/unreal-engine-skills ue-sequencer-cinematics.agents/ue-project-context.mdPublicDependencyModuleNames.AddRange(new string[]
{
"LevelSequence", "MovieScene", "CinematicCamera",
});
// Offline rendering only:
PrivateDependencyModuleNames.Add("MovieRenderPipelineCore");ALevelSequenceActorGetSequencePlayer()SequencePlayer// LevelSequenceActor.h: ULevelSequencePlayer* GetSequencePlayer() const;
ULevelSequencePlayer* Player = SeqActor->GetSequencePlayer();
if (Player) { Player->Play(); }// LevelSequencePlayer.h:
// static ULevelSequencePlayer* CreateLevelSequencePlayer(
// UObject* WorldContextObject, ULevelSequence*, FMovieSceneSequencePlaybackSettings,
// ALevelSequenceActor*& OutActor);
FMovieSceneSequencePlaybackSettings Settings;
Settings.bAutoPlay = false;
Settings.PlayRate = 1.0f;
Settings.LoopCount.Value = 0; // 0=once, -1=infinite
Settings.bDisableMovementInput = true;
Settings.bDisableLookAtInput = true;
Settings.bHidePlayer = false;
Settings.bHideHud = false;
Settings.bDisableCameraCuts = false;
Settings.bPauseAtEnd = false;
Settings.FinishCompletionStateOverride =
EMovieSceneCompletionModeOverride::ForceRestoreState; // safe for skippable cutscenes
ALevelSequenceActor* OutActor = nullptr;
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(
this, Sequence, Settings, OutActor);
// Store OutActor in a UPROPERTY to prevent GC
ActiveSequenceActor = OutActor;
if (Player)
{
Player->OnFinished.AddDynamic(this, &AMyClass::OnCutsceneFinished);
Player->Play();
}// MovieSceneSequencePlayer.h
Player->Play();
Player->PlayReverse();
Player->PlayLooping(-1); // -1 = infinite loops
Player->Pause();
Player->Stop(); // moves cursor to end, fires OnStop
Player->StopAtCurrentTime();
Player->GoToEndAndStop();
Player->SetPlayRate(0.5f); // negative = reverse
// Jump to frame (skips events between current and target)
// Blueprint exposes this as GoToFrame. In C++, use SetPlaybackPosition with Jump.
Player->SetPlaybackPosition(
FMovieSceneSequencePlaybackParams(FFrameTime(120), EUpdatePositionMethod::Jump));
// Play through to frame (triggers all events along the way)
Player->PlayTo(
FMovieSceneSequencePlaybackParams(FFrameTime(240), EUpdatePositionMethod::Play),
FMovieSceneSequencePlayToParams());
// Restrict play range
Player->SetFrameRange(0, 60); // frames 0–60
Player->SetTimeRange(0.0f, 2.5f); // seconds
// State query
bool bPlaying = Player->IsPlaying();
FQualifiedFrameTime Now = Player->GetCurrentTime();
FQualifiedFrameTime Dur = Player->GetDuration();
// Delegates (bind before Play)
Player->OnFinished.AddDynamic(this, &UMyClass::OnSeqFinished);
Player->OnPlay.AddDynamic(this, &UMyClass::OnSeqPlay);
Player->OnStop.AddDynamic(this, &UMyClass::OnSeqStop);
Player->OnNativeFinished.BindUObject(this, &UMyClass::OnNativeFinished); // non-dynamic
// Camera cut event (LevelSequencePlayer.h)
// DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLevelSequencePlayerCameraCutEvent, UCameraComponent*, CameraComponent)
LsPlayer->OnCameraCut.AddDynamic(this, &UMyClass::OnCameraCut);
// Restore state on early stop (skippable cutscene)
Player->SetCompletionModeOverride(EMovieSceneCompletionModeOverride::ForceRestoreState);
Player->Stop();
// Sub-sequence snapshot
FLevelSequencePlayerSnapshot Snap;
Player->TakeFrameSnapshot(Snap);
// Snap.CurrentShotName, Snap.RootTime, Snap.CameraComponent, Snap.ActiveShotPlay()// Spawnable: sequence owns the actor lifecycle
// Set in Sequencer editor: right-click actor track → "Change to Spawnable"
// At runtime, actor spawns when sequence reaches its range, despawns when exiting
// Dynamic possessable: bind a gameplay-spawned actor to a sequence track
// Create the binding ID in the editor, then override at runtime:
FMovieSceneObjectBindingID BindingID = /* from sequence editor */;
ALevelSequenceActor* SeqActor = /* your sequence actor */;
SeqActor->SetBinding(BindingID, {SpawnedActor});// LevelSequenceActor.h — all binding API lives here
// Replace bound actors (preferred: tag-based, resilient to GUID changes)
SeqActor->SetBindingByTag(FName("Hero"), TArray<AActor*>{ HeroActor },
/*bAllowBindingsFromAsset=*/ false);
// GUID-based (expose FMovieSceneObjectBindingID via UPROPERTY for editor assignment)
// UPROPERTY(EditAnywhere) FMovieSceneObjectBindingID HeroBindingID;
SeqActor->SetBinding(HeroBindingID, TArray<AActor*>{ HeroActor }, false);
// Append without removing existing bindings
SeqActor->AddBindingByTag(FName("NPC"), NpcActor, /*bAllowBindingsFromAsset=*/ true);
// Remove / reset
SeqActor->RemoveBindingByTag(FName("NPC"), NpcActor);
SeqActor->ResetBinding(HeroBindingID); // revert to asset binding
SeqActor->ResetBindings(); // revert all overrides
// Lookup by tag
FMovieSceneObjectBindingID ID = SeqActor->FindNamedBinding(FName("Hero"));
const TArray<FMovieSceneObjectBindingID>& All = SeqActor->FindNamedBindings(FName("NPC"));
// Inspect what is currently bound
TArray<UObject*> Bound = Player->GetBoundObjects(HeroBindingID);
// FMovieSceneObjectBindingID (MovieSceneObjectBindingID.h):
// Access via public accessors — internal fields are private:
// GetGuid() — FGuid identifying the binding track
// GetRelativeSequenceID() — which sub-sequence holds it (0 = local)// CineCameraActor.h: UCineCameraComponent* GetCineCameraComponent() const;
// CineCameraComponent.h / CineCameraSettings.h:
// FCameraFilmbackSettings Filmback (SensorWidth, SensorHeight in mm, read-only SensorAspectRatio)
// FCameraLensSettings LensSettings (MinFocalLength, MaxFocalLength, MinFStop, MaxFStop mm)
// FCameraFocusSettings FocusSettings (FocusMethod, ManualFocusDistance cm, bSmoothFocusChanges)
// float CurrentFocalLength — Interp, animatable in Sequencer
// float CurrentAperture — f-stop, Interp-animatable
ACineCameraActor* Cam = GetWorld()->SpawnActor<ACineCameraActor>(SpawnTransform);
UCineCameraComponent* CC = Cam->GetCineCameraComponent();
FCameraFilmbackSettings FB;
FB.SensorWidth = 36.0f; FB.SensorHeight = 24.0f; // full-frame 35mm
CC->SetFilmback(FB);
CC->SetCurrentFocalLength(50.0f); // mm
CC->SetCurrentAperture(2.0f); // f-stop
FCameraFocusSettings FS;
FS.FocusMethod = ECameraFocusMethod::Manual; // Manual | Tracking | Disable | DoNotOverride
FS.ManualFocusDistance = 500.0f; // cm
FS.bSmoothFocusChanges = true;
CC->SetFocusSettings(FS);
// Lookat tracking (CineCameraActor.h: FCameraLookatTrackingSettings LookatTrackingSettings)
Cam->LookatTrackingSettings.bEnableLookAtTracking = true;
Cam->LookatTrackingSettings.ActorToTrack = TargetActor;
Cam->LookatTrackingSettings.LookAtTrackingInterpSpeed = 5.0f;
Cam->LookatTrackingSettings.RelativeOffset = FVector(0, 0, 90.f);
// Prevent sequence from overriding gameplay camera (set before Play)
SeqActor->PlaybackSettings.bDisableCameraCuts = true;
// Restore player camera after cutscene (call from OnFinished delegate)
APlayerController* PC = GetWorld()->GetFirstPlayerController();
PC->SetViewTargetWithBlend(PC->GetPawn(), 0.5f, VTBlend_Cubic);
PC->SetIgnoreMoveInput(false);
PC->SetIgnoreLookInput(false);APlayerCameraManagerPlayerController->PlayerCameraManagerAPlayerController* PC = GetWorld()->GetFirstPlayerController();
// PlayerCameraManager handles blend state; SetViewTargetWithBlend triggers it.
PC->SetViewTargetWithBlend(PC->GetPawn(), 0.5f, VTBlend_Cubic);
// The blend is processed each tick inside APlayerCameraManager::UpdateCamera.UFUNCTIONUWorldALevelScriptActor// Function must be UFUNCTION(BlueprintCallable) on a context object
UFUNCTION(BlueprintCallable, Category = "Cinematics")
void TriggerExplosion()
{
ExplosionSystem->SpawnExplosion(ExplosionLocation);
}
// Trigger C++ code at a specific frame by playing to it (fires all events in range)
Player->PlayTo(
FMovieSceneSequencePlaybackParams(FFrameTime(60), EUpdatePositionMethod::Play),
FMovieSceneSequencePlayToParams());FMovieSceneEventUMovieSceneEventTrackUMovieSceneEventTriggerSectionFMovieSceneEventUWorldALevelScriptActorULevelSequenceDirectorULevelSequenceDirector// MySequenceDirector.h
#include "LevelSequenceDirector.h"
#include "MySequenceDirector.generated.h"
UCLASS(Blueprintable)
class UMySequenceDirector : public ULevelSequenceDirector
{
GENERATED_BODY()
public:
// Called from Sequencer event tracks — bind to event key in the Sequencer editor
UFUNCTION(BlueprintCallable, Category = "Cinematics")
void OnDialogueStart(FName SpeakerTag);
UFUNCTION(BlueprintCallable, Category = "Cinematics")
void OnCutsceneChoice(int32 ChoiceIndex);
};
// MySequenceDirector.cpp
void UMySequenceDirector::OnDialogueStart(FName SpeakerTag)
{
// Access the sequence player and bound actors from within the Director.
// ULevelSequenceDirector.h: UPROPERTY ULevelSequencePlayer* Player (direct field, no getter)
TArray<UObject*> Bound = Player->GetBoundObjects(SpeakerBindingID);
// Trigger gameplay logic: UI, dialogue system, camera focus, etc.
}// MovieScene.h — get from the LevelSequence asset
UMovieScene* MS = SeqActor->GetSequence()->GetMovieScene();
// Possessables (world actors) — iterate by index
for (int32 i = 0; i < MS->GetPossessableCount(); ++i)
{
const FMovieScenePossessable& P = MS->GetPossessable(i);
}
// Spawnables (sequence-owned actors) — iterate by index
for (int32 i = 0; i < MS->GetSpawnableCount(); ++i)
{
const FMovieSceneSpawnable& S = MS->GetSpawnable(i);
}
// Master tracks (not bound to any actor)
const TArray<UMovieSceneTrack*>& Masters = MS->GetTracks();
// Tracks on a specific binding
const FMovieSceneBinding* B = MS->FindBinding(SomeGuid);
if (B) { for (UMovieSceneTrack* T : B->GetTracks()) { /* cast to subtype */ } }| Track Class | Purpose |
|---|---|
| Transform animation |
| Skeletal mesh animation |
| Event triggers |
| Audio |
| Screen fade |
| Camera cuts |
| Sub-sequences |
| Arbitrary UPROPERTY animation (base class) |
MovieSceneTracksUMovieSceneTrackUMovieSceneSectionISequencerModule::RegisterTrackEditorUMovieScenePropertyTrackUMovieScenePropertyTrackUPROPERTYUMovieSceneFloatTrackUMovieSceneBoolTrackUMovieSceneColorTrackUMovieSceneFloatSectionFMovieSceneFloatChannel// Add a sub-sequence track to a master UMovieScene
UMovieScene* MasterMS = MasterSequence->GetMovieScene();
UMovieSceneSubTrack* SubTrack = MasterMS->AddTrack<UMovieSceneSubTrack>();
// Add a child sequence — AddSequence(Sequence, StartFrame, Duration)
FFrameRate DisplayRate = MasterMS->GetDisplayRate();
FFrameNumber Start = (2.0 * DisplayRate).FloorToFrame(); // 2 seconds in
int32 Duration = (5.0 * DisplayRate).FloorToFrame().Value; // 5 seconds long
UMovieSceneSubSection* SubSection =
SubTrack->AddSequence(ChildLevelSequence, Start, Duration);
// Configure sub-section timing
SubSection->Parameters.TimeScale = 1.0; // FMovieSceneTimeWarpVariant (double), playback speed multiplier
SubSection->Parameters.bCanLoop = false;UMovieSceneSubTrackAddTrackSequenceIDFMovieSceneObjectBindingID::ResolveParentIndexMovieSceneTracksPlayer->SetPlayRate(0.5f)UGameplayStatics::SetGlobalTimeDilation// MovieRenderPipelineCore module. Classes:
// UMoviePipelineQueue — holds jobs
// UMoviePipelineExecutorJob — sequence + map + config per job
// UMoviePipelinePrimaryConfig — root settings container
// UMoviePipelineOutputSetting — output path, file name format, frame rate
// Output formats: UMoviePipelineImageSequenceOutput_PNG / _EXR, UMoviePipelineAppleProResOutput
// Render passes: UMoviePipelineDeferredPassBase (final color, world normal, base color, depth)
// Add passes to the PrimaryConfig to capture multiple AOVs per frame
UMoviePipelineQueue* Queue = NewObject<UMoviePipelineQueue>(this);
UMoviePipelineExecutorJob* Job =
Queue->AllocateNewJob(UMoviePipelineExecutorJob::StaticClass());
Job->Sequence = FSoftObjectPath(MySequence);
Job->Map = FSoftObjectPath(GetWorld());
Job->JobName = TEXT("MyRender");
Job->SetConfiguration(NewObject<UMoviePipelinePrimaryConfig>(Job));
// Add pass/output settings to Job->GetConfiguration() as needed.
// Execute the render (editor only — MovieRenderPipelineEditor module)
UMoviePipelineQueueEngineSubsystem* QueueSubsystem =
GEngine->GetEngineSubsystem<UMoviePipelineQueueEngineSubsystem>();
QueueSubsystem->RenderQueueWithExecutor(UMoviePipelineInProcessExecutor::StaticClass());
// For runtime/non-editor rendering, implement UMoviePipelineExecutorBase instead.Play()SetBinding*Play()SeqActor->SetReplicatePlayback(true)OnFinishedSetViewTargetWithBlendCreateLevelSequencePlayerOutActorUPROPERTY()SetCompletionModeOverride(ForceRestoreState)Stop()GetCurrentTime()SeqActor->SequencePlayerSeqActor->GetSequencePlayer()Play()ULevelSequencePlayerALevelSequenceActorALevelSequenceActorue-actor-component-architectureue-animation-systemue-cpp-foundationsUFUNCTIONUPROPERTYue-gameplay-framework