C++ を使ってレベルをロード / アンロードする

C++ で作成したカスタム ストリーミング アクタでレベルをストリームする方法

Choose your operating system:

Windows

macOS

Linux

レベル ストリーミングのシナリオ

Sun Temple プロジェクトのメイン レベルから始めます。レベルを室内空間と、海が見える柱つきの中庭に分割します。 以下のワイヤーフレーム ビューでは、ティール色のワイヤーフレームがパーシスタント室内レベルを示し、黄色のワイヤーフレームがストリーミングされる中庭レベルを示します。 空と屋外が見えるように寺院の主要部にはいくつか窓があるので、空と海はパーシスタント レベルです。

LevelSplit.png

寺院の内装には、中庭を視界から隠す廊下を混ぜます。

StartLoading.png

プレイヤーが角を曲がって中庭に近づいてくる時にはストリーミング レベルがロードされて表示できるように、 ここで中庭レベルにストリーミングを開始します。

StreamingLevelVisible.png

設定対象は SunTemple_Persistent SunTemple_Streaming です。 Player Start SunTemple_Persistent にあります。 そしてゲームのプレイヤーは Character で表現されます。

  1. コンテンツ ブラウザ から SunTemple_Persistent を開きます。

  2. Player Start を寺院の一番手前に移動します。

    PlayerStart.png

  3. [Window] をクリックして、 [Level] を選択します。

    WindowLevels.png

  4. [Levels] のドロップダウン メニューをクリックし、 [Add Existing... (既存の...を追加)] を選択して新規サブレベルを追加します。

    AddExisting.png

  5. 追加する SunTemple_Streaming [Open Level] ダイアログで選択してから、 [Open] をクリックします。

    SunTempleStreaming_Select.png

  6. パーシスタント レベル 上で 右クリック して、ドロップダウン メニューから [Make Current] を選択します。

C++ を使ってレベルをストリーミングする

  1. コンテンツ ブラウザ を開いて、 [C++ Class] を新規作成します。このクラスは アクタ に基づくので、 アクタ を選択して [Next (次へ)] をクリックします。

  2. 作成された C++ Class に「LevelStreamerActor」と名前を付けて、 [Create Class (クラスを作成)] をクリックします。このクラスを Visual Studio または XCode で開くことができるようになります。

このシナリオの場合、 Character が OverlapVolume という Box コンポーネントをオーバーラップしたら、2 つ目のレベルをストリーミングします。

  1. LevelStreamerActor.h で、VisibleAnywhere、BlueprintReadOnly であり、AllowPrivateAccess メタ フラグをもつ OverlapVolume を宣言します。

    private:
    // Overlap volume to trigger level streaming
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
    UBoxComponent* OverlapVolume;
  2. LevelStreamerActor.cpp で、LevelStreamerActor コンストラクタの中に、OverlapVolume を作成して RootComponent にします。

    OverlapVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("OverlapVolume"));
    RootComponent = OverlapVolume;
  3. 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);
  4. LevelStreamerActor.h で、LevelToLoad を呼び出す EditAnywhere である protected の FName 変数も作成します。これにより、インスタンスごとに LevelToLoad を変更できるようになります。

    UPROPERTY(EditAnywhere)
    FName LevelToLoad;
  5. GameplayStatics ライブラリから幾つか関数を使用して、 LevelStreamerActor.cpp にこれが含まれるようにします。

    #include "Kismet/GameplayStatics.h"
  6. OverlapBegins 機能を作成する準備ができました。 LevelStreamerActor.cpp で、関数の定義を開始します。Index 0 でキャラクターを取得するために、GameplayStatics 関数 GetPlayerCharacter も使用できます。

    void OverlapBegins(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
    {
            ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);        
    }
  7. MyCharacter を取得したら、OtherActor が BoxComponent にオーバーラップしていることを確認します。さらに、LevelToLoad が空でないことを確認したら LoadStreamLevel を呼び出します。

    if (OtherActor == MyCharacter && LevelToLoad != "")
    {
        FLatentActionInfo LatentInfo;
        UGameplayStatics::LoadStreamLevel(this, LevelToLoad, true, true, LatentInfo);
    }
  8. 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);
            }
    }
  9. コードをコンパイルしたら、エディタに切り替えます。

  10. LevelStreamer ブループリントをレベル内に配置して、 Character にストリームを開始させたいパーシスタント ワールドの部分、 およびストリーミング レベルとなる歩行可能なボリューム全体を囲むように配置とスケールを調節します。

  11. Level to Stream として 「SunTemple_Streaming」 と入力します。

  12. ストリーミング レベルをテストするには、Play In Editor を使います。

C++ を使ってアンロードする

Character が BoxComponent からでる時にレベルをアンロードするには、 UGameplayStatics::UnloadStreamLevel を呼び出して OnComponentEndOverlap へ結合する OverlapEnds 関数を作成します。次のコード スニペットを
your 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);
Unreal Engine のドキュメントを改善するために協力をお願いします!どのような改善を望んでいるかご意見をお聞かせください。
調査に参加する
閉じる