皆様、こんばんは!
以前、レベルシーケンサの再生や逆再生など、再生周りの操作を Blueprint を使って遊んでた時のプロジェクトを改めて起動し、機能追加とかしてみようと思ってたのですが、個人的によく分からない部分もあったため備忘録として残しておきます。
やることはレベルシーケンサにアニメーションシーケンスを入れて再生などしたものです。
本記事はただの検証とその結果を書いた記事なので、いつも以上によく分からないことが沢山書かれているので注意して下さい!
UE 5.1.1 で作成してます。
適当なレベルシーケンスを用意
シーケンサの作成が本題ではないので詳しい内容は割愛しますが、 MF_Run_Fwd(走りアニメ) を使って左から右に移動させるものを作成してます。
再生をコントロールする UI を作成
コンテンツブラウザで右クリック> ユーザーインターフェース> ウィジェットブループリント と選択し WBP_Sequence というものを作成しました。
UI の構成はこんな感じにしています。
ボタンの見た目や名前と内部の処理が一致してませんが、各UIの役割は以下の通りです。
Stop(Button) :押すと一時停止します。
Play(Button) :押すと再生します。一時停止中の場合、その場から再生を再開します。
PlayBack(Button) :押すと逆再生します
PlayForward(Button) :押すと通常再生に戻します(機能は Play と同じですが、実装に使った関数が違い、挙動の違いが確認出来ました。後述しています。)
Seekbar(Slider) :スライダを動かすことでスクラブ(再生位置を調整)する機能です。
レベルシーケンスを変数にして使いやすくする
WBP_Sequence のグラフで右クリックし「On Initialized」を出し、「Set Input Mode UI Only」+「Set Show Mouse Cursor」で UI 専用の操作にしてみました。
※ 今回の例だと「On Initialized」ではなく「Construct」でも同じですが、初期化の処理は1回実行されればいいので「On Initialized」を利用しました。
更に「Create Level Sequence Player」の Return Value から変数へ昇格し、以降シーケンサのあれこれはこの変数を利用します。
(最初スクラブのテストをしていたので変数名は Scrub Sequence としています)
「On Initialized」の続きの部分です。
先程変数へ昇格した Scrub Sequence から引っ張り「Get End Time」を出します。この Return Value は "Qualified Frame Time 構造体" になっており、構造体を分割をすると表示される Value(Integer型)でシーケンサの最終フレーム(時間?)を取得できます。
これも変数に昇格し "End Frame" という名前にしました。
最後に Seekbar から引っ張り「Set Max Value」の "In Value" ピンに「Get End Time」で取得した値を渡し、スライダの最大値をシーケンサの最終フレームと同じにします。
"End Frame" に入る具体的な値ですが、この例だと 72 になります。
そしてレベルブループリントで「Create Widget」から「Add to Viewport」し、開始時にシーケンサを再生する冒頭の動画の挙動ができます。後は UI の操作と連動する部分を作成していきます。
再生・一時停止
再生は「Play」、一時停止は「Pause」を利用するだけなので簡単です。「Stop」という関数もありますが、これは停止後に「Play」すると最初から再生されるので挙動が違います。
また、シーケンサが最後まで再生された後にもう一度「Play」を呼ぶと最初から再生になります。
余談ですが、再生ボタンをクリックすると一時停止のアイコンに変わり、もう一回クリックすると再生のアイコンに変わるような、1ボタンで「Play」⇋「Pause」を切り替えれる UI がいいかなと思いました。
逆再生・順再生
逆再生は「Play Reverse」という関数が用意されており、呼ぶと現在の再生位置から逆再生が始まります。
順再生は普通の再生と同じく「Play」を呼んでいるため、現在の再生位置から普通に再生を再開しているという挙動です。
気になる点がありまして、この動画の5秒あたりで「Play Reverse」を呼んでシーケンサの最初に戻った所に注目すると、開始位置に戻っているのにピタッと止まってないことに気づきました(少し長めにアニメーションが再生されている)
また、順再生の方も同じくシーケンサの最後まで再生された時にピタッと止まってませんでした。
理由はよく分からないが原因は分かった
MF_Run_Fwd の0フレーム目(開始時)に Anim Notify を仕込み、アニメーションが開始した瞬間が分かるようにしました。
なぜそういう挙動になっているのかは分かりませんでしたが「Play Reverse」でシーケンサの最初に戻った時に MF_Run_Fwd(走りアニメ)が再生されていたのが原因でした。
画像にはないですが、同じ手法で MF_Run_Fwd 終了時にも Anim Notify を仕込んでシーケンサを最後まで再生させると同じくアニメーションが再生され続け、その終わりで Anim Notify が実行されました(シーケンサの終了より少し遅れて Anim Notify が実行された)
細かい所ですが仕様的にそういうもんじゃないか...という気持ちを抑え、どうにかシーケンサと連動してアニメーションがピタッと止めれないかと色々確認してみました。
検証1:When Finished で挙動が変わる
この挙動ですが、レベルシーケンス上に追加したアニメーションを右クリック> セクションの編集> When Finished を "Keep State" にしているとこうなるようでした。
これはシーケンサの再生が終わった時に固定したいものがある時に利用するプロパティです。例えばドアを開けるカットシーンがあった時に、ドアを開きっぱなしにしておくなどが出来ます。
"Keep State" を "Restore State" に変更した時の挙動がこちらです。
ピタッと止まりましたが Idle になりました。走りアニメーション中に止まって欲しかったので想定してた結果にはなりませんでした。
"Restore State" は再生する前の状態に戻ります。
ドアの例だと、シーケンサの再生が終わったらドアが閉まった状態に戻ります。
検証2:「Play To」を使って解決
※上記の「Play Reverse」「Play」を「Play To」に置き換えた画像
※元の「Movie Scene Sequence Playback Params を作成」
When Finished を "Keep State" にしている挙動の方が理想だったので "Keep State" のままで何か出来ないかも確認していると「Play To」を使うことで解決出来ました。
「Play To」の "Playback Params" 入力ピンから引っ張り、「Movie Scene Sequence Playback Params を作成」を出して構造体ピンを分割した状態の画像です。
「Movie Scene Sequence Playback Params を作成」の "Position Type" が [Frame] の場合、Frame Number の Value の値を利用するようです。
この数値はレベルシーケンサ上のフレームと同じ扱いのようです。
UI の逆再生ボタンを押すと「Play To」で現在の再生位置から 0フレームへ向けて再生されるので実質逆再生になります。
順再生ボタンを押すと、今回 End Time が 72 のシーケンサなので、現在の再生位置から72フレームへ向けて再生されるので順再生になりますが、「Play」と違い 72フレーム目に来た時ピタッと止まります。
▼ それがこの動画です
動画の最後に、逆再生後に普通の再生(「Play」を呼ぶ)ボタンを押した時は最後がピタッと止まってないことが確認できます。
検証結果:「Play」「PlayTo」
なにかの設定等で回避出来たのかもしれませんが、とりあえず今回の検証で分かったことは、再生するアニメーションを Keep State にして「Play」でシーケンサの最後まで再生した場合そのアニメーションの1サイクルが終わってないとそのまま再生され続けることが分かりました。
「Play Reverse」で逆再生した時、0フレームに戻ったタイミングでそのアニメーションを再度再生して止まるという結果になりました。
アニメーションの1サイクルとは画像で示したシーケンサ上の「|」こんなアイコンの所です。今回のシーケンサでは2サイクル目のアニメーションが再生されますが、2サイクル目が終わる前にシーケンサが終了してしまうため、残りのアニメーション終了まで再生されたということだと思います。
「Play」と「PlayTo」で何か処理が違うんですかね...
今まで「Play」「Stop」「Pause」くらいしか使ったことなかったので色々知れて勉強になりました。
スライダを使ったスクラブで再生位置を調整
こんな感じでスライダを使って再生位置を変更できます。
再生中のスライダが連動して動いていませんが、シーケンサの現在の再生位置を取得し続けるような仕組みをどう実装すればいいか分からなかったため今回は未実装になりました。
後述する「Set Playback Position」を WBP_Sequence の Tick で使えばそれっぽい挙動は出来たのですが、一時停止中などシーケンサを止めている場合でも常に実行され続けるため余分な処理が続くな...と思いました。
完成した Blueprint を先に貼っておきます。
先程スライダ(変数Seekbar)の「Set Max Value」を End Time である 72 に設定したのでスライダの値は 0~72 の間になっています。
スライダの値をそのままシーケンサのフレームへセットすることで実現できます。
「On Value Changed」 はスライダの値が変更される度に呼ばれます。スライダを左右に動かしている間も値が変わるので呼ばれます。
Scrub Sequence から引っ張り「Set Playback Position」を出します。これがシーケンサの再生位置を直接変更できる関数のようです。
これも構造体ピンを分割していき、Frame Number の Value に「On Value Changed」で変更された値 Value を繋ぎます(Float から Integer への変更のため、切り捨ての Truncate が使用されています)
「Play To」の時も出てきましたが、"Position Type" が [Frame] の場合、Frame Number の Value の値を利用するようです。
「On Mouse Capture Begin」 はスライダ上をクリックした時に1度呼ばれます。そのままスライダを動かしている間は呼ばれません。
こちらはスライダをクリックした時に「Is Playing」でシーケンサが再生されているかチェックし、再生中であれば「Pause」を使って一時停止させています。
「On Mouse Capture Begin」の方が先に処理されますが、スライダ上をクリックした = 値が変わったという事でもあるのでその後「On Value Changed」も処理されます。
スライダの値を再生位置の指定にそのまま使えるので処理自体は結構簡単ですね。
おわりに
この検証ですがネットで調べても全然情報がなく色々なノードや設定を変更してこういうことなのかな...というのが分かったのですが個人的にかなり苦戦してました。
例えば「Get End Time 」で取得した 72 という数値。これは記事にあったシーケンサの最終フレーム を取得出来ます。
しかし「Play To」や「Set Playback Position」で値をセットしたのは Frame の Value が使われています。取得は Time でセットが Frame だったので混乱してました。
そして "Position Type" の [Frame] で、[Time] を選ぶこともできるんですが、その場合は Time の値が利用されます。Frame の Value に何を指定していても関係なくこれも混乱していた原因の一つです。
しかも構造体ピンを分割とかしないと見つけられないこともあり、最初これを何に使うのか?むしろ使わない?ということも含め全然わかりませんでした...
そしてシーケンサの0フレーム・最終フレームへ到達した時のアニメーションがピタッと止まらない等々、分からないことが続いていたとは言えかなり勉強になりました。
場合によっては「Play To」での再生もいいかもしれないなということで今回は終わりにします。
それではまた!