언어:
페이지 정보
태그:

C++ 로 레벨 로드 및 언로드

레벨 스트리밍 시나리오

Sun Temple (태양의 사원) 프로젝트의 메인 레벨로 시작해서 레벨을 둘로 나눕니다. 하나는 실내 공간, 다른 하나는 기둥과 바다가 보이는 파티오 공간입니다. 아래 와이어프레임 뷰에서, 청록 와이어프레임은 퍼시스턴트 실내 레벨, 노랑 와이어프레임은 스트림 인 예정인 파티오 레벨입니다. 하늘과 바다는 퍼시스턴트 레벨에 있는데, 메인 레벨인 사원에서도 하늘과 외부를 볼 수 있는 창이 몇 곤데 있기 때문입니다.

LevelSplit.png

사원 내부에는 굽은 통로가 있어 파티오 영역이 시야에서 가려집니다.

StartLoading.png

여기서부터 파티오 레벨을 스트림 인 시키고자 하는데, 플레이어가 코너를 돌아 파티오에 접근하기 시작하면, 스트리밍 레벨이 로드되어 보일 것입니다.

StreamingLevelVisible.png

구성의 일부로 레벨이 둘 있는데, SunTemple_PersistentSunTemple_Streaming 입니다. Player StartSunTemple_Persistent 에 있으며, 게임의 플레이어는 Character 로 표현되고 있습니다.

  1. SunTemple_Persistent콘텐츠 브라우저 에서 엽니다.

  2. Player Start 를 사원 시작 위치로 옮깁니다.

    PlayerStart.png

  3. - 레벨 을 클릭합니다.

    WindowLevels.png

  4. 레벨 드롭다운 메뉴에서 기존 추가... 를 선택하여 서브레벨을 새로 추가합니다.

    AddExisting.png

  5. SunTemple_Streaming 을 선택하여 레벨 열기 대화창에 추가한 뒤, 열기 를 클릭합니다.

    SunTempleStreaming_Select.png

  6. 퍼시스턴트 레벨우클릭 하고 드롭다운 메뉴에서 Make Current (현재로 만들기)를 선택합니다.

C++ 로 레벨 스트림 인

  1. 콘텐츠 브라우저 를 열고 C++ 클래스 를 새로 만듭니다. 이 클래스는 Actor (액터) 기반이 될테니, Actor 를 선택하고 다음 을 클릭합니다.

  2. C++ 클래스 이름을 LevelStreamerActor 라 하고 클래스 생성 을 클릭합니다. 그러면 새 클래스가 Visual Studio 또는 XCode 에 보일 것입니다.

여기서는 캐릭터 가 LevelStreamerActor 의 OverlapVolume 이라는 박스 컴포넌트에 겹치면 두 번째 레벨을 스트림 인 하도록 하고 싶습니다.

  1. LevelStreamerActor.h 에서 OverlapVolume (오버랩 볼륨)을 VisibleAnywhere (아무데서나 보이고), BlueprintReadOnly (블루프린트 읽기 전용이며), AllowPrivateAccess (프라이빗 접근 허용) 메타 플래그 설정합니다.

    private:
    // 레벨 스트리밍을 발동시킬 오버랩 볼륨
    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 에서, protected FName 변수를, EditAnywhere (아무데서나 편집가능)으로, LevelToLoad 라는 이름으로 생성합니다. 그러면 LevelToLoad 의 인스턴스 단위 변경이 가능해집니다.

    UPROPERTY(EditAnywhere)
    FName LevelToLoad;
  5. GameplayStatics 라이브러리의 함수를 몇 가지 사용할 것이므로, LevelStreamerActor.cpp 상단에 포함시켜 줍니다.

    #include "Kismet/GameplayStatics.h"
  6. 이제 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);        
    }
  7. MyCharacter 를 구한 뒤, BoxComponent 에 겹치는 OtherActor 에 대해 검사합니다. 또한, 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: 
        // 이 액터 프로퍼티에 대한 기본값을 설정합니다.
        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;
    
    };

    Your final LevelStreamerActor.cpp should look like:

    #include "Levels.h"
    #include "Kismet/GameplayStatics.h"
    #include "LevelStreamerActor.h"
    
    // 기본값을 설정합니다.
    ALevelStreamerActor::ALevelStreamerActor()
    {
        // 이 액터가 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);
            }
    }
  9. 코드를 컴파일한 다음, 에디터로 다시 돌아옵니다.

  10. 레벨에 LevelStreamer 액터를 배치하고, 캐릭터 가 들어서면 스트리밍을 시작하도록 할 퍼시스턴트 월드의 일정 부분을 덮도록 위치와 스케일을 조절합니다. 스트리밍 레벵에서 걸어다닐 수 있는 부분도 같이 정해줍니다.

  11. Level to Stream (스트리밍할 레벨)에는 SunTemple_Streaming 이라 입력합니다.

  12. 에디터에서 플레이 기능을 사용하여 스트리밍 레벨을 테스트합니다.

C++ 로 레벨 언로드

캐릭터가 박스 컴포넌트를 빠져나갈 때 레벨을 언로드하기 위해, 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);