Choose your operating system:
Windows
macOS
Linux
关卡流送
从 Sun Temple 项目中的主关卡开始。此关卡已被拆分为室内空间和面朝大海、拥有柱子的末端天井。在下方的线框图中,青色线框为固定的室内关卡,黄色线框为将被流入的天井。天空和海洋处于固定关卡中,主庙宇场景中有数个窗口,可看到天空和室外场景。
庙宇室内场景的走廊中有一个弯拐,遮挡了天井区域。
我们需要在此处开始流入天井。玩家转过弯拐靠近天井时,将加载并显示流送关卡。
设置拥有两个关卡, SunTemple_Persistent 和 SunTemple_Streaming 。 玩家出生点 位于 SunTemple_Persistent 中,游戏中的玩家由 角色 表示。
-
在 Content Browser 中打开 SunTemple_Persistent 。
-
将 玩家出生点 移至庙宇开端的位置。
-
点击 Windows ,然后选择 Levels 。
-
点击 Levels 下拉菜单,然后选择 Add Existing... 新增一个关卡分段。
-
选择 SunTemple_Streaming 加入 Open Level 对话,然后点击 Open 。
-
右键点击 Persistent Level ,从下拉菜单中选择 Make Current 。
使用 C++ 流入关卡
-
打开 Content Browser ,新建一个 C++ 类 。此类将基于 Actor ,因此选择 Actor 并点击 Next 。
-
将新建的 C++ 类 命名为"LevelStreamerActor",然后点击 Create Class 。新建类将在 VisualStudio 或 XCode 中打开。
在此情况下, 角色 在 LevelStreamerActor 中与名为 OverlapVolume 的方块组件重叠时需立即流入第二个关卡。
-
在
LevelStreamerActor.h
中,声明随处可见(VisibleAnywhere)、蓝图只读(BlueprintReadOnly),并拥有允许私有访问(AllowPrivateAccess)元标记的 OverlapVolume。private: // 重叠体积域触发关卡流送 UPROPERTY(VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) UBoxComponent* OverlapVolume;
-
在
LevelStreamerActor.cpp
里的 LevelStreamerActor 构造函数中创建 OverlapVolume 并将其设为根组件(RootComponent)。OverlapVolume = CreateDefaultSubobject<UBoxComponent>(TEXT("OverlapVolume")); RootComponent = OverlapVolume;
-
返回
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);
-
在
LevelStreamerActor.h
中创建一个名为 LevelToLoad 受保护的 FName 变量,属性为 EditAnywhere。它可以每个实例为基础变更 LevelToLoad。UPROPERTY(EditAnywhere) FName LevelToLoad;
-
我们将使用来自 GameplayStatics 库的几个函数,因此将其包含在
LevelStreamerActor.cpp
顶部。#include "Kismet/GameplayStatics.h"
-
现在即可开始创建 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); }
-
获得 MyCharacter 后,将其针对和 BoxComponent 发生重叠的 OtherActor 进行检查。并确认 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: // 设置该 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 设为每帧调用 Tick()。不需要时可将此关闭,以提高性能。 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); } }
-
编译代码,然后切回编辑器。
-
将 LevelStreamer Actor 放入关卡,调整其放置和大小,直到它将固定关卡中 角色 进入即开始流送的部分,以及流送关卡所在的整个可行走体积域包含在内。
-
将 SunTemple_Streaming 设为 流送关卡(Level to Stream) 。
-
使用 Play In Editor 测试流送关卡。
使用 C++ 卸载关卡
如要在
角色
退出 BoxComponent 时卸载关卡,需要创建一个调用
UGameplayStatics::UnloadStreamLevel
的
OverlapEnds
函数,并将其绑定到
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);