2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UE5のWorldContextについての解説!

2
Posted at

UnrealEngineで使われるWorldとWorldContextとは?

Worldとは?

アクターを配置する空間の事です。
マルチプレイゲームなどを実装していると、わかると思いますが、複数のゲームインスタンスを実行できる事から
UnrealEditorでは複数のWorldを実行する事が可能です。
image.png

その他にもUMGEditorやMaterialEditorやPersonaEditorなど、ビューポート毎にもWorldは用意されます。

UnrealEditor上のワールドのイメージ
-UnrealEditor
    - EditorWorld
        - Level
            - Actor
            - Actor
    - GameWorld1
        - Level
            - Actor
            - Actor
            - Actor
    - GameWorld2
        - Level
            - Actor
            - Actor
    - MaterialEditor1
        - Level
            - Actor
    - PersonaEditor1
        - Level
            - Actor
            - Actor

WorldContextとは?

Outer(親のUObject)経由で最終的にWorldにつながっている物の事
UObject::GetWorldを呼び出した結果所属しているWorldを取得できるUObjectの事

TArray<AActor*> Actors;
UGameplayStatics::GetAllActorsOfClass(WorldContextObject, APawn::StaticClass(), Actors);

例えば上記の関数を呼び出したときに、UnrealEditor上では複数のWorldが存在している為、どのWorldに所属しているPawnを取得するべきか分からない
その為、WorlcContextを指定する事でWorldを呼び分ける事ができます。

独自クラスでWorldContext対応をする為には?

WorldContext対応Blueprint WorldContext非対応Blueprint
image.png image.png

GetWorldを実装していないオブジェクトを親クラスに継承した場合には、上記の画像のように関数を呼び出した時に
WorldContextが表示されます。
BlueprintEditor上ではUObject::ImplementsGetWorldを呼び出して、GetWorld関数が実装されているかのチェックをしています。


bool UObject::ImplementsGetWorld() const
{
	bGetWorldOverridden = true;
	GetWorld();
	return bGetWorldOverridden;
}

UObject::GetWorldのデフォルトの実装では、bGetWorldOverriddenの変数が、設定される為未実装扱いです。

Engine\Source\Runtime\CoreUObject\Private\UObject\Obj.cpp
class UWorld* UObject::GetWorld() const
{
    // 親のOuterを取得してそのWorldを取得する
    // 再帰的なループによって親が見つかるまで繰り返す
	if (UObject* Outer = GetOuter())
	{
		return Outer->GetWorld();
	}

#if DO_CHECK || WITH_EDITOR
    // Blueprint上でWorldが実装されているかのチェック
	bGetWorldOverridden = false;
#endif
	return nullptr;
}

Super::GetWorldを呼び出さない実装を作る事でWorldContext対応のUObjectにできます

class UWorld* UHogeHoge::GetWorld() const
{
	if (UObject* Outer = GetOuter())
	{
		return Outer->GetWorld();
	}
	return nullptr;
}

なぜこの記事を書いたのか???

WorlcContextを省略する為に、GameInstanceをSingletonにするようなケースが散見されます。

非推奨のGameInstanceでシングルトンを書くコード
非推奨コード
UCLASS()
class UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()
public:
	static UMyGameInstance* GetInstance() { return SingletonInstance; }
	virtual void Init() override
    {
    	SingletonInstance = this;
    	Super::Init();
    }
	virtual void Shutdown() override
    {
    	Super::Shutdown();
    	SingletonInstance = nullptr;
    }  
private:
	static inline UMyGameInstance* SingletonInstance = nullptr;
};
非推奨コード
void UMyBlueprintFunctionLibrary::MyFunction()
{
    // 無理やりGameInstanceを使う例
    // MyFunctionをどこで呼んでも、GameWorldのPlayerを取得できてしまう
    UMyGameInstance* pInstance = UMyGameInstance::GetInstance();
    APawn* pPlayer = UGameplayStatics::GetPlayerPawn(pInstance, 0);
    if (IsValid(pPlayer))
    {
    	pPlayer->Destroy();
    }
}

AnimNotifyやシーケンサーのディレクターBlueprintなどで上を実装すると
PersonaエディターやシーケンサーエディターとPIEが同時に動いているときに、意図していない挙動になります。
マルチプレイヤーなどの観点からもWorldContextの省略は避けるべきです

特殊なWorldContextの実装例に関して

UObjectのOuterがWorldに紐づいていない場合のGetWorldの実装例です。
アニメーションアセットなど何度も実行される為、UObjectの複製コストを避ける為の実装です。
おおよそconst関数で、Blueprintで定義できる関数が定義されているのが特徴です

AnimNotify


UCLASS(abstract, Blueprintable, const, hidecategories=Object, collapsecategories, MinimalAPI)
class UAnimNotify : public UObject
{
	GENERATED_UCLASS_BODY()

    // Blueprint関数の定義
	UFUNCTION(BlueprintImplementableEvent, meta=(AutoCreateRefTerm="EventReference"))
	bool Received_Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference) const;

    void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
    {
        // Received_Notify関数が呼ばれている間だけWorlcContextが使えるようにする
        // MeshCompを一時的にメンバ変数に指定する事で、GetWorldでWorldをたどれるようにする
    	USkeletalMeshComponent* PrevContext = MeshContext;
    	MeshContext = MeshComp;
    	Received_Notify(MeshComp, Animation, EventReference);
    	MeshContext = PrevContext;
    }

    // ワールドコンテキストの実装
	virtual class UWorld* GetWorld() const override
    {
    	return (MeshContext ? MeshContext->GetWorld() : NULL);
    }

private:
    // 今アニメーションを実行しているSkeltalMeshコンポーネント
	class USkeletalMeshComponent* MeshContext;
};


2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?