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

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

UE4 シーケンサーを一時停止する

シーケンサーを使っていて一時停止で困ることがあります。
タップ待ちなどでシーケンサーの進行は一時停止したいが、キャラのモーションは継続させたい。
もしくはシーケンサー関係なくゲーム自体を一時停止させることでシーケンサーもキャラも、ゲーム内すべてを停止させたい。
そんな感じで使い分けるならどんな感じでやるのかなとふと思ったので対応してみる。




目標・要件


シーケンサーの一時停止を2種類対応する。
・キャラのモーションは継続させるがシーケンサーの進行は停止させる。
・キャラのモーションもシーケンサーも、ゲームの進行自体を停止させる。


環境

・UE 4.27.0 (Gitのコミット:99b6e203a15d04fc7bbbf554c421a985c1ccb8f1 をビルド)
・VisualStudio 2019 16.11.2
・サードパーソンのテンプレートを元にします。


やってみる

作戦としては
一時停止系に関しては調べてみると
シーケンサーを一時停止させる
→「UMovieSceneSequencePlayer::Pause」を利用する。

・ゲームの進行自体を停止させる
→「UGameplayStatics::SetGamePaused」を利用する。

とするのがよさそうです。

シーケンサー一時停止中にモーションを継続させる。
→AnimationTrackを使うと一時停止してしまうので、AnimationBlueprintで処理させる。

という対応を検討してみます。


準備

まずはテスト用のシーケンサーを作成します。
私は以下のような感じで作成しました。

f:id:naoxgames:20220211000724p:plain
内容としては
・サードパーソンのプロジェクトにある「ThirdPersonCharacter」をSpawnableで配置
・「ThirdPersonCharacter」の開始と終わりに適当な座標を設定し、移動させる
・「CameraActor」をLevelに配置し、Possessableで設定(Spawnableでも問題なし)
また、名前は「LS_Pause_Test」としています。

このシーケンサーを再生すると、立ちモーションのまま移動をするだけのものになっているはずです。

作成したらレベルに配置して、「自動プレイ」「ループ」を以下のように設定しておきましょう、確認が楽になります。
f:id:naoxgames:20220211001415p:plain
これを元にこの先の対応を行っていきます。


シーケンサーを一時停止させる

特に凝ったことはせず、あっさり対応します。
イベントトラックで以下のように設定します。
f:id:naoxgames:20220210235621p:plain
f:id:naoxgames:20220210235648p:plain
「LevelSequenceDirector」(イベントトラックの中身設定するところ)で「LevelSequencePlayer」である「Player」を呼び出し、「Pause」を呼ぶだけです。
タイミングは任意に設定してください。

これだけでは一時停止して何もできなくなるだけなので、再開させる処理も対応します。

ここではレベルブループリントに書くことにします。
レベルに配置した「LS_Pause_Test」を選択した状態でレベルブループリントを開き、リファレンスを作成でアクセスできるようにします。
f:id:naoxgames:20220211001709p:plain
そして以下のようにします。
f:id:naoxgames:20220211001921p:plain
この例では「1」キーを押したときにPlayをするようになっており、一時停止時は再開をするようになります。

ここまでの対応で実行をすると、
シーケンサーが途中で止まる
・キャラは立ちモーションを継続している
・「1」キーを押すとシーケンサーが再開する
となります。


ゲームの進行自体を停止させる

次にゲームの進行を停止、つまりキャラのモーションすらも止めてなにも動かない状態にします。
f:id:naoxgames:20220211002312p:plain
これを呼べば終わりです。
ですがこれを呼ぶと、復帰することができなくなるので復帰処理を書きたくなります。
例えば以下のようにします。(レベルブループリントに書いてます)
f:id:naoxgames:20220211003341p:plain
このようにすると、
・「2」キーを押すと一時停止
・「3」キーを押すと再開

と思いきや、このままではうまくいきません。(試してみてください。)

調べてみると、Widgetなどでしかイベントを取得できなくなるようです。
ですが入力処理に設定をすることで呼ばれるようにすることが可能です。

インプットイベントの以下の詳細から「Execute when paused」にチェックを入れます
f:id:naoxgames:20220211003843p:plain
これによって呼ばれるようになりました。(試してみてください。)

例として「2」「3」キーに処理を割り当てましたが、このままにしておきましょう。


ここまでの対応で実行をすると、
シーケンサーが途中で止まる
・キャラは立ちモーションを継続している
・「1」キーを押すとシーケンサーが再開する
・「2」キーを押すとゲームが一時停止して、キャラのモーションも停止する
・「3」キーを押すとゲームが再開する
となります。


アレ?できたんじゃね?


シーケンサー一時停止中に任意のモーションを継続させる

とりあえず要件満たしましたが、現状モーションは立ちモーション一択です。
かといってアニメーショントラックを使ってモーションをさせると、シーケンサー一時停止時にそのタイミングのセクションの位置でモーションが止まってしまいます。
なので任意のモーションに変更できる足がかりを考えてみます

そもそもシーケンサー一時停止を使うときは、おそらくタップ待ちなどの処理になると思われます。
となると、基本的にはループモーション的なものが設定されるのでしょう!という前提で考えます。

作戦としては、
・AnimationBlueprintに変数を追加
・その値に応じてモーションを変化させる
・その値はシーケンサーから設定できるようにする
という感じで行こうと思います。

まずはAnimationBlueprintについて、以下のようにしてみます。
f:id:naoxgames:20220211005526p:plain
こちらはサードパーソンのプロジェクトにある「ThirdPerson_AnimBP」を編集しています。
「IsOverride」というboolの変数を追加する必要があります。
「IsOverride」は以下のように「シネマティクスに公開」にチェックを入れましょう、シーケンサーでいじれるようになります。
f:id:naoxgames:20220211005922p:plain
C++では以下のようにします。

UPROPERTY(Interp, BlueprintReadWrite)
    bool IsOverride;


この処理で、「IsOverride」が「True」だったら「ThirdPersonRun」モーションが流れる ということになります。
(「ThirdPersonRun」はサードパーソンのプロジェクトにあるマネキンの走るモーション)


次にシーケンサーでAnimationBlueprintの値を設定します。

以下のように対応します。
・キャラのSkeletalMeshComponentを設定します。(ここでは「CharacterMesh0」) f:id:naoxgames:20220211010313p:plain

・SkeletalMeshComponentからアニメーションインスタンスを設定します。(ここでは「ThirdPersonAnimBP」)
f:id:naoxgames:20220211010501p:plain

・先ほど追加した「ThirdPersonAnimBP」の「IsOverride」の変数を探し、設定します。
f:id:naoxgames:20220211010750p:plain
以下のように「IsOverride」を「False」にしたり「True」にしたりする
f:id:naoxgames:20220211011223p:plain


これによりモーションは
シーケンサーの特定タイミングで走りモーションになったり、立ちモーションになったりする
シーケンサーから指定できる
シーケンサー一時停止の影響を受けない
ということになります。

※ここではboolでやりましたが、使い勝手悪すぎるので、実際はEnumとかにしてC++側で判定したモーションをAnimBPに渡して流すとか、そういう感じにするのが良いと思います。


思ったこと

物自体はわりと簡単でしたね。
一時停止したーーいって言われて、一時停止だけならすぐだけと、モーションとかAnimationBlueprintとかも絡んでくるからさほどあっさりではないよねっていう。
今回調べるまで「Execute when paused」知らなかったし、わりと普通に一時停止系やると困ることがちょこちょこありそうだなと思いました。




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