お世話になっております。
現在制作中のプロジェクトでは、ワールドパーティションを利用しているレベル上で、いくつかのレベルインスタンスを配置することで設計されているレベルが存在しています。
シーケンスの再生中、レベル上のレベルインスタンス内のオブジェクトを移動させるなどの操作を行いたいと思っています。
レベル上の通常のオブジェクトを操作する手法と同様に、Possessable なアクターとしてトラックを追加しようとしても、
・元のレベルの編集状態では追加ができない
・そのオブジェクトが配置されているレベルインスタンスを編集状態とすると追加できるようになるが、元のレベルで再生してもPossessable トラックでの操作は実行されない(バインドがうまく紐づけられていない)
といった問題があり、うまくいっておりません。
[Content removed] で紹介されているFActorSpawnParameters::OverrideLevel を使用することも試みましたが、現状ワールドパーティション上のレベルインスタンスはインゲーム中ではうまく取得できていません。
[Content removed] アクタ自体は存在していないように見えます)
[Content removed]
レベルインスタンス内のオブジェクトをシーケンス上で操作する正しい方法がございましたら、ご教授いただければ幸いです。
よろしくお願いいたします。
[Content removed]
ご報告ありがとうございます。
ご指摘の挙動につきましては、WP環境下でLevel Instance内のアクターをSequencerからバインドしようとした際の制限として知られているものかと思われます。Epicの公式テックノートにおいても、Level Instance内に対するLevel Sequencerのサポートは現状提供されていない旨の記載がございます。
技術的な背景としましては、ALevelInstanceアクターはエディタ上の論理構造としてのみ存在しており、クック/ランタイム時にはストリーミングジェネレータがコンテンツを展開してWPランタイムセルに分配する形となります。この過程でコンテナID(FActorContainerID)を含むアクターパスがマングルされるため、SequencerのPossessableが保持しているパス情報がランタイムで解決できなくなっているものと思われます。OverrideLevelをご使用いただいた場合も同様で、ランタイムには独立したULevelとしてコンテンツがロードされておらず、ALevelInstance自体も残っていないため、指し示せる対象が存在しない状態となっているかと考えられます。
回避策としましては、以下のようなアプローチが考えられるかと思いますので、ご状況に応じてご検討いただければ幸いです。
- Dynamic Binding/Replaceable Bindingの使用:Sequencer側のバインディングをDynamic/Replaceableに切り替え、リゾルバBlueprintで実行時にターゲットアクターを返す形をお試しいただく方法です。パスではなくゲームプレイ上のアイデンティティで解決する仕組みのため、Level Instance経由かどうかには依存しにくくなるかと思われます。汎用性の観点では比較的扱いやすいアプローチかと存じます。
- プロキシBlueprintによる中継:パーシスタント側に小さなBlueprintアクターを配置し、BeginPlayでタグ等から内部アクターを取得してSequencerからの変更を中継する形となります。Dynamic Bindingがご利用いただけないバージョンでの代替案としてご参考になればと思います。
- 対象アクターをLevel Instanceから外す:シーケンス専用のギミックである場合には、Level Instanceに含めずパーシスタント側に直接配置していただく構成もご検討いただけるかと存じます。OFPAをご利用いただいていれば、共同編集の観点でも大きな問題は生じにくいのではないかと思われます。
お手数ですが、よろしくお願いします。
お世話になっております。
ご指摘の「同じLevel Instanceがいくつも置かれているとき、同じ椅子オブジェクトをどう見分けるか」という点が、今回いちばんむずかしいところだと思います。これはSequencerだけの問題ではなく、同じテンプレートから複数のインスタンスを作るというLevel Instanceの仕組みそのものによるものです。置かれたインスタンスはアセットとしてはまったく同じなので、アセット側の情報だけで「3番目のHouseの椅子」を見分けるのは、仕組み上むずかしいというのが正直なところです。
現実的な方法としては、見分けるための情報をHouseテンプレート側に置いたアクターに持たせるやり方が中心になると思います。具体的には、Houseテンプレートの中に小さなBlueprintアクター(アンカー、またはトリガーを兼ねたもの)を1つ置き、同じHouseの中の椅子への参照をエディタ上で設定しておきます。この参照はLevel Instanceの中だけで完結する参照(両方が同じインスタンスの中)なので、コンテナID(FActorContainerID)によるパスの再マッピングを通じて、各インスタンスがそれぞれ自分のHouseの椅子を正しく指す形になるはずです。パーシスタント側とインスタンスの中をまたぐ参照が壊れてしまうのとは違い、中だけで完結する参照はインスタンスごとに分かれます。ただしこのあたりは挙動が異なる部分なので、念のためクック後のWPビルドでご確認いただければと思います。
シーケンスに「どのHouseか」を伝える部分は、アセットではなくゲームプレイ側から渡すのがいちばん自然だと思います。たとえばトリガーをHouseテンプレートの中に置いておけば、各インスタンスがそれぞれ自分専用のトリガーと椅子への参照を持ちます。プレイヤーが入ったときやクエストが始まったときなどに、そのトリガーが持っている椅子の参照をバインディングのオーバーライドとしてLevel Sequenceに渡してから再生します。こうすると「どのトリガーが動いたか」がそのまま「どのHouseか」を表すので、同じインスタンスを無理に見分ける必要がなくなります。オーバーライドは、Dynamic Bindingのリゾルバに椅子の参照を渡す方法でも、これまでどおりGet Sequence Bindings→Add Bindingでそのトラックを差し替える方法でも、どちらでもできると思います。
トリガーのような場所のきっかけがなく、ディレクター側でHouseを選ぶ必要がある場合は、上のアンカーをBeginPlayでWorldSubsystemなどに登録しておき、ゲームプレイ上で意味のあるIDから探す形になります。それもむずかしく、アセット側だけで見分けたい場合に限っては、ご提案の座標を使う方法が現実的な代わりになります。そのときは「いちばん近い椅子を探す」よりも、アンカー自身の決まったワールド座標をキーにするほうが、問題が起きにくいと思います。
なお、エディタやPIEではGetLevelInstanceSubsystem()->ForEachActorInLevelInstance()でインスタンスごとにアクターを取得できますが、クック後のスタンドアロンWPビルドではALevelInstanceが存在しないため使えません。ご確認いただいた挙動とも合っています。そのため、ランタイムで確実に動かすなら、テンプレートの中に置いたアクターを使う方法が確実だと思います。
お手数ですが、よろしくお願いします。
ご返信ありがとうございます。
そして、対応方針をこれほど丁寧に整理してお知らせいただき、大変ありがとうございます。
タグによる照合で再バインドし、複数一致する場合は0フレーム時点のTransformで最も近いものを採用する、という流れ、とても筋の通った設計だと思います。設定時の競合の少なさと手順の簡潔さを優先されたご判断は、実運用をしっかり見据えた的確な落としどころで、すぐに回り始める形になっているのが素晴らしいです。
4のTransformによるフォールバックも実用上まったく問題ないかと思います。もし今後さらに精度を上げたくなった際には、椅子そのものの座標(アニメーションで動く可能性があります)よりも、タグを付与しているBP自身の確定したワールド座標を基準にすると一段と安定しやすいかと思いますので、引き出しの一つとして覚えておいていただければ幸いです。
配置後のインスタンスを判別する手段、あるいはLevel Instanceの段階でバインドを正しく紐づけられる仕組みのご要望につきましては、確かに承りました。関係チームへしっかり共有させていただきます。同種のお声は他のライセンシー様からもいただいており、今後の改善につながる貴重なフィードバックとして申し伝えます。
本件、ご案内のとおりクローズとさせていただきます。難しいテーマながら、きれいな着地点までたどり着かれていて、こちらも嬉しく思います。制作の追い込み、どうぞお気をつけて。また何かございましたら、いつでもお気軽にお声がけください。
引き続きよろしくお願いします。
ご回答ありがとうございます。
レベルインスタンス内のオブジェクトをシーケンサーで直接操作する機能はないとのことで、承知いたしました。
頂いた回避策で対応可能か検討しようと思います。
ご提示いただいた回避策のアプローチを検討しましたが、今のところ、解決にいたっておりません。
Blueprint によってバインドを解決する手法を取りたいと考えていますが、実際にはうまく解決できる手立てがないと感じています。
例として家の外装と机、椅子のような内装が1セットとなった"House" というLevel Instance がパーシスタントレベルに複数個配置されていたとき、
そのうち一つの"House" Level Instance を舞台としたレベルシーケンスで、椅子を非表示にしたい場合があります。
この時、適切な"House" Level Instance 産の椅子Static Mesh オブジェクトを取得できるシステムは、どのように構築できるでしょうか。
こちらで検討した限りでは、ただ一つである固有のレベルインスタンスのアクターを特定することはできそうですが、
同一のレベルインスタンスが複数配置されている場合の、同じ椅子オブジェクト同士を判別する方法には思い当っておりません。
シーケンス側も多数の映像があり、操作する対象は椅子とは限らないため、対象アクターをLevel Instance から外すのも現実的ではありません。
強引な手段となってしまいますが、レベルインスタンスの座標情報を特定用の情報に含め、最も適合する座標にある椅子オブジェクトを取得する方法は考えられます。
Level Instance を利用したワールドパーティションのレベル設計は現行のUE の機能では一般的ではないかと推測しますが、
現実的な手段でレベルシーケンスと併用することはできないのでしょうか?
もし良い方法がございましたらご教示ください。
よろしくお願いいたします。
ご回答ありがとうございます。
配置後のLevel Instance はアセットとして同一であり、アセット側の情報だけで複数の椅子を判別するのは仕組み上難しいとの旨、承知いたしました。
いただいたご提案も加味して現状、以下のように対応しようと考えています。
1. Level Instance 内のオブジェクトに一意なアクタータグを付与するBP を配置する
2. シーケンスにLevel Instance 内のアクタートラックを追加した時、付与したアクタータグと同じタグをトラックに付ける
3. 再生時はトラックタグとアクタータグで照合し、一致するものを再バインドする
4. 同一Level Instance が複数置かれていることで、一致するアクタータグが複数ある場合、0フレーム時点のトラックのTransform(存在しない場合は他の座標を利用)のうち最も近いものを採用する
4. の判定は状況によっては問題がありそうですが、運用中に判定用の工夫を施すことができそうなため、設定時の競合や手順の少なさを優先しています。
もし今後のアップデートで配置後のインスタンスを判別できる方法、またはLevel Instance の時点でバインドをうまく紐づけられる方法を追加していただければ、
より安全な方法で管理できることになりますので、要望いたしたく存じます。
この質問はクローズしていただいて構いません。
ありがとうございました。