使用C++加载和卸载关卡

如何使用在C++中创建的自定义流送Actor来流送关卡

Choose your operating system:

Windows

macOS

Linux

我们想在此处的露台关卡中开始流送,这样在玩家转过拐角并开始靠近露台时,流送中的关卡 就会加载好并可见。

StreamingLevelVisible.png

作为设置的一部分,我们有两个关卡:SunTemple_PersistentSunTemple_Streaming 。我们的 玩家出生点(Player Start) 位于 SunTemple_Persistent 中,我们的玩家在游戏中 由 角色 表示。

  1. 内容浏览器(Content Browser) 中打开 SunTemple_Persistent

  2. 玩家出生点(Player Start) 移至模板的最开头。

    PlayerStart.png

  3. 点击 窗口(Windows),然后选择 关卡(Levels)

  1. 点击 关卡(Levels) 下拉菜单,然后选择 添加现有...(Add Existing...) 以添加新的子关卡。

    AddExisting.png

  2. 选择 SunTemple_Streaming 以添加 打开关卡(Open Level) 对话框,然后点击 打开(Open)

    SunTempleStreaming_Select.png

  3. 右键点击 持久关卡(Persistent Level) ,并从下拉菜单选择 设为当前(Make Current)

使用C++在关卡中流送

  1. 打开 内容浏览器(Content Browser) 并创建新 C++类 。此类将基于 Actor ,因此选择 Actor 并点击 下一步(Next)

  2. 将新 C++类 命名为"LevelStreamerActor",然后点击 创建类(Create Class) 。该新类将在Visual Studio或XCode中打开。

对于这种情况,我们需要在 角色 与LevelStreamerActor中称为OverlapVolume的BoxComponent重叠时立即流送第二个关卡。

  1. LevelStreamerActor.h 中,声明一个具有VisibleAnywhere、BlueprintReadOnly属性且有AllowPrivateAccess meta标记的OverlapVolume。

    private:
    // 重叠体积以触发关卡流送
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
    UBoxComponent* OverlapVolume;

1.在 LevelStreamerActor.cpp 的LevelStreamerActor构造函数中,创建OverlapVolume并将其设为RootComponent。

    OverlapVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("OverlapVolume"));
    RootComponent = OverlapVolume;
  1. 回到 LevelStreamerActor.h 中,声明一个受保护OverlapBegins函数,它将绑定到BoxComponent的OnComponentBeginOverlap函数。此绑定意味着, OverlapBegins必须标记有UFUNCTION宏,并且必须拥有与OnComponentBeginOverlap相同的签名。

    protected:
    
    UFUNCTION()
    void OverlapBegins(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult);
  2. 同样在 LevelStreamerActor.h 中,创建一个EditAnywhere且名为LevelToLoad的受保护FName变量。这样一来,你就可以逐实例更改LevelToLoad。

    UPROPERTY(EditAnywhere)
    FName LevelToLoad;
  3. 我们将使用GameplayStatics库中的一些函数,因此请将其包含在 LevelStreamerActor.cpp 顶部。

    #include "Kismet/GameplayStatics.h"
  4. 现在你已准备好创建OverlapBegins功能。在 LevelStreamerActor.cpp 中,开始定义该函数。你可以使用GameplayStatics函数 GetPlayerCharacter 获取索引0处的角色。

    void ALevelStreamerActor::OverlapBegins(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
    {
            ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);        
    }
  5. 获取MyCharacter后,针对与BoxComponent重叠的OtherActor检查它。此外,验证LevelToLoad是否不为空,然后调用LoadStreamLevel。

    if (OtherActor == MyCharacter && LevelToLoad != "")
    {
        FLatentActionInfo LatentInfo;
        UGameplayStatics::LoadStreamLevel(this, LevelToLoad, true, true, LatentInfo);
    }
  6. 在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: 
        // 为此Actor的属性设置默认值
        ALevelStreamerActor();
    
        // 每一帧都调用
        virtual void Tick( float DeltaSeconds ) override;
    
    protected:
    
        // 当游戏开始或生成时调用
        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:
        // 重叠体积以触发关卡流送
        UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true"))
        UBoxComponent* OverlapVolume;
    
    };

    你的最终 LevelStreamerActor.cpp 应当如下所示:

    #include "Levels.h"
    #include "Kismet/GameplayStatics.h"
    #include "LevelStreamerActor.h"
    
    // 设置默认值
    ALevelStreamerActor::ALevelStreamerActor()
    {
        // 将此Actor设置为每帧调用更新函数()。  如果不需要此特性,可以关闭以提升性能。
        PrimaryActorTick.bCanEverTick = true;
    
        OverlapVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("OverlapVolume"));
        RootComponent = OverlapVolume;
    
        OverlapVolume->OnComponentBeginOverlap.AddUniqueDynamic(this, &ALevelStreamerActor::OverlapBegins);
    }
    // 当游戏开始或生成时调用
    void ALevelStreamerActor::BeginPlay()
    {
        Super::BeginPlay();
    
    }
    
    // 每一帧都调用
    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);
            }
    }
  7. 编译你的代码,然后切换回编辑器。

  8. LevelStreamer Actor放入关卡中,然后调整位置并缩放,直至它包含你希望 角色 位于其中才能开始流送的持久世界的一部分, 以及流送中的关卡将位于的整个可行走体积。

  9. 输入 *SunTemple_Streaming** 作为 **要流送的关卡** 。

  10. 使用在编辑器中运行(Play in Editor)来测试流送中的关卡。

使用C++卸载关卡

要在 角色 离开BoxComponent时卸载关卡,你需要创建 OverlapEnds 函数来调用 UGameplayStatics::UnloadStreamLevel 并将函数绑定到 OnComponentEndOverlap 。将以下代码片段添加到 你的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);