claude-code-arcane 2.2.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +104 -55
- package/agents/career/career-strategist.md +88 -0
- package/agents/career/cv-reviewer.md +81 -0
- package/agents/career/hiring-manager.md +68 -0
- package/agents/career/mock-interviewer.md +76 -0
- package/agents/freelance/client-screener.md +84 -0
- package/agents/freelance/discovery-call.md +65 -0
- package/agents/freelance/pipeline-strategist.md +99 -0
- package/agents/freelance/proposal-reviewer.md +82 -0
- package/agents/game/ue-blueprint-specialist.md +125 -0
- package/agents/game/ue-gas-specialist.md +133 -0
- package/agents/game/ue-umg-specialist.md +131 -0
- package/dist/cli.js +57 -13
- package/docs/RELEASE-SETUP.md +1 -1
- package/docs/SKILLS-CATALOG.md +67 -4
- package/docs/USER-GUIDE.md +77 -72
- package/docs/agent-hierarchy.md +21 -1
- package/docs/presentations/build_arcane_deck.py +2 -2
- package/docs/presentations/build_arcane_deck_12.py +2 -2
- package/hooks/detect-unreal.sh +90 -0
- package/package.json +2 -2
- package/profiles/freelance.yaml +43 -0
- package/profiles/job-hunt.yaml +5 -2
- package/profiles/unreal-dev.yaml +97 -0
- package/rules/drafter-reviewer.md +16 -3
- package/rules/freelance-guardrails.md +53 -0
- package/rules/gamedev/unreal-code.md +125 -0
- package/skills/career-registry/SKILL.md +95 -0
- package/skills/career-registry/scripts/career_registry.py +488 -0
- package/skills/client-screen/SKILL.md +83 -0
- package/skills/client-screen/references/red-flags.md +95 -0
- package/skills/cover-letter/SKILL.md +4 -3
- package/skills/cv-tailor/SKILL.md +11 -2
- package/skills/freelance-deliver/SKILL.md +90 -0
- package/skills/freelance-hunt/SKILL.md +126 -0
- package/skills/freelance-hunt/references/templates/Connects.md +39 -0
- package/skills/freelance-hunt/references/templates/Contrato.md +60 -0
- package/skills/freelance-hunt/references/templates/Propuesta.md +66 -0
- package/skills/freelance-kickoff/SKILL.md +94 -0
- package/skills/freelance-pipeline/SKILL.md +109 -0
- package/skills/freelance-pipeline/scripts/import_history.py +425 -0
- package/skills/freelance-profile/SKILL.md +93 -0
- package/skills/freelance-proposal/SKILL.md +112 -0
- package/skills/freelance-scan/SKILL.md +196 -0
- package/skills/freelance-scan/references/dedup.md +35 -0
- package/skills/freelance-scan/references/platforms.md +167 -0
- package/skills/freelance-scan/scripts/freelance_search.py +1077 -0
- package/skills/install-mcp/SKILL.md +135 -46
- package/skills/install-mcp/references/unreal-operations.md +55 -0
- package/skills/interview-prep/SKILL.md +11 -3
- package/skills/job-aplicar/SKILL.md +5 -1
- package/skills/job-hunt/SKILL.md +17 -0
- package/skills/job-outcome/SKILL.md +15 -1
- package/skills/job-upskill/SKILL.md +10 -2
- package/skills/ue-actor-component-architecture/SKILL.md +509 -0
- package/skills/ue-actor-component-architecture/references/actor-lifecycle.md +301 -0
- package/skills/ue-actor-component-architecture/references/component-types.md +592 -0
- package/skills/ue-ai-navigation/SKILL.md +526 -0
- package/skills/ue-ai-navigation/references/behavior-tree-patterns.md +392 -0
- package/skills/ue-ai-navigation/references/behavior-tree-workflow.md +107 -0
- package/skills/ue-ai-navigation/references/custom-bttask.md +104 -0
- package/skills/ue-ai-navigation/references/eqs-reference.md +423 -0
- package/skills/ue-animation-system/SKILL.md +521 -0
- package/skills/ue-animation-system/references/anim-notify-reference.md +486 -0
- package/skills/ue-animation-system/references/locomotion-setup.md +550 -0
- package/skills/ue-async-threading/SKILL.md +433 -0
- package/skills/ue-async-threading/references/thread-safety-guide.md +213 -0
- package/skills/ue-async-threading/references/threading-patterns.md +345 -0
- package/skills/ue-audio-system/SKILL.md +527 -0
- package/skills/ue-audio-system/references/audio-setup-patterns.md +700 -0
- package/skills/ue-blueprints/SKILL.md +134 -0
- package/skills/ue-blueprints/references/communication.md +82 -0
- package/skills/ue-character-movement/SKILL.md +475 -0
- package/skills/ue-character-movement/references/cmc-extension-patterns.md +335 -0
- package/skills/ue-character-movement/references/movement-pipeline.md +189 -0
- package/skills/ue-cpp-foundations/SKILL.md +533 -0
- package/skills/ue-cpp-foundations/references/components-and-gc.md +107 -0
- package/skills/ue-cpp-foundations/references/container-patterns.md +544 -0
- package/skills/ue-cpp-foundations/references/delegate-patterns.md +497 -0
- package/skills/ue-cpp-foundations/references/gameplay-classes-cpp.md +136 -0
- package/skills/ue-cpp-foundations/references/property-specifiers.md +306 -0
- package/skills/ue-data-assets-tables/SKILL.md +527 -0
- package/skills/ue-data-assets-tables/references/asset-loading-patterns.md +306 -0
- package/skills/ue-data-assets-tables/references/data-driven-design.md +378 -0
- package/skills/ue-editor-tools/SKILL.md +523 -0
- package/skills/ue-editor-tools/references/detail-customization-patterns.md +395 -0
- package/skills/ue-editor-tools/references/editor-module-setup.md +480 -0
- package/skills/ue-game-features/SKILL.md +477 -0
- package/skills/ue-game-features/references/experience-system.md +222 -0
- package/skills/ue-game-features/references/game-feature-patterns.md +308 -0
- package/skills/ue-gameplay-abilities/SKILL.md +518 -0
- package/skills/ue-gameplay-abilities/references/ability-task-reference.md +391 -0
- package/skills/ue-gameplay-abilities/references/gameplay-effect-reference.md +397 -0
- package/skills/ue-gameplay-abilities/references/gas-setup-patterns.md +369 -0
- package/skills/ue-gameplay-framework/SKILL.md +466 -0
- package/skills/ue-gameplay-framework/references/framework-class-map.md +243 -0
- package/skills/ue-input-system/SKILL.md +394 -0
- package/skills/ue-input-system/references/cpp-setup.md +131 -0
- package/skills/ue-input-system/references/enhanced-input-workflow.md +117 -0
- package/skills/ue-input-system/references/input-action-reference.md +731 -0
- package/skills/ue-mass-entity/SKILL.md +476 -0
- package/skills/ue-mass-entity/references/mass-entity-patterns.md +319 -0
- package/skills/ue-mass-entity/references/mass-fragment-reference.md +119 -0
- package/skills/ue-materials-rendering/SKILL.md +526 -0
- package/skills/ue-materials-rendering/references/material-parameter-reference.md +216 -0
- package/skills/ue-materials-rendering/references/post-process-settings.md +383 -0
- package/skills/ue-module-build-system/SKILL.md +487 -0
- package/skills/ue-module-build-system/references/build-cs-reference.md +418 -0
- package/skills/ue-module-build-system/references/common-build-errors.md +381 -0
- package/skills/ue-naming-conventions/SKILL.md +142 -0
- package/skills/ue-naming-conventions/references/asset-name-modifiers.md +233 -0
- package/skills/ue-naming-conventions/references/content-structure.md +83 -0
- package/skills/ue-networking-replication/SKILL.md +452 -0
- package/skills/ue-networking-replication/references/replication-patterns.md +526 -0
- package/skills/ue-networking-replication/references/rpc-decision-guide.md +393 -0
- package/skills/ue-niagara-effects/SKILL.md +531 -0
- package/skills/ue-niagara-effects/references/niagara-data-interfaces.md +491 -0
- package/skills/ue-niagara-effects/references/niagara-parameter-types.md +153 -0
- package/skills/ue-niagara-effects/references/niagara-workflow.md +115 -0
- package/skills/ue-packaging/SKILL.md +116 -0
- package/skills/ue-physics-collision/SKILL.md +423 -0
- package/skills/ue-physics-collision/references/collision-channel-setup.md +218 -0
- package/skills/ue-physics-collision/references/trace-patterns.md +499 -0
- package/skills/ue-procedural-generation/SKILL.md +505 -0
- package/skills/ue-procedural-generation/references/pcg-node-reference.md +381 -0
- package/skills/ue-procedural-generation/references/procedural-mesh-patterns.md +940 -0
- package/skills/ue-project-context/SKILL.md +305 -0
- package/skills/ue-sequencer-cinematics/SKILL.md +506 -0
- package/skills/ue-sequencer-cinematics/references/sequencer-patterns.md +629 -0
- package/skills/ue-serialization-savegames/SKILL.md +524 -0
- package/skills/ue-serialization-savegames/references/save-system-architecture.md +705 -0
- package/skills/ue-state-trees/SKILL.md +489 -0
- package/skills/ue-state-trees/references/state-tree-mass-integration.md +184 -0
- package/skills/ue-state-trees/references/state-tree-patterns.md +321 -0
- package/skills/ue-testing-debugging/SKILL.md +520 -0
- package/skills/ue-testing-debugging/references/automation-test-patterns.md +387 -0
- package/skills/ue-testing-debugging/references/profiling-commands.md +357 -0
- package/skills/ue-ui-umg-slate/SKILL.md +431 -0
- package/skills/ue-ui-umg-slate/references/common-ui-setup.md +484 -0
- package/skills/ue-ui-umg-slate/references/widget-types.md +487 -0
- package/skills/ue-world-level-streaming/SKILL.md +518 -0
- package/skills/ue-world-level-streaming/references/streaming-patterns.md +414 -0
- package/templates/gamedev/unreal-project-context.md +107 -0
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
# Sequencer Patterns Reference
|
|
2
|
+
|
|
3
|
+
Common runtime patterns for Unreal Engine Sequencer / LevelSequence. All patterns use real
|
|
4
|
+
API from LevelSequenceActor.h, LevelSequencePlayer.h, MovieSceneSequencePlayer.h,
|
|
5
|
+
CineCameraActor.h, CineCameraComponent.h, and CineCameraSettings.h.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Pattern 1: Full-Screen Dialogue Cutscene
|
|
10
|
+
|
|
11
|
+
A cutscene triggered by gameplay that disables player input, plays a pre-authored sequence,
|
|
12
|
+
then restores control.
|
|
13
|
+
|
|
14
|
+
### Header
|
|
15
|
+
|
|
16
|
+
```cpp
|
|
17
|
+
// MyCutsceneManager.h
|
|
18
|
+
#pragma once
|
|
19
|
+
#include "GameFramework/Actor.h"
|
|
20
|
+
#include "LevelSequencePlayer.h"
|
|
21
|
+
#include "LevelSequenceActor.h"
|
|
22
|
+
#include "MovieSceneSequencePlaybackSettings.h"
|
|
23
|
+
#include "MyCutsceneManager.generated.h"
|
|
24
|
+
|
|
25
|
+
UCLASS()
|
|
26
|
+
class AMyCutsceneManager : public AActor
|
|
27
|
+
{
|
|
28
|
+
GENERATED_BODY()
|
|
29
|
+
public:
|
|
30
|
+
/** LevelSequence asset to play — assign in editor or set via SetSequenceAsset() */
|
|
31
|
+
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Cinematics")
|
|
32
|
+
ULevelSequence* CutsceneAsset;
|
|
33
|
+
|
|
34
|
+
/** Optional: named binding tag for the hero actor (tag set in Sequencer UI) */
|
|
35
|
+
UPROPERTY(EditAnywhere, Category = "Cinematics")
|
|
36
|
+
FName HeroBindingTag = FName("Hero");
|
|
37
|
+
|
|
38
|
+
UFUNCTION(BlueprintCallable, Category = "Cinematics")
|
|
39
|
+
void PlayCutscene(AActor* HeroActor);
|
|
40
|
+
|
|
41
|
+
UFUNCTION(BlueprintCallable, Category = "Cinematics")
|
|
42
|
+
void SkipCutscene();
|
|
43
|
+
|
|
44
|
+
private:
|
|
45
|
+
UPROPERTY()
|
|
46
|
+
ALevelSequenceActor* ActiveSequenceActor;
|
|
47
|
+
|
|
48
|
+
UPROPERTY()
|
|
49
|
+
ULevelSequencePlayer* ActivePlayer;
|
|
50
|
+
|
|
51
|
+
UFUNCTION()
|
|
52
|
+
void OnCutsceneFinished();
|
|
53
|
+
|
|
54
|
+
void RestorePlayerControl();
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Implementation
|
|
59
|
+
|
|
60
|
+
```cpp
|
|
61
|
+
// MyCutsceneManager.cpp
|
|
62
|
+
#include "MyCutsceneManager.h"
|
|
63
|
+
#include "LevelSequencePlayer.h"
|
|
64
|
+
#include "LevelSequenceActor.h"
|
|
65
|
+
#include "Kismet/GameplayStatics.h"
|
|
66
|
+
|
|
67
|
+
void AMyCutsceneManager::PlayCutscene(AActor* HeroActor)
|
|
68
|
+
{
|
|
69
|
+
if (!CutsceneAsset)
|
|
70
|
+
{
|
|
71
|
+
UE_LOG(LogTemp, Warning, TEXT("AMyCutsceneManager: No CutsceneAsset assigned."));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Build playback settings
|
|
76
|
+
FMovieSceneSequencePlaybackSettings Settings;
|
|
77
|
+
Settings.bAutoPlay = false;
|
|
78
|
+
Settings.PlayRate = 1.0f;
|
|
79
|
+
Settings.LoopCount.Value = 0; // play once
|
|
80
|
+
Settings.bDisableMovementInput = true;
|
|
81
|
+
Settings.bDisableLookAtInput = true;
|
|
82
|
+
Settings.bHidePlayer = false;
|
|
83
|
+
Settings.bHideHud = false;
|
|
84
|
+
Settings.bPauseAtEnd = false;
|
|
85
|
+
// ForceRestoreState: if skipped mid-sequence, actors return to pre-sequence state
|
|
86
|
+
Settings.FinishCompletionStateOverride =
|
|
87
|
+
EMovieSceneCompletionModeOverride::ForceRestoreState;
|
|
88
|
+
|
|
89
|
+
// Spawn sequence actor and player
|
|
90
|
+
ALevelSequenceActor* OutActor = nullptr;
|
|
91
|
+
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(
|
|
92
|
+
this, CutsceneAsset, Settings, OutActor);
|
|
93
|
+
|
|
94
|
+
if (!Player || !OutActor)
|
|
95
|
+
{
|
|
96
|
+
UE_LOG(LogTemp, Error, TEXT("AMyCutsceneManager: Failed to create sequence player."));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Store references to prevent GC
|
|
101
|
+
ActiveSequenceActor = OutActor;
|
|
102
|
+
ActivePlayer = Player;
|
|
103
|
+
|
|
104
|
+
// Bind actor to the Hero track before play
|
|
105
|
+
if (HeroActor && !HeroBindingTag.IsNone())
|
|
106
|
+
{
|
|
107
|
+
OutActor->SetBindingByTag(HeroBindingTag,
|
|
108
|
+
TArray<AActor*>{ HeroActor },
|
|
109
|
+
/*bAllowBindingsFromAsset=*/ false);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Subscribe to completion
|
|
113
|
+
Player->OnFinished.AddDynamic(this, &AMyCutsceneManager::OnCutsceneFinished);
|
|
114
|
+
|
|
115
|
+
// Play
|
|
116
|
+
Player->Play();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
void AMyCutsceneManager::SkipCutscene()
|
|
120
|
+
{
|
|
121
|
+
if (!ActivePlayer) { return; }
|
|
122
|
+
|
|
123
|
+
// ForceRestoreState was set in settings, so Stop() restores actor transforms
|
|
124
|
+
ActivePlayer->Stop();
|
|
125
|
+
// OnCutsceneFinished will fire after Stop in certain configurations;
|
|
126
|
+
// call RestorePlayerControl directly to be safe
|
|
127
|
+
RestorePlayerControl();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
void AMyCutsceneManager::OnCutsceneFinished()
|
|
131
|
+
{
|
|
132
|
+
RestorePlayerControl();
|
|
133
|
+
ActivePlayer = nullptr;
|
|
134
|
+
ActiveSequenceActor = nullptr;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
void AMyCutsceneManager::RestorePlayerControl()
|
|
138
|
+
{
|
|
139
|
+
APlayerController* PC = GetWorld()->GetFirstPlayerController();
|
|
140
|
+
if (!PC) { return; }
|
|
141
|
+
|
|
142
|
+
// Return camera to the player pawn with a short blend
|
|
143
|
+
APawn* PlayerPawn = PC->GetPawn();
|
|
144
|
+
if (PlayerPawn)
|
|
145
|
+
{
|
|
146
|
+
PC->SetViewTargetWithBlend(PlayerPawn, 0.5f, VTBlend_Cubic);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
PC->SetIgnoreMoveInput(false);
|
|
150
|
+
PC->SetIgnoreLookInput(false);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Pattern 2: In-Game Triggered Camera (No Input Lockout)
|
|
157
|
+
|
|
158
|
+
A background camera sequence that plays without hiding the HUD or disabling input — for
|
|
159
|
+
scripted gameplay moments (e.g. a crane shot during a boss encounter).
|
|
160
|
+
|
|
161
|
+
```cpp
|
|
162
|
+
// In a GameMode or GameplayComponent
|
|
163
|
+
void AMyGameMode::TriggerBossArrivalCamera()
|
|
164
|
+
{
|
|
165
|
+
if (!BossArrivalSequence) { return; }
|
|
166
|
+
|
|
167
|
+
FMovieSceneSequencePlaybackSettings Settings;
|
|
168
|
+
Settings.bAutoPlay = false;
|
|
169
|
+
Settings.PlayRate = 1.0f;
|
|
170
|
+
Settings.LoopCount.Value = 0;
|
|
171
|
+
Settings.bDisableMovementInput = false; // player keeps control
|
|
172
|
+
Settings.bDisableLookAtInput = false;
|
|
173
|
+
Settings.bHidePlayer = false;
|
|
174
|
+
Settings.bHideHud = false;
|
|
175
|
+
Settings.bDisableCameraCuts = false; // allow camera cuts in sequence
|
|
176
|
+
Settings.bPauseAtEnd = false;
|
|
177
|
+
|
|
178
|
+
ALevelSequenceActor* OutActor = nullptr;
|
|
179
|
+
BossArrivalPlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(
|
|
180
|
+
this, BossArrivalSequence, Settings, OutActor);
|
|
181
|
+
BossArrivalSequenceActor = OutActor;
|
|
182
|
+
|
|
183
|
+
if (BossArrivalPlayer)
|
|
184
|
+
{
|
|
185
|
+
// React to camera cut events (e.g. to trigger audio stingers)
|
|
186
|
+
BossArrivalPlayer->OnCameraCut.AddDynamic(
|
|
187
|
+
this, &AMyGameMode::OnBossArrivalCameraCut);
|
|
188
|
+
|
|
189
|
+
BossArrivalPlayer->OnFinished.AddDynamic(
|
|
190
|
+
this, &AMyGameMode::OnBossArrivalCameraFinished);
|
|
191
|
+
|
|
192
|
+
BossArrivalPlayer->Play();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
UFUNCTION()
|
|
197
|
+
void AMyGameMode::OnBossArrivalCameraCut(UCameraComponent* NewCamera)
|
|
198
|
+
{
|
|
199
|
+
// e.g. play a stinger sound effect when cut happens
|
|
200
|
+
UGameplayStatics::PlaySound2D(this, CameraCutStinger);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
UFUNCTION()
|
|
204
|
+
void AMyGameMode::OnBossArrivalCameraFinished()
|
|
205
|
+
{
|
|
206
|
+
// Return to gameplay camera
|
|
207
|
+
APlayerController* PC = GetWorld()->GetFirstPlayerController();
|
|
208
|
+
if (PC && PC->GetPawn())
|
|
209
|
+
{
|
|
210
|
+
PC->SetViewTargetWithBlend(PC->GetPawn(), 1.0f, VTBlend_EaseInOut, 2.0f);
|
|
211
|
+
}
|
|
212
|
+
BossArrivalPlayer = nullptr;
|
|
213
|
+
BossArrivalSequenceActor = nullptr;
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Pattern 3: Scripted Event Sequence with Runtime Actor Binding
|
|
220
|
+
|
|
221
|
+
A scripted event that binds multiple actors at runtime (e.g. two NPCs performing an
|
|
222
|
+
interaction authored in Sequencer with tag-based bindings).
|
|
223
|
+
|
|
224
|
+
### Sequence Setup (in Editor)
|
|
225
|
+
|
|
226
|
+
1. Create a LevelSequence asset called `LS_NPCHandshake`.
|
|
227
|
+
2. Add two possessable bindings: tag them `NPC_A` and `NPC_B` via right-click -> Tags.
|
|
228
|
+
3. Add transform, skeletal animation, and event tracks to each binding.
|
|
229
|
+
4. Add an Event Track at frame 60 bound to `TriggerHandshakeReaction()`.
|
|
230
|
+
|
|
231
|
+
### C++ Runtime Binding
|
|
232
|
+
|
|
233
|
+
```cpp
|
|
234
|
+
// ScriptedEventTrigger.cpp
|
|
235
|
+
|
|
236
|
+
void AScriptedEventTrigger::TriggerHandshakeSequence(
|
|
237
|
+
AActor* NpcA, AActor* NpcB)
|
|
238
|
+
{
|
|
239
|
+
if (!HandshakeSequence) { return; }
|
|
240
|
+
|
|
241
|
+
FMovieSceneSequencePlaybackSettings Settings;
|
|
242
|
+
Settings.bAutoPlay = false;
|
|
243
|
+
Settings.LoopCount.Value = 0;
|
|
244
|
+
Settings.bDisableMovementInput = false;
|
|
245
|
+
Settings.bHideHud = false;
|
|
246
|
+
Settings.FinishCompletionStateOverride =
|
|
247
|
+
EMovieSceneCompletionModeOverride::ForceRestoreState;
|
|
248
|
+
|
|
249
|
+
ALevelSequenceActor* OutActor = nullptr;
|
|
250
|
+
HandshakePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(
|
|
251
|
+
this, HandshakeSequence, Settings, OutActor);
|
|
252
|
+
HandshakeSequenceActor = OutActor;
|
|
253
|
+
|
|
254
|
+
if (!HandshakePlayer) { return; }
|
|
255
|
+
|
|
256
|
+
// Bind both NPCs before playing
|
|
257
|
+
HandshakeSequenceActor->SetBindingByTag(
|
|
258
|
+
FName("NPC_A"), TArray<AActor*>{ NpcA }, false);
|
|
259
|
+
HandshakeSequenceActor->SetBindingByTag(
|
|
260
|
+
FName("NPC_B"), TArray<AActor*>{ NpcB }, false);
|
|
261
|
+
|
|
262
|
+
HandshakePlayer->OnFinished.AddDynamic(
|
|
263
|
+
this, &AScriptedEventTrigger::OnHandshakeFinished);
|
|
264
|
+
HandshakePlayer->Play();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Called by the Event Track at frame 60 (must be on an object in event context)
|
|
268
|
+
UFUNCTION(BlueprintCallable, Category = "Cinematics")
|
|
269
|
+
void AScriptedEventTrigger::TriggerHandshakeReaction()
|
|
270
|
+
{
|
|
271
|
+
// Gameplay response to the mid-sequence event
|
|
272
|
+
UE_LOG(LogTemp, Log, TEXT("Handshake event fired from Sequencer!"));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
UFUNCTION()
|
|
276
|
+
void AScriptedEventTrigger::OnHandshakeFinished()
|
|
277
|
+
{
|
|
278
|
+
HandshakePlayer = nullptr;
|
|
279
|
+
HandshakeSequenceActor = nullptr;
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Pattern 4: Looping Ambient Sequence (Background Atmosphere)
|
|
286
|
+
|
|
287
|
+
A sequence that loops indefinitely to drive ambient elements (foliage sway, light flicker,
|
|
288
|
+
water ripple) without affecting player state.
|
|
289
|
+
|
|
290
|
+
```cpp
|
|
291
|
+
void AAtmosphereManager::BeginPlay()
|
|
292
|
+
{
|
|
293
|
+
Super::BeginPlay();
|
|
294
|
+
|
|
295
|
+
if (!AmbientSequence) { return; }
|
|
296
|
+
|
|
297
|
+
FMovieSceneSequencePlaybackSettings Settings;
|
|
298
|
+
Settings.bAutoPlay = false;
|
|
299
|
+
Settings.LoopCount.Value = -1; // -1 = infinite
|
|
300
|
+
Settings.bDisableMovementInput = false;
|
|
301
|
+
Settings.bDisableLookAtInput = false;
|
|
302
|
+
Settings.bHidePlayer = false;
|
|
303
|
+
Settings.bHideHud = false;
|
|
304
|
+
Settings.bDisableCameraCuts = true; // do not take over camera
|
|
305
|
+
|
|
306
|
+
ALevelSequenceActor* OutActor = nullptr;
|
|
307
|
+
AmbientPlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(
|
|
308
|
+
this, AmbientSequence, Settings, OutActor);
|
|
309
|
+
AmbientSequenceActor = OutActor;
|
|
310
|
+
|
|
311
|
+
if (AmbientPlayer)
|
|
312
|
+
{
|
|
313
|
+
AmbientPlayer->Play();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
void AAtmosphereManager::EndPlay(const EEndPlayReason::Type Reason)
|
|
318
|
+
{
|
|
319
|
+
if (AmbientPlayer && AmbientPlayer->IsPlaying())
|
|
320
|
+
{
|
|
321
|
+
AmbientPlayer->Stop();
|
|
322
|
+
}
|
|
323
|
+
Super::EndPlay(Reason);
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Pattern 5: CineCameraActor — Runtime Camera Setup in Sequence
|
|
330
|
+
|
|
331
|
+
Spawning and configuring a `ACineCameraActor` then handing it to a sequence.
|
|
332
|
+
|
|
333
|
+
```cpp
|
|
334
|
+
#include "CineCameraActor.h"
|
|
335
|
+
#include "CineCameraComponent.h"
|
|
336
|
+
#include "CineCameraSettings.h" // FCameraFilmbackSettings, FCameraLensSettings, FCameraFocusSettings
|
|
337
|
+
|
|
338
|
+
ACineCameraActor* AMyDirector::SpawnCineCamera(
|
|
339
|
+
FVector Location, FRotator Rotation)
|
|
340
|
+
{
|
|
341
|
+
FActorSpawnParameters Params;
|
|
342
|
+
Params.Owner = this;
|
|
343
|
+
|
|
344
|
+
ACineCameraActor* Camera = GetWorld()->SpawnActor<ACineCameraActor>(
|
|
345
|
+
ACineCameraActor::StaticClass(),
|
|
346
|
+
Location, Rotation, Params);
|
|
347
|
+
|
|
348
|
+
if (!Camera) { return nullptr; }
|
|
349
|
+
|
|
350
|
+
UCineCameraComponent* CineComp = Camera->GetCineCameraComponent();
|
|
351
|
+
|
|
352
|
+
// 35mm full-frame sensor
|
|
353
|
+
FCameraFilmbackSettings Filmback;
|
|
354
|
+
Filmback.SensorWidth = 36.0f; // mm
|
|
355
|
+
Filmback.SensorHeight = 24.0f;
|
|
356
|
+
CineComp->SetFilmback(Filmback);
|
|
357
|
+
|
|
358
|
+
// 35mm prime lens
|
|
359
|
+
FCameraLensSettings Lens;
|
|
360
|
+
Lens.MinFocalLength = 35.0f;
|
|
361
|
+
Lens.MaxFocalLength = 35.0f;
|
|
362
|
+
Lens.MinFStop = 1.4f;
|
|
363
|
+
Lens.MaxFStop = 16.0f;
|
|
364
|
+
Lens.MinimumFocusDistance = 30.0f;
|
|
365
|
+
CineComp->SetLensSettings(Lens);
|
|
366
|
+
|
|
367
|
+
CineComp->SetCurrentFocalLength(35.0f);
|
|
368
|
+
CineComp->SetCurrentAperture(2.0f);
|
|
369
|
+
|
|
370
|
+
// Manual focus at 5 meters (500 cm)
|
|
371
|
+
FCameraFocusSettings FocusSettings;
|
|
372
|
+
FocusSettings.FocusMethod = ECameraFocusMethod::Manual;
|
|
373
|
+
FocusSettings.ManualFocusDistance = 500.0f;
|
|
374
|
+
FocusSettings.bSmoothFocusChanges = true;
|
|
375
|
+
FocusSettings.FocusSmoothingInterpSpeed = 8.0f;
|
|
376
|
+
CineComp->SetFocusSettings(FocusSettings);
|
|
377
|
+
|
|
378
|
+
// Lookat tracking toward hero
|
|
379
|
+
Camera->LookatTrackingSettings.bEnableLookAtTracking = true;
|
|
380
|
+
Camera->LookatTrackingSettings.ActorToTrack = HeroActor;
|
|
381
|
+
Camera->LookatTrackingSettings.RelativeOffset = FVector(0, 0, 80.f);
|
|
382
|
+
Camera->LookatTrackingSettings.LookAtTrackingInterpSpeed = 4.0f;
|
|
383
|
+
Camera->LookatTrackingSettings.bAllowRoll = false;
|
|
384
|
+
|
|
385
|
+
return Camera;
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Pattern 6: Partial Playback — Play a Specific Frame Range
|
|
392
|
+
|
|
393
|
+
Play only a portion of a sequence (e.g. frames 0-60 for an intro, then frames 61-120 for the
|
|
394
|
+
main loop).
|
|
395
|
+
|
|
396
|
+
```cpp
|
|
397
|
+
void AMySequenceController::PlayIntroSegment()
|
|
398
|
+
{
|
|
399
|
+
if (!FullSequence) { return; }
|
|
400
|
+
|
|
401
|
+
FMovieSceneSequencePlaybackSettings Settings;
|
|
402
|
+
Settings.bAutoPlay = false;
|
|
403
|
+
Settings.LoopCount.Value = 0;
|
|
404
|
+
|
|
405
|
+
ALevelSequenceActor* OutActor = nullptr;
|
|
406
|
+
ActivePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(
|
|
407
|
+
this, FullSequence, Settings, OutActor);
|
|
408
|
+
ActiveSequenceActor = OutActor;
|
|
409
|
+
|
|
410
|
+
if (!ActivePlayer) { return; }
|
|
411
|
+
|
|
412
|
+
// Restrict playback to frames 0–60 (at the sequence's display rate)
|
|
413
|
+
ActivePlayer->SetFrameRange(0, 60);
|
|
414
|
+
|
|
415
|
+
ActivePlayer->OnFinished.AddDynamic(this, &AMySequenceController::OnIntroFinished);
|
|
416
|
+
ActivePlayer->Play();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
UFUNCTION()
|
|
420
|
+
void AMySequenceController::OnIntroFinished()
|
|
421
|
+
{
|
|
422
|
+
if (!ActivePlayer) { return; }
|
|
423
|
+
|
|
424
|
+
// Switch to main loop segment: frames 61-120, loop indefinitely
|
|
425
|
+
ActivePlayer->OnFinished.RemoveDynamic(
|
|
426
|
+
this, &AMySequenceController::OnIntroFinished);
|
|
427
|
+
|
|
428
|
+
ActivePlayer->SetFrameRange(61, 59); // start=61, duration=59 frames
|
|
429
|
+
ActivePlayer->PlayLooping(-1); // -1 = infinite
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Pattern 7: Sub-Sequence Snapshot Inspection
|
|
436
|
+
|
|
437
|
+
Read the current shot name from a master sequence containing multiple sub-sequences (shots).
|
|
438
|
+
|
|
439
|
+
```cpp
|
|
440
|
+
void AMyHUD::Tick(float DeltaTime)
|
|
441
|
+
{
|
|
442
|
+
Super::Tick(DeltaTime);
|
|
443
|
+
|
|
444
|
+
ULevelSequencePlayer* Player = ActiveSequenceActor
|
|
445
|
+
? ActiveSequenceActor->GetSequencePlayer()
|
|
446
|
+
: nullptr;
|
|
447
|
+
|
|
448
|
+
if (!Player || !Player->IsPlaying()) { return; }
|
|
449
|
+
|
|
450
|
+
FLevelSequencePlayerSnapshot Snapshot;
|
|
451
|
+
Player->TakeFrameSnapshot(Snapshot);
|
|
452
|
+
|
|
453
|
+
// Snapshot fields:
|
|
454
|
+
// RootName -- name of the root sequence
|
|
455
|
+
// RootTime -- current time in root sequence (FQualifiedFrameTime)
|
|
456
|
+
// CurrentShotName -- name of the active sub-sequence/shot
|
|
457
|
+
// CurrentShotLocalTime -- time within the current shot
|
|
458
|
+
// SourceTimecode -- timecode string
|
|
459
|
+
// CameraComponent -- currently active camera component (TSoftObjectPtr)
|
|
460
|
+
// ActiveShot -- ULevelSequence* of the current shot
|
|
461
|
+
|
|
462
|
+
FString ShotInfo = FString::Printf(
|
|
463
|
+
TEXT("Shot: %s | Root Frame: %d"),
|
|
464
|
+
*Snapshot.CurrentShotName,
|
|
465
|
+
Snapshot.RootTime.Time.FrameNumber.Value);
|
|
466
|
+
|
|
467
|
+
DrawDebugString(GetWorld(), FVector::ZeroVector, ShotInfo, nullptr,
|
|
468
|
+
FColor::White, 0.0f, true);
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
---
|
|
473
|
+
|
|
474
|
+
## Pattern 8: Replicated Cutscene (Multiplayer)
|
|
475
|
+
|
|
476
|
+
Play a cutscene on all clients synchronized via server authority.
|
|
477
|
+
|
|
478
|
+
```cpp
|
|
479
|
+
// Server-side: spawn and configure the sequence actor with replication enabled
|
|
480
|
+
void AMyNetworkGameMode::Server_PlayCutscene_Implementation(
|
|
481
|
+
ULevelSequence* Sequence)
|
|
482
|
+
{
|
|
483
|
+
FActorSpawnParameters SpawnParams;
|
|
484
|
+
SpawnParams.Owner = this;
|
|
485
|
+
|
|
486
|
+
// Spawn the actor on the server — it will replicate to clients
|
|
487
|
+
ALevelSequenceActor* SeqActor = GetWorld()->SpawnActor<ALevelSequenceActor>(
|
|
488
|
+
ALevelSequenceActor::StaticClass(), FTransform::Identity, SpawnParams);
|
|
489
|
+
|
|
490
|
+
if (!SeqActor) { return; }
|
|
491
|
+
|
|
492
|
+
// Enable replication before setting any state
|
|
493
|
+
SeqActor->SetReplicatePlayback(true); // bReplicatePlayback
|
|
494
|
+
SeqActor->SetSequence(Sequence);
|
|
495
|
+
|
|
496
|
+
// PlaybackSettings replicated to clients
|
|
497
|
+
SeqActor->PlaybackSettings.bAutoPlay = false;
|
|
498
|
+
SeqActor->PlaybackSettings.LoopCount.Value = 0;
|
|
499
|
+
SeqActor->PlaybackSettings.bDisableMovementInput = true;
|
|
500
|
+
SeqActor->PlaybackSettings.bHidePlayer = false;
|
|
501
|
+
|
|
502
|
+
ULevelSequencePlayer* Player = SeqActor->GetSequencePlayer();
|
|
503
|
+
if (Player)
|
|
504
|
+
{
|
|
505
|
+
Player->OnFinished.AddDynamic(this, &AMyNetworkGameMode::OnReplicatedCutsceneFinished);
|
|
506
|
+
Player->Play(); // server starts playback; clients follow via NetSyncProps
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
UFUNCTION()
|
|
511
|
+
void AMyNetworkGameMode::OnReplicatedCutsceneFinished()
|
|
512
|
+
{
|
|
513
|
+
// Notify all clients to restore input
|
|
514
|
+
Multicast_RestorePlayerInput();
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
UFUNCTION(NetMulticast, Reliable)
|
|
518
|
+
void AMyNetworkGameMode::Multicast_RestorePlayerInput()
|
|
519
|
+
{
|
|
520
|
+
APlayerController* PC = GetWorld()->GetFirstPlayerController();
|
|
521
|
+
if (PC)
|
|
522
|
+
{
|
|
523
|
+
PC->SetIgnoreMoveInput(false);
|
|
524
|
+
PC->SetIgnoreLookInput(false);
|
|
525
|
+
APawn* Pawn = PC->GetPawn();
|
|
526
|
+
if (Pawn)
|
|
527
|
+
{
|
|
528
|
+
PC->SetViewTargetWithBlend(Pawn, 0.5f);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## API Quick Reference
|
|
537
|
+
|
|
538
|
+
### ULevelSequencePlayer::CreateLevelSequencePlayer
|
|
539
|
+
```
|
|
540
|
+
static ULevelSequencePlayer* CreateLevelSequencePlayer(
|
|
541
|
+
UObject* WorldContextObject,
|
|
542
|
+
ULevelSequence* LevelSequence,
|
|
543
|
+
FMovieSceneSequencePlaybackSettings Settings,
|
|
544
|
+
ALevelSequenceActor*& OutActor)
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### FMovieSceneSequencePlaybackSettings fields
|
|
548
|
+
```
|
|
549
|
+
bool bAutoPlay -- auto-play on BeginPlay
|
|
550
|
+
float PlayRate -- 1.0 = normal, 2.0 = 2x, -1.0 = reverse
|
|
551
|
+
float StartTime -- offset in seconds from sequence start
|
|
552
|
+
int32 LoopCount.Value -- 0 = no loop, -1 = infinite, N = N loops
|
|
553
|
+
bool bDisableMovementInput -- locks player movement during play
|
|
554
|
+
bool bDisableLookAtInput -- locks player look during play
|
|
555
|
+
bool bHidePlayer -- hides player pawn mesh
|
|
556
|
+
bool bHideHud -- hides HUD widgets
|
|
557
|
+
bool bDisableCameraCuts -- prevents sequence from overriding camera
|
|
558
|
+
bool bPauseAtEnd -- pauses (not stops) at last frame
|
|
559
|
+
EMovieSceneCompletionModeOverride FinishCompletionStateOverride
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### ALevelSequenceActor binding methods
|
|
563
|
+
```
|
|
564
|
+
void SetBinding(FMovieSceneObjectBindingID, TArray<AActor*>, bAllowFromAsset)
|
|
565
|
+
void SetBindingByTag(FName Tag, TArray<AActor*>, bAllowFromAsset)
|
|
566
|
+
void AddBinding(FMovieSceneObjectBindingID, AActor*, bAllowFromAsset)
|
|
567
|
+
void AddBindingByTag(FName Tag, AActor*, bAllowFromAsset)
|
|
568
|
+
void RemoveBinding(FMovieSceneObjectBindingID, AActor*)
|
|
569
|
+
void RemoveBindingByTag(FName Tag, AActor*)
|
|
570
|
+
void ResetBinding(FMovieSceneObjectBindingID)
|
|
571
|
+
void ResetBindings()
|
|
572
|
+
FMovieSceneObjectBindingID FindNamedBinding(FName Tag) const
|
|
573
|
+
const TArray<FMovieSceneObjectBindingID>& FindNamedBindings(FName Tag) const
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### UMovieSceneSequencePlayer playback control
|
|
577
|
+
```
|
|
578
|
+
void Play()
|
|
579
|
+
void PlayReverse()
|
|
580
|
+
void PlayLooping(int32 NumLoops = -1)
|
|
581
|
+
void Pause()
|
|
582
|
+
void Stop()
|
|
583
|
+
void StopAtCurrentTime()
|
|
584
|
+
void GoToEndAndStop()
|
|
585
|
+
void SetPlayRate(float)
|
|
586
|
+
void SetFrameRange(int32 StartFrame, int32 Duration, float SubFrames = 0.f)
|
|
587
|
+
void SetTimeRange(float StartTime, float Duration)
|
|
588
|
+
void SetPlaybackPosition(FMovieSceneSequencePlaybackParams)
|
|
589
|
+
void PlayTo(FMovieSceneSequencePlaybackParams, FMovieSceneSequencePlayToParams)
|
|
590
|
+
void RestoreState()
|
|
591
|
+
void SetCompletionModeOverride(EMovieSceneCompletionModeOverride)
|
|
592
|
+
bool IsPlaying() const
|
|
593
|
+
bool IsPaused() const
|
|
594
|
+
bool IsReversed() const
|
|
595
|
+
float GetPlayRate() const
|
|
596
|
+
FQualifiedFrameTime GetCurrentTime() const
|
|
597
|
+
FQualifiedFrameTime GetDuration() const
|
|
598
|
+
int32 GetFrameDuration() const
|
|
599
|
+
TArray<UObject*> GetBoundObjects(FMovieSceneObjectBindingID)
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
### UCineCameraComponent key properties/methods
|
|
603
|
+
```
|
|
604
|
+
FCameraFilmbackSettings Filmback -- SensorWidth, SensorHeight (mm)
|
|
605
|
+
FCameraLensSettings LensSettings -- MinFocalLength, MaxFocalLength, MinFStop, MaxFStop
|
|
606
|
+
FCameraFocusSettings FocusSettings -- FocusMethod, ManualFocusDistance (cm)
|
|
607
|
+
float CurrentFocalLength -- current zoom (mm), Interp-animatable
|
|
608
|
+
float CurrentAperture -- f-stop, Interp-animatable
|
|
609
|
+
float CurrentFocusDistance -- read-only, derived from FocusSettings
|
|
610
|
+
|
|
611
|
+
void SetFilmback(const FCameraFilmbackSettings&)
|
|
612
|
+
void SetLensSettings(const FCameraLensSettings&)
|
|
613
|
+
void SetFocusSettings(const FCameraFocusSettings&)
|
|
614
|
+
void SetCurrentFocalLength(float)
|
|
615
|
+
void SetCurrentAperture(float)
|
|
616
|
+
float GetHorizontalFieldOfView() const
|
|
617
|
+
float GetVerticalFieldOfView() const
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### ULevelSequencePlayer additional delegates/events
|
|
621
|
+
```
|
|
622
|
+
FOnLevelSequencePlayerCameraCutEvent OnCameraCut -- fires on every camera cut
|
|
623
|
+
FOnMovieSceneSequencePlayerEvent OnPlay
|
|
624
|
+
FOnMovieSceneSequencePlayerEvent OnPlayReverse
|
|
625
|
+
FOnMovieSceneSequencePlayerEvent OnStop
|
|
626
|
+
FOnMovieSceneSequencePlayerEvent OnPause
|
|
627
|
+
FOnMovieSceneSequencePlayerEvent OnFinished
|
|
628
|
+
FOnMovieSceneSequencePlayerNativeEvent OnNativeFinished
|
|
629
|
+
```
|