目次
※この記事で使用しているUnrealのVersionは04.25.3です。
※この記事のサンプルプロジェクトは以下URLにアップされています。
WorldContextについて レベル【★★☆】
最近いろんな人(プログラマー)から「EditorUtility系のBPとかでWorldContextの取得ってどうやるの?」と聞かれることが多かったため、WorldContextについてここにまとめておきます。
普段Level BlueprintやActor Blueprint内で、例えば「Get All Actors of Class」関数を使うとします。
その際は特に不自由なくノードを使えるかと思います(↓ActorClass内のGet All Actors of Class)
しかし、EditorUtilityObjectなど(Worldに属さないObject)の中で「Get All Actors of Class」を使おうとすると、「World Context Object」ピンがスッと現れます。
このWorldContextに何かしらのUObjectの参照をつなげてあげないと、コンパイル時にエラーを起こしたり、Play In Editor時に挙動がおかしくなったりします。
↓Editor Utility ObjectなどのWorldに属さないオブジェクトではコンパイル時にエラーがでる。
↓Editor Utility WidgetでPlay In Editor時にGet All Actors of Classを使った際の不自然な挙動
Editor Utility Widgetでは、World Contextに何もつながなくてもエラーは出ませんが、その場合はプレイしていても、プレイをしていない時のWorldを取得してしまいます。
なので、↑の動画のように、プレイ中にあるStaticMeshが移動しないで、プレイを終わった後のEditor上のStaticMeshが移動してしまっています。
Q.じゃあWorldContextって何のためにあるの?
この「World Context Object」は何のためにあるのかというと、関数を実行するObjectがどの環境のWorldに属しているかを明示的に指定するためにあります。
パッケージされたゲームでは、基本的にWorldContextはゲームプレイ中にストリームする各PersistentLevelのWorldとなるかと思います。
ですがEditor上では、Play時と非Play時でそれぞれ別のWorldとなっています。
考えてみればわかるかと思いますが、Play時と非Play時のWorldが同じ環境を使っていたら、PlayするたびにWorldの中が変更されその情報をそのまま.umapアセットに保存してしまうことになります。
なので、Play時には、非プレイ時のインスタンス環境をそのまま使わずに、Play用に新しい環境を構成してそこでPlayを行っているというわけです。
※上記説明はなるべくわかりやすく説明しているため、事実と若干異なる部分もありますがご了承ください。
Q.なら明示的にPlayか非プレイのWorldContextを指定できたりする?
Editor上、Play In Editor上のそれぞれのWorld Contextを取得する方法はあります。
Editor上(非プレイ時)のWorldContextの取得
UWorld* UEditorLevelLibrary::GetEditorWorld()
Editor上(GamePlay時)のWorldContextの取得
UWorld* UEditorLevelLibrary::GetGameWorld()
※この関数は「Editor Scripting Utilities」というプラグインを有効にしないと使用できません。(4.25でプロジェクト作成するとデフォルトでONになっている)
この関数で取得したObjectをWorldContextにつなげてあげることで、取得した環境のWorldに対して関数を実行できます。
以下プレイ中のStaticMeshを動かした動画
(動画ではMobilityをMovableにしてなかったから1回動きませんでした。焦りました^^;)
ちなみに、GetEditorWorldはPlay In Editor中はNullになり、GetGameWorldは非プレイ中にNullになります。
なので最初の動画で、Editor Utility Widget内でWorld Contextを繋げない場合はプレイ中でも非プレイ時のアクターに対して処理をしていましたが、GetEditorWorldで取得したObjectをWorld Contextにつなげると、プレイ中に実行しようとするとエラーを返すようになります。
↓以下ログ
LogEditorScripting: Error: The Editor is currently in a play mode.
LogScript: Warning: Script Msg: A null object was passed as a world context object to UEngine::GetWorldFromContextObject().
これを応用して今プレイしてるかどうかもC++コードなしでEditor Utility上で取得できます。
このWorld Contextを理解することで、Editor Utilityでプレイ中のデバッグメニューなども作成できます。
簡単な説明ではありましたが、以上です。
※この記事のサンプルプロジェクトは以下URLにアップされています。