UE5 シーケンサーに関する小ネタメモ

# 概要
UnrealEngine5 のシーケンサー関連の小ネタです。
レベルシーケンス作成方法等は他のページをご覧ください。


## 更新履歴
| 日付 | 内容 |
|:-----|:----|
|2024/08/09| 初版 |
|2024/09/06| fbxでのカメラデータインポートについて追記 |


## 参考
以下の記事を参考にいたしました、ありがとうございます。
[UE公式：シーケンサーの概要](https://dev.epicgames.com/documentation/ja-jp/unreal-engine/unreal-engine-sequencer-movie-tool-overview?application_version=5.0)
[【UE5】シーケンサーの使い方](https://metatimecg.com/ue5-how-to-use-sequencer/)
[【初心者向け】UE5 シーケンサーと Movie Render Queue の使い方【Cinematic Dive 2023】 ](https://www.docswell.com/s/EpicGamesJapan/Z7V32W-cinematicdive-epic#p1)
[[UE4][C++]シーケンサーで非対応のパラメータを制御可能にする方法](https://historia.co.jp/archives/8411/)
[UE4 シーケンサーを一時停止する](https://naoxgames.hatenablog.jp/entry/2022/03/01/014651)


## 環境
Windows10
Visual Studio 2022
UnrealEngine 5.3.2


## 関連ソース
"Engine\Source\Runtime\LevelSequence\Public\LevelSequence.h"
"Engine\Source\Runtime\LevelSequence\Public\LevelSequencePlayer.h"
"Engine\Source\Runtime\MovieScene\Public\MovieSceneSequencePlaybackSettings.h"
"Engine\Source\Runtime\MovieScene\Public\MovieSceneSequencePlayer.h"
"Engine\Source\Runtime\Engine\Classes\GameFramework\PlayerController.h"


# シーケンサー

## BPでの再生
プレイヤーを作成して再生します。
`OutActor`に対して`Self`を入れていますがレベルシーケンス側でActorの位置による処理がなければ不要です。

![playLS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/5d72ae56-a100-8208-2936-326b3449e905.png)



## C++での再生
C++でのシーケンサー再生コード例。
再生終了時のコールバックもやっています。

```c++:.h
UCLASS()
class SAMPLE_API UMyComponent : public UActorComponent
{
	GENERATED_BODY()

..省略..

public:
	// デモを再生する
	UFUNCTION(BlueprintCallable)
	void PlayDemo(ULevelSequence* _LevelSequence);
	// デモを停止する
	UFUNCTION(BlueprintCallable)
	void StopDemo();
	// 再生中か？
	UFUNCTION(BlueprintCallable)
	bool IsDemo() const;

	// レベルシーケンスアセット
	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	TObjectPtr<ULevelSequence>	LevelSequence;
 
	// 再生終了時コールバック
	UFUNCTION()
	void CallBackFinished(){ UE_LOG(LogTemp, Log, TEXT("CallBackFinished.")); }


protected:
	// レベルシーケンスプレイヤー
	TWeakObjectPtr<ULevelSequencePlayer> LevelSequencePlayer = nullptr;
};
```

```c++:.cpp
// 再生
void UMyComponent::PlayDemo(ULevelSequence* _LevelSequence)
{
	FMovieSceneSequencePlaybackSettings _Settings;
	ALevelSequenceActor* _OutActor;
	
	// レベルシーケンスプレイヤーを作成
	LevelSequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(this->GetWorld(), _LevelSequence, _Settings, _OutActor);

	// イベントデリゲート(FOnMovieSceneSequencePlayerEvent)コールバック
	LevelSequencePlayer.Get()->OnFinished.AddDynamic(this, &ThisClass::CallBackFinished);

	if(::IsValid(_OutActor)){
		_OutActor->bOverrideInstanceData = true;

		auto _InstanceData =  Cast<UDefaultLevelSequenceInstanceData>(_OutActor->DefaultInstanceData);
		if (_InstanceData) {
			_InstanceData->TransformOriginActor = GetOwner();
		}
	}
	
	// 再生開始
	if(LevelSequencePlayer.Get()){
		LevelSequencePlayer.Get()->Play();
	}
}

// 停止
void UMyComponent::StopDemo()
{
	// 再生停止
	if(LevelSequencePlayer.Get()){
		LevelSequencePlayer.Get()->Stop();
	}
}

// 再生中か？
bool UMyComponent::IsDemo() const
{
	if(LevelSequencePlayer.Get()){
		return(LevelSequencePlayer.Get()->IsPlaying());
	}
	
	return(false);
}

```

:::note
コールバックイベントは再生終了時`OnFinished` の他に 再生開始時`OnPlay`、逆再生開始時`OnPlayReverse`、停止時`OnStop`、一時停止時`OnPause` があります。
:::



## 再生/終了時の処理
シーケンサー再生時にシネマティックモードの設定として `APlayerController` の`SetCinematicMode(bool, bool, bool)` が呼ばれますがこれは実体のほうのUFUNCTION()がついた`SetCinematicMode(bool, bool, bool, bool, bool)` から呼ばれているようです。

```C++:PlayerController.h
// シネマティックモードに基づいて入力を調整する
ENGINE_API virtual void SetCinematicMode(bool bInCinematicMode, bool bAffectsMovement, bool bAffectsTurning)

// プレイヤーがシネマティック モードかどうかを変更するためのサーバー/SP 専用関数。さまざまな状態変数の値を更新し、クライアントへの呼び出しを複製します
// * 現在のシネマティック モードを同期します。
UFUNCTION(BlueprintCallable, Category="Game|Cinematic", meta=(bHidePlayer="true", bAffectsHUD="true"))
ENGINE_API virtual void SetCinematicMode(bool bInCinematicMode, bool bHidePlayer, bool bAffectsHUD, bool bAffectsMovement, bool bAffectsTurning);

```

## カメラデータ(fbx)のインポート
デザインツールなどからカメラデータを取り込むにはfbx形式で出力し、インポートすることができます。
![ImportFbx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/25e4f15b-87bd-2208-1a5d-82bf1d1108fa.png)

再インポートはカメラアクターを右クリックしてインポートでできます、この時カメラアクター名が違うと警告が出ます。
![reimportFbx.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/82b95d62-61c0-4cb3-cf66-e49a24744239.png)



# CineCamera
レベルシーケンスのCine Camera Actor は `ACineCameraActor` を継承したクラスに差し替えができます。

![CineCamera.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/cd71706e-1ce2-76eb-e6b4-a7d15c0e51b8.png)


以下は `ACineCameraActor`クラスを継承したコード例。
`BecomeViewTarget`は ViewTargetになった時に呼ばれるメソッド、`EndViewTarget` はViewTagetではなくなった時に呼ばれるメソッドです。

```cpp:MyCineCameraActor.h
#pragma once

#include "CoreMinimal.h"
#include "CineCameraActor.h"
#include "GameplayTagContainer.h"
#include "MyCineCameraActor.generated.h"

UCLASS()
class SAMPLE_API AMyCineCameraActor : public ACineCameraActor
{
	GENERATED_BODY()
	
public:
	AMyCineCameraActor(const FObjectInitializer& ObjectInitializer);

//	virtual void BeginPlay() override;
//	virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;

	// このアクタが指定された PlayerController の ViewTarget になった時に呼び出されます。
	virtual void BecomeViewTarget( class APlayerController* _PC );
	// このアクタが指定された PlayerController の ViewTarget でなくなった時に呼び出されます。
	virtual void EndViewTarget( class APlayerController* _PC );
};
```

```cpp:MyCineCameraActor.cpp
#include "./MyCineCameraActor.h"
#include "GameFramework/PlayerController.h"

AMyCineCameraActor::AMyCineCameraActor(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	PrimaryActorTick.bCanEverTick = false;
	SetActorTickEnabled(false);
}

// ViewTargetになった時に呼ばれる処理
void AMyCineCameraActor::BecomeViewTarget(class APlayerController* _PC)
{
	Super::BecomeViewTarget(_PC);
	
	UE_LOG(LogTemp, Log, TEXT("BecomeViewTarget"));
}

// ViewTargetではなくなった時に呼ばれる処理
void AMyCineCameraActor::EndViewTarget(class APlayerController* _PC)
{
	Super::EndViewTarget(_PC);

	UE_LOG(LogTemp, Log, TEXT("EndViewTarget"));
}

```

シーケンサーイベント後にゲームカメラへ繋ぐ処理などを作ることができると思います。



# まとめ
会話イベントなど、ボタン送りをするイベントに使う方法はないものですかね。