wigetでシーケンスのフォルダを操作する

自分へのメモも兼ねて記事を起こしていきます。
今回は、レベルシーケンスのフォルダの操作について書いてきます。
実際に使用してみないと使い方が分からないノードもあった為まとめてみました。


# 検証環境
UnrealEngine5.3.2


# フォルダを追加してその中にアクターを入れる
ここから、サンプルのノードを見つつ説明していきます。
サンプルは**いずれも、Widgetで動かして**います。

まずは、『**レベルシーケンスにフォルダを追加してその中にアクターを入れる**』事を実行した例です。
実行結果が以下のようになっています。

![レベルシーケンスにフォルダを追加してその中にアクターを入れる_実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/3912d029-f628-7226-f46b-3e246b176235.png)
フォルダが一つ作成され、その中にアクターが二つ作成されています。

『SequenceActorA』『SequenceActorB』は、Actorから継承しただけのブループリントで、フォルダの中に入れる為に、用意したものです。Spawnableでインスタンス化できるならスタティックメッシュでも何でも構いません。

こちらのノードを実行すると、上の画像の結果が得られます。

![レベルシーケンスにフォルダを追加してその中にアクターを入れる_ノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/37e7dd98-d49c-9937-50dc-1e0985dc382f.png)

ポイントになりそうなところだけ説明させていただきます。

**AddRootFoldertoSequenceノード**

![AddRootFoldertoSequenceノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/28b61b29-f229-b95a-0a6f-e13c22937b5c.png)

AddRootFoldertoSequenceノードは、シーケンスにフォルダを追加します。フォルダを追加するノードは、これしかない為、追加するフォルダの個数の回数だけ呼び出す事になります。
引数の『**NewFolderName**』は作成するフォルダ名になります。

**AddChildObjectBindingノード**

![AddChildObjectBindingノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/0aa55aad-dcab-7267-0df5-085082e0de73.png)

AddChildObjectBindingノードは、フォルダと何らかのオブジェクトを親子するものと考えてください。フォルダに親子付けされると、そのフォルダに入れられます。
第一引数の『**Folder**』は、MovieSceneFolder型(UMovieSceneFolder)を引数にとります。MovieSceneFolderオブジェクトは、変数化できませんので、ブループリントで変数に入れて、保持しておくことはできません。
第二引数の『**InObjectBinding**』は、MovieSceneBindingProxy型(FMovieSceneBindingProxy)を取ります。

:::note info
シーケンスで管理されているアクターやトラックは、MovieSceneBindingProxyを持っている為、ほとんどのオブジェクトで親子付けが可能です。
:::



# フォルダを追加してその中にサブフォルダを追加してアクターを入れる

次に、『**レベルシーケンスにフォルダを追加してその中にサブフォルダを追加してアクターを入れる**』事を実行した例です。
下の画像が実行結果です。

![レベルシーケンスにフォルダを追加してその中にサブフォルダを追加してアクターを入れる_実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/1048a08d-e87f-dbab-56b5-58d6512ffd43.png)

こちらのノードを実行すると、上の画像の結果が得られます。

![レベルシーケンスにフォルダを追加してその中にサブフォルダを追加してアクターを入れる_ノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/f7067938-5b81-913c-8214-7620eb158f0c.png)

ポイントになりそうなところだけ説明させていただきます。

**AddChildFolderノード**

![AddChildFolderノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/b1f55b12-813e-98bc-301c-1d2e9f47a069.png)

AddChildFolderノードは、フォルダ同士を親子付けするノードです。『**TargetFolder**』のフォルダの中に『**FoldertoAdd**』のフォルダが作成されます。
AddRootFoldertoSequenceノードで必要な個数のフォルダのインスタンスを作成し、AddChildFolderノードで階層化していく感じです。



# レベルシーケンスのフォルダを削除する

次に、追加した『**フォルダの削除**』の方法です。
こちらは、実行結果を用意していません。
サンプルノードは、以下の通りです。

![レベルシーケンスのフォルダの中で管理されているアクターを削除する_ノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/d9428252-3096-6c60-d9b5-707f8fa7af7b.png)

ポイントになりそうなところだけ説明させていただきます。

**RemoveRootFolderfromSequenceノード**

![RemoveRootFolderfromSequenceノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/6cefc27d-f63d-59b9-7a54-50bbf1695ef4.png)


RemoveRootFolderfromSequenceノードは、シーケンス内のフォルダのインスタンスを削除します。MovieSceneFolder型を引数に取る為、任意のフォルダを削除したい場合は、**削除したいフォルダのMovieSceneFolder型のインスタンスを見つけてくる**必要があります。
フォルダを削除については、注意点がいくつかります。

:::note warn

1.  RemoveRootFolderfromSequenceノードでフォルダを削除すると子供や孫などの**下の階層のフォルダも削除**される
1.  RemoveRootFolderfromSequenceノードで削除できるのは、フォルダ(のインスタンス)であって、**中に入っているトラックやBindingオブジェクトは削除されない**
※ この場合、フォルダ内のトラックやBindingオブジェクトは、シーケンスの直下に置かれてしまい残ります。<font color="red">**実行時は、消える為、正しく動いているように見えますが、レベルシーケンスを開き直すと残っている事が確認できます**</font>。

:::



# フォルダの中で管理されているアクターの管理を外す

次に、『**レベルシーケンスのフォルダの中で管理されているアクターの管理を外す**』やり方の説明です。
まずは、下の画像は、『フォルダを追加してその中にサブフォルダを追加してアクターを入れる』に対して実行した結果を見てください。

![レベルシーケンスのフォルダの中で管理されているアクターの管理を外す_実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/3a60ad05-c596-e057-c91e-b7f7921ac456.png)

これは、フォルダ内のトラックやオブジェクトを移動させるやり方です。
フォルダ内のあるトラックやオブジェクトのフォルダの管理が外れ、別のフォルダに関連させる事で、トラックの移動が実現できます。しかし、管理が外れたあと、どのフォルダにも管理されなけば、**シーケンスの直下に置かれ**画像もそのような結果になっています。


以下のノードを実行すれば、この結果が得られます。

![レベルシーケンスのフォルダの中で管理されているアクターの管理を外す_ノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/6740f31d-0287-a80c-e19d-6a06fba5f133.png)

ポイントになりそうなところだけ説明させていただきます。

**RemoveChildObjectBindingノード**

RemoveChildObjectBindingノードは、フォルダの子供のBindingオブジェクトを削除します。
上の方でも説明しましたが、<font color="red">**レベルシーケンスからトラックやBindingオブジェクトが削除される訳ではありません**</font>。
また、もう一点気を付けて欲しい事は、<font color="red">**ForEachLoopと相性が悪い点**</font>です。
通常ではあれば、以下のノードのように、『ForEachLoop』を使用するかと思います。

![RemoveChildObjectBindingとForEachLoopの相性が良くない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/13b5028f-624d-21f8-be3c-6dd1e3334023.png)

しかし、こちらの方法だと、『GetChildObjectBinding』から返されている配列が、参照になっており、RemoveChildObjectBindingノードを削除する度に、要素が減るので、**最後までループが実行されません**。
その為、サンプルでは、通常の『ForLoop』で回しています。




# フォルダの中で管理されているアクターを削除する

ここでは、『**レベルシーケンスのフォルダの中で管理されているアクターを削除する**』事について説明します。
下の画像は、『フォルダを追加してその中にサブフォルダを追加してアクターを入れる』に対し実行した結果です。

![レベルシーケンスのフォルダの中で管理されているアクターを削除する_実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/c0a67cf7-743a-4940-042d-029312ee9e13.png)

以下のノードを実行すれば、この結果が得られます。

![レベルシーケンスのフォルダの中で管理されているアクターを削除する_ノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/ab29d8dd-edcb-b2b0-f3b1-3fdf9563f0db.png)

ポイントになりそうなところだけ説明させていただきます。
ポイントとしては、MovieSceneBindingProxyのRemoveを呼び出している点です。

![MovieSceneBindingProxy_Removeノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/5420323b-5b85-ae38-4f96-5d9f8e3fb933.png)

また、Removeを呼び出すだけだと、**フォルダの中のオブジェクトが削除されるだけなので、フォルダも消したい場合は、RemoveRootFolderfromSequenceノードと組み合わせで使う**事になると思います。



# フォルダの見つけ方

最後に特定のフォルダの見つけ方についてです。
簡単にテキストエディットに入力されたのフォルダ名が見つけられるノードを組んでみました。

![レベルシーケンスのフォルダの中から特定のフォルダを探す_ノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/78947416-41f8-b5b4-6645-c4801c650f4c.png)

基本的には、一階層ごとにループを回して階層を辿っていくような探し方になります。
全てのフォルダのリストの一覧が取れたりすれば、便利なんですが、そんな事もできる訳はなく…。

![GetRootFoldersinSequence_GetChildFoldersノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/16ab147c-62ef-4670-84fe-496f8e931dd2.png)

注意すべきは、シーケンスの直下のフォルダは、『GetRootFoldersinSequenceノード』で取得し、子供以降の階層については、『GetChildFoldersノード』で探していく点です。


# その他

**GetFolderColor / SetFolderColor**

![SetFolderColor_GetFolderColorノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/bd3bcc82-cf0e-c9a6-4fa2-92ea0aa5d581.png)

フォルダ色にアクセスするノード

**GetChildTracks / RemoveChildTrack**

![AddChildTrack_GetChildTrackノード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153021/f979b2ed-ab4d-f952-e77e-f554fc029a5d.png)


トラックにアクセスする系のノード

**C++の定義**
中身を見たい方は、参考にしてください。

- UnrealEngine-5.3\Engine\Plugins\MovieScene\SequencerScripting\Source\SequencerScripting\Public\ExtensionLibraries\MovieSceneFolderExtensions.h
- UnrealEngine-5.3\Engine\Plugins\MovieScene\SequencerScripting\Source\SequencerScripting\Private\ExtensionLibraries\MovieSceneFolderExtensions.cpp