プレイヤーが角を曲がって中庭に近づいてくる時にはストリーミング レベルがロードされて表示できるように、 ここで中庭レベルにストリーミングを開始します。
設定対象は SunTemple_Persistent と SunTemple_Streaming です。Player Start は SunTemple_Persistent にあります。 そしてゲームのプレイヤーは Character で表現されます。
コンテンツ ブラウザ から SunTemple_Persistent を開きます。
Player Start を寺院の一番手前に移動します。
[Window] をクリックして、[Level] を選択します。
[Levels] のドロップダウン メニューをクリックし、[Add Existing... (既存の...を追加)] を選択して新規サブレベルを追加します。
追加する SunTemple_Streaming を [Open Level] ダイアログで選択してから、[Open] をクリックします。
パーシスタント レベル 上で 右クリック して、ドロップダウン メニューから [Make Current] を選択します。
C++ を使ってレベルをストリーミングする
コンテンツ ブラウザ を開いて、[C++ Class] を新規作成します。このクラスは アクタ に基づくので、アクタ を選択して [Next (次へ)] をクリックします。
作成された C++ Class に「LevelStreamerActor」と名前を付けて、[Create Class (クラスを作成)] をクリックします。このクラスを Visual Studio または XCode で開くことができるようになります。
このシナリオの場合、Character が OverlapVolume という Box コンポーネントをオーバーラップしたら、2 つ目のレベルをストリーミングします。
LevelStreamerActor.h
で、VisibleAnywhere、BlueprintReadOnly であり、AllowPrivateAccess メタ フラグをもつ OverlapVolume を宣言します。private: // Overlap volume to trigger level streaming UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) UBoxComponent* OverlapVolume;
LevelStreamerActor.cpp
で、LevelStreamerActor コンストラクタの中に、OverlapVolume を作成して RootComponent にします。OverlapVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("OverlapVolume")); RootComponent = OverlapVolume;
LevelStreamerActor.h
に戻って、protected の OverlapBegins 関数を宣言すると、BoxComponent の OnComponentBeginOverlap 関数に結合します。つまり、OverlapBegins は UFUNCTION マクロでタグ付けされなければならず、OnComponentBeginOverlap と同じシグネチャを持たなければならないという意味です。protected: UFUNCTION() void OverlapBegins(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
LevelStreamerActor.h
で、LevelToLoad を呼び出す EditAnywhere である protected の FName 変数も作成します。これにより、インスタンスごとに LevelToLoad を変更できるようになります。UPROPERTY(EditAnywhere) FName LevelToLoad;
GameplayStatics ライブラリから幾つか関数を使用して、
LevelStreamerActor.cpp
にこれが含まれるようにします。#include "Kismet/GameplayStatics.h"
OverlapBegins 機能を作成する準備ができました。
LevelStreamerActor.cpp
で、関数の定義を開始します。Index 0 でキャラクターを取得するために、GameplayStatics 関数GetPlayerCharacter
も使用できます。void ALevelStreamerActor::OverlapBegins(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult) { ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0); }
MyCharacter を取得したら、OtherActor が BoxComponent にオーバーラップしていることを確認します。さらに、LevelToLoad が空でないことを確認したら LoadStreamLevel を呼び出します。
if (OtherActor == MyCharacter && LevelToLoad != "") { FLatentActionInfo LatentInfo; UGameplayStatics::LoadStreamLevel(this, LevelToLoad, true, true, LatentInfo); }
LevelStreamerActor コンストラクタ で OverlapBegins を BoxComponent の OnComponentBeginOverlap に結合します。
OverlapVolume->OnComponentBeginOverlap.AddUniqueDynamic(this, &ALevelStreamerActor::OverlapBegins);
LevelStreamerActor.h
は最終的にこのようになります。#pragma once #include "GameFramework/Actor.h" #include "LevelStreamerActor.generated.h" UCLASS() class LEVELS_API ALevelStreamerActor : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties ALevelStreamerActor(); // Called every frame virtual void Tick( float DeltaSeconds ) override; protected: // Called when the game starts or when spawned virtual void BeginPlay() override; UFUNCTION() void OverlapBegins(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult); UPROPERTY(EditAnywhere) FName LevelToLoad; private: // Overlap volume to trigger level streaming UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) UBoxComponent* OverlapVolume; };
LevelStreamerActor.cpp
は最終的にこのようになります。#include "Levels.h" #include "Kismet/GameplayStatics.h" #include "LevelStreamerActor.h" // Sets default values ALevelStreamerActor::ALevelStreamerActor() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; OverlapVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("OverlapVolume")); RootComponent = OverlapVolume; OverlapVolume->OnComponentBeginOverlap.AddUniqueDynamic(this, &ALevelStreamerActor::OverlapBegins); } // Called when the game starts or when spawned void ALevelStreamerActor::BeginPlay() { Super::BeginPlay(); } // Called every frame void ALevelStreamerActor::Tick( float DeltaTime ) { Super::Tick( DeltaTime ); } void ALevelStreamerActor::OverlapBegins(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult) { ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0); if (OtherActor == MyCharacter && LevelToLoad != "") { FLatentActionInfo LatentInfo; UGameplayStatics::LoadStreamLevel(this, LevelToLoad, true, true, LatentInfo); } }
コードをコンパイルしたら、エディタに切り替えます。
LevelStreamer ブループリントをレベル内に配置して、Character にストリームを開始させたいパーシスタント ワールドの部分、 およびストリーミング レベルとなる歩行可能なボリューム全体を囲むように配置とスケールを調節します。
Level to Stream として 「SunTemple_Streaming」 と入力します。
ストリーミング レベルをテストするには、Play In Editor を使います。
C++ を使ってアンロードする
Character が BoxComponent からでる時にレベルをアンロードするには、UGameplayStatics::UnloadStreamLevel
を呼び出して OnComponentEndOverlap
へ結合する OverlapEnds
関数を作成します。次のコード スニペットを
LevelStreamerActor: に追加します。
LevelStreamerActor.h への追加:
UFUNCTION()
void OverlapEnds(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
LevelStreamerActor.cpp への追加:
void ALevelStreamerActor::OverlapEnds(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);
if (OtherActor == MyCharacter && LevelToLoad != "")
{
FLatentActionInfo LatentInfo;
UGameplayStatics::UnloadStreamLevel(this, LevelToLoad, LatentInfo);
}
}
コンストラクタへの追加:
OverlapVolume->OnComponentEndOverlap.AddUniqueDynamic(this, &ALevelStreamerActor::OverlapEnds);