ue-sequencer-cinematics

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Skill: ue-sequencer-cinematics

技能:ue-sequencer-cinematics

You are an expert in Unreal Engine's Sequencer and cinematic systems.
你是Unreal Engine的Sequencer和镜头系统专家。

Context Check

上下文检查

Read
.agents/ue-project-context.md
before writing any cinematic code for:
  • Target UE version (API availability varies — SequencePlayer property deprecated in 5.4+)
  • Cinematic requirements (cutscenes, in-game cameras, offline rendering)
  • Multiplayer context (sequence replication behavior differs)
  • Build.cs modules already declared
在编写任何镜头代码之前,请阅读
.agents/ue-project-context.md
,了解以下内容:
  • 目标UE版本(API可用性因版本而异——SequencePlayer属性在5.4+中已被弃用)
  • 镜头需求(过场动画、游戏内镜头、离线渲染)
  • 多人游戏上下文(序列同步行为不同)
  • 已声明的Build.cs模块

Information Gathering

信息收集

Ask for:
  1. Cinematic type: full-screen cutscene, in-game camera, or background ambient sequence
  2. Whether actors bind at runtime or are pre-placed in the level
  3. Whether camera control must return to the player after playback
  4. One-shot or looping sequence
  5. Real-time gameplay or offline Movie Render Queue output

请询问以下信息:
  1. 镜头类型:全屏过场动画、游戏内镜头还是背景环境序列
  2. 角色是在运行时绑定还是预先放置在关卡中
  3. 播放结束后是否需要将镜头控制权交还给玩家
  4. 是一次性播放还是循环播放序列
  5. 是实时游戏还是离线Movie Render Queue输出

Build.cs Modules

Build.cs模块

csharp
PublicDependencyModuleNames.AddRange(new string[]
{
    "LevelSequence", "MovieScene", "CinematicCamera",
});
// Offline rendering only:
PrivateDependencyModuleNames.Add("MovieRenderPipelineCore");

csharp
PublicDependencyModuleNames.AddRange(new string[]
{
    "LevelSequence", "MovieScene", "CinematicCamera",
});
// 仅离线渲染时添加:
PrivateDependencyModuleNames.Add("MovieRenderPipelineCore");

Playing Level Sequences

播放Level Sequence

ALevelSequenceActor — World-Placed

ALevelSequenceActor — 放置于世界中

ALevelSequenceActor
owns the player. Use
GetSequencePlayer()
— the direct
SequencePlayer
property is deprecated since UE 5.4.
cpp
// LevelSequenceActor.h: ULevelSequencePlayer* GetSequencePlayer() const;
ULevelSequencePlayer* Player = SeqActor->GetSequencePlayer();
if (Player) { Player->Play(); }
ALevelSequenceActor
拥有播放器实例。使用
GetSequencePlayer()
——直接访问
SequencePlayer
属性在UE 5.4及以上版本已被弃用。
cpp
// LevelSequenceActor.h: ULevelSequencePlayer* GetSequencePlayer() const;
ULevelSequencePlayer* Player = SeqActor->GetSequencePlayer();
if (Player) { Player->Play(); }

ULevelSequencePlayer::CreateLevelSequencePlayer — Runtime Spawn

ULevelSequencePlayer::CreateLevelSequencePlayer — 运行时生成

cpp
// 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();
}
cpp
// 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=播放一次,-1=无限循环
Settings.bDisableMovementInput  = true;
Settings.bDisableLookAtInput    = true;
Settings.bHidePlayer            = false;
Settings.bHideHud               = false;
Settings.bDisableCameraCuts     = false;
Settings.bPauseAtEnd            = false;
Settings.FinishCompletionStateOverride =
    EMovieSceneCompletionModeOverride::ForceRestoreState; // 适用于可跳过的过场动画

ALevelSequenceActor* OutActor = nullptr;
ULevelSequencePlayer* Player  = ULevelSequencePlayer::CreateLevelSequencePlayer(
    this, Sequence, Settings, OutActor);

// 将OutActor存储在UPROPERTY中以防止被垃圾回收
ActiveSequenceActor = OutActor;

if (Player)
{
    Player->OnFinished.AddDynamic(this, &AMyClass::OnCutsceneFinished);
    Player->Play();
}

Play Control (UMovieSceneSequencePlayer base)

播放控制(基于UMovieSceneSequencePlayer)

cpp
// 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.ActiveShot

cpp
// MovieSceneSequencePlayer.h
Player->Play();
Player->PlayReverse();
Player->PlayLooping(-1);       // -1 = 无限循环
Player->Pause();
Player->Stop();                // 将播放指针移至末尾,触发OnStop
Player->StopAtCurrentTime();
Player->GoToEndAndStop();
Player->SetPlayRate(0.5f);     // 负值为倒放

// 跳转到指定帧(跳过当前帧与目标帧之间的所有事件)
// 蓝图中此功能为GoToFrame,在C++中使用SetPlaybackPosition并指定Jump方式
Player->SetPlaybackPosition(
    FMovieSceneSequencePlaybackParams(FFrameTime(120), EUpdatePositionMethod::Jump));

// 播放到指定帧(触发范围内的所有事件)
Player->PlayTo(
    FMovieSceneSequencePlaybackParams(FFrameTime(240), EUpdatePositionMethod::Play),
    FMovieSceneSequencePlayToParams());

// 限制播放范围
Player->SetFrameRange(0, 60);           // 帧范围0–60
Player->SetTimeRange(0.0f, 2.5f);       // 时间范围0.0–2.5秒

// 状态查询
bool bPlaying = Player->IsPlaying();
FQualifiedFrameTime Now = Player->GetCurrentTime();
FQualifiedFrameTime Dur = Player->GetDuration();

// 委托(需在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); // 非动态委托

// 镜头切换事件(LevelSequencePlayer.h)
// DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnLevelSequencePlayerCameraCutEvent, UCameraComponent*, CameraComponent)
LsPlayer->OnCameraCut.AddDynamic(this, &UMyClass::OnCameraCut);

// 提前停止时恢复状态(适用于可跳过的过场动画)
Player->SetCompletionModeOverride(EMovieSceneCompletionModeOverride::ForceRestoreState);
Player->Stop();

// 子序列快照
FLevelSequencePlayerSnapshot Snap;
Player->TakeFrameSnapshot(Snap);
// Snap.CurrentShotName, Snap.RootTime, Snap.CameraComponent, Snap.ActiveShot

Actor Binding

Actor绑定

Tag bindings in Sequencer (right-click object binding -> Tags...) then override at runtime. Always bind before calling
Play()
.
在Sequencer中为绑定添加标签(右键对象绑定 → 标签...),然后在运行时覆盖。务必在调用
Play()
之前完成绑定。

Spawnables vs Possessables

Spawnables与Possessables

Possessables bind to pre-existing world actors (placed in level or spawned by gameplay). Spawnables are actors the sequence itself creates and destroys.
cpp
// 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});
Why this matters: Use possessables for persistent world actors (doors, elevators) and spawnables for transient cutscene-only actors (cinematic-only characters, props). Possessables survive sequence end; spawnables are cleaned up automatically.
cpp
// 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)

Possessables绑定到已存在的世界Actor(放置在关卡中或由游戏逻辑生成)。Spawnables是由序列自身创建和销毁的Actor。
cpp
// Spawnable:序列拥有Actor的生命周期
// 在Sequencer编辑器中设置:右键Actor轨道 → "切换为Spawnable"
// 运行时,Actor会在序列到达其时间范围时生成,离开时间范围时销毁

// 动态Possessable:将游戏逻辑生成的Actor绑定到序列轨道
// 在编辑器中创建绑定ID,然后在运行时覆盖:
FMovieSceneObjectBindingID BindingID = /* 来自序列编辑器 */;
ALevelSequenceActor* SeqActor = /* 你的序列Actor */;
SeqActor->SetBinding(BindingID, {SpawnedActor});
为何区分:对持久化世界Actor(门、电梯)使用Possessables,对仅用于过场的临时Actor(仅镜头角色、道具)使用Spawnables。Possessables在序列结束后保留;Spawnables会被自动清理。
cpp
// LevelSequenceActor.h — 所有绑定API都在此

// 替换绑定的Actor(推荐:基于标签,可应对GUID变更)
SeqActor->SetBindingByTag(FName("Hero"), TArray<AActor*>{ HeroActor },
    /*bAllowBindingsFromAsset=*/ false);

// 基于GUID(通过UPROPERTY暴露FMovieSceneObjectBindingID以便在编辑器中赋值)
// UPROPERTY(EditAnywhere) FMovieSceneObjectBindingID HeroBindingID;
SeqActor->SetBinding(HeroBindingID, TArray<AActor*>{ HeroActor }, false);

// 追加绑定而不移除现有绑定
SeqActor->AddBindingByTag(FName("NPC"), NpcActor, /*bAllowBindingsFromAsset=*/ true);

// 移除/重置绑定
SeqActor->RemoveBindingByTag(FName("NPC"), NpcActor);
SeqActor->ResetBinding(HeroBindingID);  // 恢复为资源中的绑定
SeqActor->ResetBindings();              // 恢复所有覆盖的绑定

// 通过标签查找
FMovieSceneObjectBindingID ID = SeqActor->FindNamedBinding(FName("Hero"));
const TArray<FMovieSceneObjectBindingID>& All = SeqActor->FindNamedBindings(FName("NPC"));

// 检查当前绑定的对象
TArray<UObject*> Bound = Player->GetBoundObjects(HeroBindingID);

// FMovieSceneObjectBindingID (MovieSceneObjectBindingID.h):
//   通过公共访问器访问——内部字段为私有:
//     GetGuid()              — 标识绑定轨道的FGuid
//     GetRelativeSequenceID() — 子序列的ID(0表示本地)

Camera System

镜头系统

ACineCameraActor / UCineCameraComponent

ACineCameraActor / UCineCameraComponent

cpp
// 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);
cpp
// CineCameraActor.h: UCineCameraComponent* GetCineCameraComponent() const;
// CineCameraComponent.h / CineCameraSettings.h:
//   FCameraFilmbackSettings Filmback  (SensorWidth、SensorHeight单位为毫米,只读的SensorAspectRatio)
//   FCameraLensSettings LensSettings  (MinFocalLength、MaxFocalLength、MinFStop、MaxFStop单位为毫米)
//   FCameraFocusSettings FocusSettings (FocusMethod、ManualFocusDistance单位为厘米,bSmoothFocusChanges)
//   float CurrentFocalLength  — 可插值,可在Sequencer中动画
//   float CurrentAperture     — f值,可插值动画

ACineCameraActor* Cam = GetWorld()->SpawnActor<ACineCameraActor>(SpawnTransform);
UCineCameraComponent* CC = Cam->GetCineCameraComponent();

FCameraFilmbackSettings FB;
FB.SensorWidth = 36.0f; FB.SensorHeight = 24.0f;  // 全画幅35mm
CC->SetFilmback(FB);

CC->SetCurrentFocalLength(50.0f);   // 毫米
CC->SetCurrentAperture(2.0f);       // f值

FCameraFocusSettings FS;
FS.FocusMethod         = ECameraFocusMethod::Manual;  // Manual | Tracking | Disable | DoNotOverride
FS.ManualFocusDistance = 500.0f;    // 厘米
FS.bSmoothFocusChanges = true;
CC->SetFocusSettings(FS);

// 看向跟踪(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);

// 防止序列覆盖游戏镜头(在Play()之前设置)
SeqActor->PlaybackSettings.bDisableCameraCuts = true;

// 过场结束后恢复玩家镜头(从OnFinished委托中调用)
APlayerController* PC = GetWorld()->GetFirstPlayerController();
PC->SetViewTargetWithBlend(PC->GetPawn(), 0.5f, VTBlend_Cubic);
PC->SetIgnoreMoveInput(false);
PC->SetIgnoreLookInput(false);

APlayerCameraManager

APlayerCameraManager

APlayerCameraManager
(accessed via
PlayerController->PlayerCameraManager
) manages camera blending and view target selection for the local player. After a cutscene ends, restore the gameplay camera explicitly — Sequencer does not do this automatically:
cpp
APlayerController* 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.

APlayerCameraManager
(通过
PlayerController->PlayerCameraManager
访问)为本地玩家管理镜头混合和视图目标选择。过场结束后,需显式恢复游戏镜头——Sequencer不会自动执行此操作:
cpp
APlayerController* PC = GetWorld()->GetFirstPlayerController();
// PlayerCameraManager处理混合状态;SetViewTargetWithBlend触发混合
PC->SetViewTargetWithBlend(PC->GetPawn(), 0.5f, VTBlend_Cubic);
// 混合在APlayerCameraManager::UpdateCamera的每帧中处理

Sequencer Events

Sequencer事件

Event tracks call
UFUNCTION
s on objects in the event context. Default event context:
UWorld
+
ALevelScriptActor
.
cpp
// 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());
事件轨道会调用事件上下文中对象的
UFUNCTION
。默认事件上下文:
UWorld
+
ALevelScriptActor
cpp
// 函数必须是上下文对象上的UFUNCTION(BlueprintCallable)
UFUNCTION(BlueprintCallable, Category = "Cinematics")
void TriggerExplosion()
{
    ExplosionSystem->SpawnExplosion(ExplosionLocation);
}

// 通过播放到指定帧来触发C++代码(触发范围内的所有事件)
Player->PlayTo(
    FMovieSceneSequencePlaybackParams(FFrameTime(60), EUpdatePositionMethod::Play),
    FMovieSceneSequencePlayToParams());

FMovieSceneEvent

FMovieSceneEvent

FMovieSceneEvent
holds the event endpoint data — the bound function to call when the event fires. Event tracks are structured as:
  • UMovieSceneEventTrack
    — the master track added to a binding or as a master track
  • UMovieSceneEventTriggerSection
    — a section containing one or more trigger entries
  • FMovieSceneEvent
    — each entry inside the trigger section, pointing to the endpoint function
The endpoint function is resolved at runtime against the event context objects (by default
UWorld
and
ALevelScriptActor
). Director-based events resolve against a
ULevelSequenceDirector
subclass instance.
FMovieSceneEvent
存储事件端点数据——事件触发时要调用的绑定函数。事件轨道的结构如下:
  • UMovieSceneEventTrack
    — 添加到绑定或作为主轨道的主轨道
  • UMovieSceneEventTriggerSection
    — 包含一个或多个触发条目的区段
  • FMovieSceneEvent
    — 触发区段内的每个条目,指向端点函数
端点函数会在运行时根据事件上下文对象(默认是
UWorld
ALevelScriptActor
)解析。基于导演的事件会针对
ULevelSequenceDirector
子类实例解析。

ULevelSequenceDirector — Custom Event Context

ULevelSequenceDirector — 自定义事件上下文

ULevelSequenceDirector
provides a per-sequence scripting context that receives event track calls. Subclass it (Blueprint or C++) and assign to the LevelSequence asset's Director Class property. The Director instance is created when the sequence begins playing and destroyed when it stops — its lifetime matches the sequence player.
cpp
// 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.
}
Why Director over Level Script: The Director travels with the sequence asset, not the level. Reusable across maps. Supports per-sequence state (member variables). Level Script events only work when the sequence is placed in that specific level.

ULevelSequenceDirector
提供了每个序列的脚本上下文,用于接收事件轨道的调用。继承它(蓝图或C++)并分配给LevelSequence资源的Director Class属性。导演实例会在序列开始播放时创建,停止时销毁——其生命周期与序列播放器一致。
cpp
// MySequenceDirector.h
#include "LevelSequenceDirector.h"
#include "MySequenceDirector.generated.h"

UCLASS(Blueprintable)
class UMySequenceDirector : public ULevelSequenceDirector
{
    GENERATED_BODY()
public:
    // 从Sequencer事件轨道调用——在Sequencer编辑器中绑定到事件关键帧
    UFUNCTION(BlueprintCallable, Category = "Cinematics")
    void OnDialogueStart(FName SpeakerTag);

    UFUNCTION(BlueprintCallable, Category = "Cinematics")
    void OnCutsceneChoice(int32 ChoiceIndex);
};

// MySequenceDirector.cpp
void UMySequenceDirector::OnDialogueStart(FName SpeakerTag)
{
    // 在导演类中访问序列播放器和绑定的Actor。
    // ULevelSequenceDirector.h: UPROPERTY ULevelSequencePlayer* Player(直接字段,无getter)
    TArray<UObject*> Bound = Player->GetBoundObjects(SpeakerBindingID);
    // 触发游戏逻辑:UI、对话系统、镜头对焦等。
}
为何选择导演类而非关卡脚本:导演类随序列资源移动,不依赖关卡。可在多个地图中复用。支持每个序列的状态(成员变量)。关卡脚本事件仅在序列放置于特定关卡时生效。

MovieScene Tracks

MovieScene轨道

cpp
// 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 ClassPurpose
UMovieScene3DTransformTrack
Transform animation
UMovieSceneSkeletalAnimationTrack
Skeletal mesh animation
UMovieSceneEventTrack
Event triggers
UMovieSceneAudioTrack
Audio
UMovieSceneFadeTrack
Screen fade
UMovieSceneCameraCutTrack
Camera cuts
UMovieSceneSubTrack
Sub-sequences
UMovieScenePropertyTrack
Arbitrary UPROPERTY animation (base class)
All track types require
MovieSceneTracks
in Build.cs.
Custom tracks: subclass
UMovieSceneTrack
+
UMovieSceneSection
for domain-specific animation data. Register via
ISequencerModule::RegisterTrackEditor
. This is an advanced pattern — most needs are met by
UMovieScenePropertyTrack
subclasses.
UMovieScenePropertyTrack
animates arbitrary
UPROPERTY
values on bound objects. Common concrete subclasses:
UMovieSceneFloatTrack
(float properties),
UMovieSceneBoolTrack
(bool properties),
UMovieSceneColorTrack
(FLinearColor / FColor properties). Each creates sections of the matching type (e.g.,
UMovieSceneFloatSection
) that store a
FMovieSceneFloatChannel
.
cpp
// MovieScene.h — 从LevelSequence资源获取
UMovieScene* MS = SeqActor->GetSequence()->GetMovieScene();

// Possessables(世界Actor)——按索引遍历
for (int32 i = 0; i < MS->GetPossessableCount(); ++i)
{
    const FMovieScenePossessable& P = MS->GetPossessable(i);
}
// Spawnables(序列拥有的Actor)——按索引遍历
for (int32 i = 0; i < MS->GetSpawnableCount(); ++i)
{
    const FMovieSceneSpawnable& S = MS->GetSpawnable(i);
}

// 主轨道(不绑定到任何Actor)
const TArray<UMovieSceneTrack*>& Masters = MS->GetTracks();

// 特定绑定的轨道
const FMovieSceneBinding* B = MS->FindBinding(SomeGuid);
if (B) { for (UMovieSceneTrack* T : B->GetTracks()) { /* 转换为子类型 */ } }
轨道类用途
UMovieScene3DTransformTrack
变换动画
UMovieSceneSkeletalAnimationTrack
骨骼网格动画
UMovieSceneEventTrack
事件触发
UMovieSceneAudioTrack
音频
UMovieSceneFadeTrack
屏幕淡入淡出
UMovieSceneCameraCutTrack
镜头切换
UMovieSceneSubTrack
子序列
UMovieScenePropertyTrack
任意UPROPERTY动画(基类)
所有轨道类型都需要在Build.cs中添加
MovieSceneTracks
模块。
自定义轨道:继承
UMovieSceneTrack
+
UMovieSceneSection
以实现领域特定的动画数据。通过
ISequencerModule::RegisterTrackEditor
注册。这是高级模式——大多数需求可通过
UMovieScenePropertyTrack
的子类满足。
UMovieScenePropertyTrack
为绑定对象的任意
UPROPERTY
值制作动画。常见的具体子类:
UMovieSceneFloatTrack
(浮点属性)、
UMovieSceneBoolTrack
(布尔属性)、
UMovieSceneColorTrack
(FLinearColor / FColor属性)。每个子类都会创建对应类型的区段(例如
UMovieSceneFloatSection
),存储
FMovieSceneFloatChannel

Sub-Sequences

子序列

cpp
// 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;
UMovieSceneSubTrack
is a singleton master track —
AddTrack
returns the existing one if already present. Binding IDs inside sub-sequences carry a non-zero
SequenceID
; use
FMovieSceneObjectBindingID::ResolveParentIndex
when overriding bindings from the root player. Requires
MovieSceneTracks
module.
cpp
// 为主UMovieScene添加子序列轨道
UMovieScene* MasterMS = MasterSequence->GetMovieScene();
UMovieSceneSubTrack* SubTrack = MasterMS->AddTrack<UMovieSceneSubTrack>();

// 添加子序列——AddSequence(Sequence, StartFrame, Duration)
FFrameRate DisplayRate = MasterMS->GetDisplayRate();
FFrameNumber Start = (2.0 * DisplayRate).FloorToFrame(); // 2秒处
int32 Duration = (5.0 * DisplayRate).FloorToFrame().Value; // 时长5秒
UMovieSceneSubSection* SubSection =
    SubTrack->AddSequence(ChildLevelSequence, Start, Duration);

// 配置子区段的时间
SubSection->Parameters.TimeScale = 1.0;   // FMovieSceneTimeWarpVariant(双精度),播放速度倍数
SubSection->Parameters.bCanLoop = false;
UMovieSceneSubTrack
是单例主轨道——
AddTrack
会返回已存在的轨道(如果有的话)。子序列内的绑定ID带有非零的
SequenceID
;从根播放器覆盖绑定时,使用
FMovieSceneObjectBindingID::ResolveParentIndex
。需要
MovieSceneTracks
模块。

Time Dilation and SlowMo

时间 dilation与慢动作

For SlowMo effects during sequences, use
Player->SetPlayRate(0.5f)
on the sequence player — this is independent of
UGameplayStatics::SetGlobalTimeDilation
and does not affect world physics or other gameplay systems. Combine with a post-process motion blur intensity increase for cinematic slow motion without disrupting gameplay state.

要在序列中实现慢动作效果,使用序列播放器的
Player->SetPlayRate(0.5f)
——这与
UGameplayStatics::SetGlobalTimeDilation
无关,不会影响世界物理或其他游戏系统。结合后期处理的运动模糊强度增加,可实现不破坏游戏状态的镜头慢动作。

Movie Render Queue

Movie Render Queue

cpp
// 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.

cpp
// MovieRenderPipelineCore模块。相关类:
//   UMoviePipelineQueue           — 存储任务
//   UMoviePipelineExecutorJob     — 每个任务包含序列+地图+配置
//   UMoviePipelinePrimaryConfig   — 根设置容器
//   UMoviePipelineOutputSetting   — 输出路径、文件名格式、帧率
// 输出格式:UMoviePipelineImageSequenceOutput_PNG / _EXR, UMoviePipelineAppleProResOutput
// 渲染通道:UMoviePipelineDeferredPassBase(最终颜色、世界法线、基础颜色、深度)
//   向PrimaryConfig添加通道以捕获每帧的多个AOV

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));
// 根据需要向Job->GetConfiguration()添加通道/输出设置。

// 执行渲染(仅编辑器——需要MovieRenderPipelineEditor模块)
UMoviePipelineQueueEngineSubsystem* QueueSubsystem =
    GEngine->GetEngineSubsystem<UMoviePipelineQueueEngineSubsystem>();
QueueSubsystem->RenderQueueWithExecutor(UMoviePipelineInProcessExecutor::StaticClass());
// 对于运行时/非编辑器渲染,需自行实现UMoviePipelineExecutorBase。

Common Mistakes

常见错误

Binding after Play: Overrides applied after
Play()
miss frame 0. Always
SetBinding*
before
Play()
.
Multiplayer camera cuts: Camera cuts only affect the local client. Use
SeqActor->SetReplicatePlayback(true)
for server-driven sync.
Camera not returning after cutscene: Sequencer does not auto-restore the player camera. Subscribe to
OnFinished
and call
SetViewTargetWithBlend
+ re-enable input.
GC of spawned sequence actor:
CreateLevelSequencePlayer
returns a raw pointer. Store
OutActor
in a
UPROPERTY()
member to prevent garbage collection.
Skipping mid-sequence: Call
SetCompletionModeOverride(ForceRestoreState)
before
Stop()
so actors return to their pre-sequence state.
PIE timing: Avoid wall-clock assumptions; use
GetCurrentTime()
frame numbers.
Deprecated direct property:
SeqActor->SequencePlayer
is deprecated since UE 5.4. Use
SeqActor->GetSequencePlayer()
.
Wrong player instance: Calling
Play()
on a stale or mismatched
ULevelSequencePlayer
pointer (e.g., from a different
ALevelSequenceActor
in the level) produces no visible effect or animates the wrong actors. Always retrieve the player from the specific
ALevelSequenceActor
that owns the sequence you intend to drive.

播放后绑定:在
Play()
之后应用的覆盖会错过第0帧。务必在
Play()
之前调用
SetBinding*
多人游戏镜头切换:镜头切换仅影响本地客户端。使用
SeqActor->SetReplicatePlayback(true)
实现服务器驱动的同步。
过场后镜头未恢复:Sequencer不会自动恢复玩家镜头。订阅
OnFinished
并调用
SetViewTargetWithBlend
+ 重新启用输入。
生成的序列Actor被垃圾回收
CreateLevelSequencePlayer
返回原始指针。将
OutActor
存储在
UPROPERTY()
成员中以防止被垃圾回收。
中途跳过序列:在调用
Stop()
之前调用
SetCompletionModeOverride(ForceRestoreState)
,使Actor恢复到序列前的状态。
PIE时序问题:避免依赖挂钟时间;使用
GetCurrentTime()
的帧编号。
已弃用的直接属性
SeqActor->SequencePlayer
在UE 5.4及以上版本已被弃用。使用
SeqActor->GetSequencePlayer()
错误的播放器实例:在过期或不匹配的
ULevelSequencePlayer
指针上调用
Play()
(例如来自关卡中另一个
ALevelSequenceActor
)会导致无可见效果或动画错误的Actor。务必从你要控制的序列所属的特定
ALevelSequenceActor
中获取播放器。

Related Skills

相关技能

  • ue-actor-component-architecture
    — actor spawning and component setup for bound actors
  • ue-animation-system
    — skeletal animation tracks, AnimMontage integration in Sequencer
  • ue-cpp-foundations
    — delegate patterns,
    UFUNCTION
    ,
    UPROPERTY
  • ue-gameplay-framework
    — PlayerController camera restoration, GameMode flow
  • ue-actor-component-architecture
    — 绑定Actor的生成与组件设置
  • ue-animation-system
    — 骨骼动画轨道、AnimMontage与Sequencer的集成
  • ue-cpp-foundations
    — 委托模式、
    UFUNCTION
    UPROPERTY
  • ue-gameplay-framework
    — PlayerController镜头恢复、GameMode流程