エンジニアっぽくなりたい

UnityやUnrealEngine 4などでなにか役に立ちそうなことを発信していく。

UE4 LevelSequenceDirectorを使いまわす

シーケンサーでイベントトラックを使ってBPで処理を作る、とかやりますよね。
プロジェクトによってはそれをデザイナーやプランナーに設定してもらう、という場合もあると思います。
シーケンサー毎に毎回イベントトラックで〇〇ノードを呼び出して、このピンをつなげて・・・・・なんて説明するのも面倒ですよね。
要はシーケンサーが作られた段階でイベントトラックに必要な処理が準備されていて、イベントトラックを作成したらBPいじらずに目的のイベントを仕込めたら、きっと楽になるはずだ!


目標


シーケンサーのイベントトラックでイベントを設定するのを楽にしたい!
汎用的なイベントは共通化して処理は一か所にしたい。

※今回はエンジン改造はしません。


環境

今回からエンジンビルドします。
・UE 4.27.0 (Gitのコミット:99b6e203a15d04fc7bbbf554c421a985c1ccb8f1 をビルド)
・VisualStudio 2019 16.11.2 ※バージョンアップしました。


やってみる

作戦としてはLevelSequenceDirectorを継承したクラス&BPを作ってそれに置き換えます。
LevelSequenceDirectorは、シーケンサーでイベントトラックを使った際に処理を書くBPのことです。

LevelSequenceDirectorを開く

開き方は
シーケンサーでイベントトラックを作成し、キーを打ちます。
f:id:naoxgames:20210913212608p:plain
そのキーをダブルクリックすると以下のようなBPが開きます。
f:id:naoxgames:20210913212728p:plain
これの右上を見るとわかりますが、こいつが噂の「LevelSequenceDirector」です。


LevelSequenceDirector継承したクラス&BPを作成

C++クラスを追加で「LevelSequenceDirector」を選択します。
ここでは「MyLevelSequenceDirector」とします。
f:id:naoxgames:20210913213840p:plain

次にブループリントを作成します。
「MyLevelSequenceDirector」を選択します。
ここでは「BP_MyLevelSequenceDirector」とします。
f:id:naoxgames:20210913220448p:plain

これでクラスとBPを作成できました。

汎用処理を作成

カットシーンでよくありそうな汎用処理を作成します。
ここでは
・一時停止
・再開
Widget生成(クリック待ち)
を作成してみます。


まずは「一時停止」と「再開」を作成します。
これらはC++クラスに記述しようと思います。
以下のようにします。

・MovieSceneモジュール追加
Project.Build.cs

~
    PublicDependencyModuleNames.AddRange(new string[] { "MovieScene" });
~


・処理作成
MyLevelSequenceDirector.h

#pragma once

#include "CoreMinimal.h"
#include "LevelSequenceDirector.h"
#include "MyLevelSequenceDirector.generated.h"

UCLASS()
class PROJECT_API UMyLevelSequenceDirector : public ULevelSequenceDirector
{
    GENERATED_BODY()
    
public:
    UFUNCTION(BlueprintCallable)
        void Pause();

    UFUNCTION(BlueprintCallable)
        void Resume();

};


MyLevelSequenceDirector.cpp

#include "MyLevelSequenceDirector.h"
#include "LevelSequencePlayer.h"

void UMyLevelSequenceDirector::Pause()
{
    Player->Pause();
}

void UMyLevelSequenceDirector::Resume()
{
    Player->Play();
}


これで作成できました。
「LevelSequenceDirector」では「ULevelSequencePlayer」型の「Player」が使えるので、シーケンサーを操作する処理がかなりやりやすいです。

次にWidget生成(クリック待ち)を作成します。
これはBP側で作成します。
ウィジェットブループリントを作成します。
ここでは「WBP_ClickWait」とします。
f:id:naoxgames:20210913222051p:plain

パレットから「Button」を探し、配置します。
そうすることで「階層ビュー」にButtonが表示されます。
f:id:naoxgames:20210913222321p:plain
ボタンは好きなように整えてください。
私は以下のようにしました。
f:id:naoxgames:20210913235759p:plain

次にボタンに押されたときのイベントを設定します。

「階層ビュー」から「Button」を選択し、「詳細ビュー」のイベントから、「OnClicked」を選びます。
f:id:naoxgames:20210914000650p:plain

以下のようなイベントが作成されます。
f:id:naoxgames:20210914000854p:plain

次にイベントディスパッチャーを作成し、呼び出すようにします。
「WBP_ClickWait」の「マイブループリントビュー」から「イベントディスパッチャー」の右にある「+」を押して追加します。
ここでは「OnClickedDelegate」とします。
f:id:naoxgames:20210914001139p:plain

先ほど作成した「Button」の「OnClicked」のイベントから呼び出すようにします。
ドラッグアンドドロップで「呼び出し」を選択する
f:id:naoxgames:20210914001417p:plain
 ↓
f:id:naoxgames:20210914001434p:plain

これでWidgetの対応はできました。


次に「BP_MyLevelSequenceDirector」でクリック待ちのイベントを作成します。

ノードは以下のようにします。
f:id:naoxgames:20210914002044p:plain
簡単に説明します。
上記では「WaitClick」というカスタムイベントを作成。
「UMyLevelSequenceDirector」で作成した「Pause」を呼び、「WBP_ClickWait」を生成して表示。
「WBP_ClickWait」の「OnClickedDelegate」に、ボタンが押されたとき用のカスタムイベントを新たに作成して設定。
「UMyLevelSequenceDirector」で作成した「Resume」を呼び、Widgetを削除しています。


これで汎用処理の準備ができました!!!
(「Pause」とか「Resume」とか作りましたけど、結局使うのは「WaitClick」だけですね。。。)



LevelSequenceDirectorを置き換え

「LevelSequenceDirector」を汎用処理を設定したBPに差し替えます。

まずはシーケンサーのイベントトラックからキーをダブルクリックして「LevelSequenceDirector」に入ります。
この画面です。
f:id:naoxgames:20210913212728p:plain

次に「クラス設定」を押し、「詳細ビュー」から「親クラス」の項目を選択し、「BP_MyLevelSequenceDirector」を選択します。
f:id:naoxgames:20210914002845p:plain

そしてイベントグラフから「WaitClick」を検索すると・・・・
f:id:naoxgames:20210914003119p:plain
ある!!!!!


イベントの設定の仕方

シーケンサーの「LevelSequenceDirector」に入ってからイベントにつなげるのでも問題ありませんが、せっかくなのでシーケンサーから直接設定してみましょう。

シーケンサーのイベントトラックから直接指定することができます。
f:id:naoxgames:20210914003442p:plain
キーを右クリックし、プロパティのイベントからクイックバインドを選択すると上記のように先ほど作成したイベントが呼べるようになっています。
※イベントにすでに設定されている場合はクリアを選択すると選べるようになります。
※引数があるようなイベントの場合、上記のプロパティ内に設定する値が表示され、指定することができるようになります。(ObjectBindingIDとかActorとかも指定できちゃう)

新しいLevelSequenceを作成しても、「LevelSequenceDirector」の親クラスを今回作成したものに変えることで同じ機能が揃った状態になります。

便利!!!!!!!!!!

ちなみに、残念なことに、ここでイベント選んでも、直接そのイベントになるのではなく、都度カスタムイベントが作られる形になります。
こんな感じ
f:id:naoxgames:20210914004213p:plain

シーケンサーで今設定しているイベントが何かを確認しようとすると以下のように、カスタムイベント名が表示されるため、中身がわかりません
f:id:naoxgames:20210914004246p:plain

カスタムイベントが作成されることは避けられませんが、カスタムイベントの名前は変えられます。
カスタムイベント名をわかりやすいものにすることで、シーケンサーからの視認性もよくなると思います。
f:id:naoxgames:20210914004814p:plain


これ、結構便利じゃないですか?各シーケンサーで書かされるより、一つのBPで管理できるほうが楽ですよね。

実行!!!!

ただキャラが左に行くだけのシーケンサーを作ってみました。
途中で「WaitClick」が処理され、一時停止され、ボタンを押すと再開する、というものです。
f:id:naoxgames:20210914005351p:plain
これが以下のようになります。


ちゃんと一時停止して、ボタンを押すと再開していますね。
シーケンサー作成のたびにそれ用の処理を組むという手間が省けるので、かなり使いやすいのではないかと思います。


Plus ultra !!!!

以下の記事で少しエンジン改造をすることで親クラスを始めから任意のクラスに置き換える対応をしてみました。
興味がありましたら見てみてください。
naoxgames.hatenablog.jp



思ったこと

LevelSequenceDirectorについて調べてみるとほとんど情報が出てきませんでした。
今回の対応は内容は全く難しくないですが、恩恵は大きいと思っています。
もしあまり知られていないのであれば是非使っていただきたい!
(もしかしてみんな普通にやってることなのかな・・・・?おれはこの前まで知らなかったよ!!)




正しい対応方法やより良い方法があればご指摘お願いいたします!!!