※この記事で使用している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にアップされています。

サンプルプロジェクト

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です