제대로 따라가기 (6) C++ 프로그래밍 튜토리얼 :: 일인칭 슈팅 C++ 튜토리얼 (1)

작성버전 :: 4.21.0

 


언리얼 엔진 튜토리얼인 일인칭 슈팅 C++ 튜토리얼에서는 C++ 코드 작업을 통해서 기본적인 일인칭 슈팅(FPS) 게임을 만드는 법을 배울 수 있다.

 

이번 튜토리얼은 각 하위 섹션들의 길이가 길어서 분할되어 작성된다.

 

튜토리얼대로 하면 문제가 발생해서 제대로 따라갈 수 없는 부분으로 동작이 가능하게 수정해야하는 부분은 빨간 블럭으로 표시되어 있다.


이번 튜토리얼에서 새로 배우게 되는 내용은 글 제일 끝에 "이번 섹션에서 배운 것"에 정리된다.

 

1. 프로젝트 구성

 

1-1. 프로젝트 구성(문서)

 

언리얼 엔진을 실행하고 프로젝트 브라우저에서 새 프로젝트 탭에서 C++탭을 선택한다.

 

기본 코드(Basic Code)를 선택하고 프로젝트 이름을 "FPSProject"[각주:1]로 입력한다. "시작용 콘텐츠 없음"으로 하여 프로젝트를 생성한다.

 

 

언리얼 에디터에서 프로젝트가 열리면, 플레이 버튼을 눌러서 에디터에서 플레이(PIE, Play In Editor) 모드로 들어가본다. WASD키를 이용해서 이동하거나 마우스를 이용해서 화면의 방향을 전환할 수 있다.

 

 

Esc키를 누르거나, 중지 버튼을 눌러서 PIE 모드를 빠져나간다.

 

 

레벨 탐험을 마쳤다면 Contents 폴더 안에 Maps 폴더를 생성한다.

 

 

파일 메뉴에서 현재 레벨을 다른 이름으로 저장... 을 선택하여 레벨을 Maps 폴더에 "FPSMap"으로 저장한다.

 

 

편집 메뉴에서 프로젝트 세팅을 클릭한다.

 

 

프로젝트 세팅 창에서 프로젝트 섹션의 맵 & 모드에 Editor Startup Map을 우리가 만든 FPSMap으로 설정해준다.

 

 

프로젝트 세팅 창을 닫고, 프로젝트를 저장한 뒤, 다음 단계로 이동하자.

 

 

1-2. Visual Studio에서 프로젝트 열기(문서)

 

Game Mode는 게임의 규칙과 승리 조건등을 정의하는 클래스로, 프로젝트를 구성할 때, 언리얼 엔진이 기본 Game Mode 클래스를 생성해주었다. 우리는 이 Game Mode에 기본 게임플레이 프레임워크 유형에 사용될 기본 클래스를, Pawn, PlayerController, HUD 등을 포함해서 설정할 계획이다. 이 파트에서는 에디터를 통해서 비주얼 스튜디오를 열고 거기서 프로젝트의 Game Mode 클래스를 확인해 볼 것이다.

 

언리얼 에디터의 파일 메뉴에서 Visual Studio 열기를 선택하여 비주얼 스튜디오를 연다.

 

 

비주얼 스튜디오가 열리면, 솔루션 탐색기를 통해서 프로젝트에 포함된 소스파일(.cpp)과 헤더파일(.h)가 보인다.

 

 

FPSProjectGameMode.cpp 안에 다음과 같은 코드가 있을 것이다.

 

#include "FPSProject.h"
#include "FPSProjectGameMode.h"

 

언리얼 엔진이 버전업 되면서 프로젝트에 자동 생성되는 Game Mode 클래스명 끝에 Base가 붙도록 변경되었다. 그래서 열어봐야할 소스파일의 이름은 "FPSProjectGameModeBase.cpp가 된다. 이것은 헤더파일에도 포함되는 것이다.

 

그리고 처음에 불필요한 빌드 및 컴파일 시간은 줄이기 위해서 기본적으로 필요한 헤더를 제외한 헤더의 포함을 최소화 하도록 변경되었기 때문에 FPSProjectGameModeBase.cpp 파일의 전처리기에 "FPSProject.h"가 포함되어 있지 않을 것이다. 그렇기 때문에 소스파일의 내용은 다음과 같을 것이다.

 

#include "FPSProjectGameModeBase.h"

 

다음 부분 부터는 FPSProjectGameModeBase를 기준으로 설명할 것이다.

 

FPSProjectGameModeBase.h 안에는 다음과 같은 코드가 있다.

 

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "FPSProjectGameModeBase.generated.h"

/**
 *
 */
UCLASS()
class FPSPROJECT_API AFPSProjectGameModeBase : public AGameModeBase
{
    GENERATED_BODY()
};

 

이제 프로젝트에 코드를 추가할 준비가 완료되었다.

 

 

 

 

1-3. 로그 메시징 추가(문서)

 

이 파트에서는 로그 메시지를 사용해서 언리얼 엔진에서 제공되는 기본 Game Mode가 아닌 FPSProjectGameModeBase가 실제로 사용되는지 점검해볼 것이다. 로그 메시지는 개발 도중 코드를 점검하고 디버깅하는데 쓰이는 유용한 도구이다.

 

FPSProjectGameModeBase.h의 클래스 선언 하단에 다음 함수 선언을 추가하자.

 

public:
    virtual void StartPlay() override;

 

그리고 FPSProjectGameModeBase.cpp로 가서 함수의 구현을 작성한다.

 

void AFPSProjectGameModeBase::StartPlay()
{
    Super::StartPlay();

    if (GEngine)
    {
        GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Hello World, this is FPSGameMode!"));
    }
}

 

이 부분에서는 GEngine이 정의되지 않았다는 문제가 발생할 것이다. 이 문제는 FPSProjectGameModeBase.cpp의 전처리기 파트에 "Engine.h"를 포함시켜주면 해결된다.

 

참고로 이 Engine 헤더는 덩치가 꽤나 큰 헤더기 때문에 필요할 때마다 이곳 저곳에서 포함시켜서 사용하는 것보다는 "FPSProject.h" 같은 헤더에 미리 선언해두고 이 "FPSProject.h"를 포함시켜서 사용하는 편이 좋을 수 있다.

 

#include "Engine.h"

 

코드 작성이 모두 끝났다면 변경사항들을 저장하고 에디터로 넘어간다.

 

 

1-4. 프로젝트 컴파일(문서)

 

이 파트에서는 프로젝트를 컴파일하여 코드 변경사항을 게임에 반영시켜볼 것이다.

 

에디터로 돌아왔다면, 컴파일 버튼을 클릭해서 코드를 컴파일한다.

 

 

플레이 버튼을 눌러서 PIE모드에 들어가서 화면에 로그가 뜨는지 확인해보자.

 

 

하지만 PIE 모드에 들어가도, 화면에 로그가 나타나지 않을 것이다. 그 이유는 아직 기본 Game Mode를 사용하고 우리가 만든 FPS Game Mode를 적용하지 않았기 때문이다.

 

그럼 이제, Esc를 눌러 PIE 모드를 중지하고 다음 단계로 넘어가자.

 

CPP Game Mode 클래스를 블루프린트로 확장

 

먼저, 콘텐트 브라우저의 콘텐츠 폴더 안에 Blueprints 폴더를 만든다.

 

 

C++클래스/FPSProject 폴더 안의 FPSGameModeBase 클래스를 우클릭해서 "FPSProjectGameModeBase 기반 블루프린트 클래스 생성"을 선택한다.

 

 

새 블루프린트 클래스의 이름을 BP_FPSProjectGameModeBase로 짓고, Blueprints 폴더를 선택한 뒤, 블루프린트 클래스 생성 버튼을 누른다.

 

 

새로 생성한 블루프린트 클래스가 Blueprints 폴더에 생긴 것을 볼 수 있다. 블루프린트를 저장하고 블루프린트 에디터를 닫자.

 

 

 

1-5. 디폴트 게임 모드 설정(문서)

 

새로 만든 게임 모드를 블루프린트로 확장시키는데 성공했으니, 이번 파트에서는 프로젝트가 FPSProjectGameModeBase를 기본 게임 모드로 사용하도록 설정해줘야 한다.

 

편집 메뉴에서 프로젝트 세팅창을 연다.

 

프로젝트 세팅 창이 열리면 프로젝트 섹션 아래의 맵 & 모드를 선택하고 Default GameMode 드롭다운에서 BP_FPSProjectGameModeBase를 선택한다.

 

 

프로젝트 세팅 메뉴를 닫고 레벨 에디터의 플레이 버튼을 클릭하면 뷰포트 좌상단 구성에서 "Hello World, this is FPSGameMode!" 라는 문구가 5초간 노란색으로 표시되는 것을 볼 수 있다.

 

 

 

 

이제 프로젝트 구성이 끝났다. 다음 섹션에서부터는 캐릭터를 구현하는 방법을 배우게 될 것이다.

 

 

 

 

 


 

이번 섹션에서 배운 것

 

1. AGameMode

 

StartPlay();

 

플레이가 시작되었을 때, 게임 모드에서 액터들의 BeginPlay() 함수를 호출하는 역할.

 

2. GEngine

 

GEngine;

 

전역에 선언되어 있는 엔진 포인터. 사용하기 위해서는 "Engine.h"를 포함해줘야 한다. 엔진에서 실행되는 경우가 아닐 경우, 값이 유효하지 않을 수 있으니 사용하기 전에 반드시 GEngine이 유효한 상태인지 체크하고 사용해야한다.

 

GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("Hello World, this is FPSGameMode!"));

 

뷰포트에 디버그 메시지를 띄우는데 사용되는 함수

 

3. FColor

 

FColor Color;

 

언리얼 엔진에서 색상으로 표현하는데 사용되는 구조체

 

FColor::Red;
FColor::Blue;
FColor::Green;
FColor::Black;
FColor::White;
FColor::Cyan;
FColor::Emerald;
FColor::Magenta;
FColor::Orange;
FColor::Purple;
FColor::Silver;
FColor::Transparent;
FColor::Turquoise;
FColor::Yellow;

 

언리얼 엔진에서는 기본적인 색상을 스태틱으로 미리 만들어서 사용자가 일일이 구조체를 생성해서 색상을 만들 필요가 없게 만들어 두었다.

 

 

  1. 다른 이름을 사용해도 상관없지만, 만약 다른 이름을 사용한다면 몇몇 코드 샘플에서의 이름이 달라질 것이다. [본문으로]
반응형
  1. 지나가던유니티 2020.03.10 04:09

    공식튜토리얼에서 이상하게 써놔서 어떻게할까 하다가 찾다보니 좋은정보를 알려주시는군요..감사합니다 .

    • wergia 2020.03.11 10:58 신고

      언리얼 튜토리얼은 그래서 진입장벽이 있습니다

  2. junseolim 2021.01.17 21:41 신고

    좋은 글 감사합니다!

  3. gyut 2021.05.24 23:22

    좋은 글 감사합니다. 언리얼 처음 시작하는데 큰 도움이 되는 시리즈네요. 열심히 하겠습니다~

제대로 따라가기 (5) C++ 프로그래밍 튜토리얼 :: UMG와 유저 인터페이스

 


작성버전 :: 4.21.0

언리얼 엔진 튜토리얼인 UMG와 유저 인터페이스에서는 언리얼 모션 그래픽(UMG)을 사용해서 여러가지 화면과 버튼이 있는 기본적인 메뉴 시스템을 만드는 법을 배울 수 있다.

 

튜토리얼대로 하면 문제가 발생해서 제대로 따라갈 수 없는 부분으로 동작이 가능하게 수정해야하는 부분은 빨간 블럭으로 표시되어 있다.


이번 튜토리얼에서 새로 배우게 되는 내용은 글 제일 끝에 "이번 섹션에서 배운 것"에 정리된다.

 

 

1. UMG용 모듈 종속성 구성(문서)

 

C++탭에서 기본 코드를 선택하고 "HowTo_UMG"라는 이름으로 프로젝트를 새로 생성한다.

 

 

언리얼 모션 그래픽(UMG)을 사용하는 코드를 작성할 것이기 때문에 비주얼 스튜디오(Visual Studio)에 들어가서 기본으로 포함되어 있지 않은 몇 가지 모듈을 포함시키도록 하자.

 

언리얼 에디터의 파일 드롭다운 메뉴에서 Visual Studio 열기를 선택해서 비주얼 스튜디오를 연다.

 

 

UMG는 몇 가지 모듈에 종속되어 있는데, 그 모듈을 "HowTo_UMG.Build.cs"에 추가해야 한다.

 

 

"HowTo_UMG.Build.CS"에서 포함된 퍼블릭 모듈 목록에 "UMG"를, 포함된 프라이빗 모듈 목록에 "Slate" 와 "SlateCore" 를 추가해야 한다.

 

PublicDependencyModuleNames에 UMG를 다음과 같이 추가한다.

 

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG" });

 

비어있는 PrivateDependencyModuleNams를 주석 처리하고 "Slate"와 "SlateCore"가 있는 부분을 주석 해제 한다.

 

//PrivateDependencyModuleNames.AddRange(new string[] {  });

// Uncomment if you are using Slate UI
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });

 

UMG 구성이 완료되었다면, 프로젝트의 커스텀 게임 모드에 코드를 추가하여 게임 메뉴를 만들고 표시할 수 있다.

 

 

2. 게임 모드 확장(문서)

 

게임이 시작되면 유저 위젯(User Widget)을 새로 만들어 표시하거나, 나중에 제거할 수 있도록 하기 위해서 Game Mode(게임 모드) 클래스에 함수와 프로퍼티를 추가하자. 각 프로젝트에는 커스텀 게임 모드 클래스가 딸려오므로, HowTo_UMGGameMode.h에 다음 코드를 추가하면 된다.

 

버전이 바뀌면서 GameMode 클래스 파일의 이름이 "ProjectNameGameMode.h", "ProjectNameGameMode.cpp"에서 "ProjectNameGameModeBase.h", "ProjectNameGameModeBase.cpp"로 바뀌었다. 비주얼 스튜디오의 솔루션 탐색기에서 HowTo_UMGGameModeBase.h를 열어서 작업하자.

 

public:
    UFUNCTION(BlueprintCallable, Category = "UMG_Game")
    void ChangeMenuWidget(TSubclassOf NewWidgetClass);

protected:
    virtual void BeginPlay() override;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UMG_Game")
    TSubclassOf StartingWidgetClass;

    UPROPERTY()
    UUserWidget* CurrentWidget;

 

TSubclassOf 클래스를 사용할 때, [클래스 템플릿 "TSubclassOf"에 대한 인수 목록이 없다]는 에러가 발생한다. 전체 코드를 보고 유추해보건데, BeginPlay() 함수에서 StartingWidgetClass의 내용물을 CurrentWidget 변수에 넣어주거나 ChangeMenuWidget() 함수가 동작할 때, 매개변수로 받은 NewWidgetClass를 CurrentWidget에 대입해주는 방식으로 동작할 것임을 알 수 있다. 그렇기 때문에 여기에서는 TSubclassOf의 템플릿 인수로 UUserWidget 타입을 넣어주는 것이 올바른 해결책일 것이다.

 

다음과 같이 코드를 수정해주자.

 

public:
    UFUNCTION(BlueprintCallable, Category = "UMG_Game")
    void ChangeMenuWidget(TSubclassOf<UUserWidget> NewWidgetClass);

protected:
    virtual void BeginPlay() override;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UMG_Game")
    TSubclassOf<UUserWidget> StartingWidgetClass;

 

이제 HowTo_UMGGameModeBase.cpp로 가서, 선언한 두 함수의 구현을 해야 한다. 우선 BeginPlay()를 덮어쓰는 것으로 시작하자.

 

void AHowTo_UMGGameModeBase::BeginPlay()
{
    Super::BeginPlay();
    ChangeMenuWidget(StartingWidgetClass);
}

 

부모 클래스의 함수를 덮어쓸 때는, 여기 BeginPlay에서 하듯이 해당 함수의 부모 클래스 버전을 호줄하는 것이 중요한 경우가 많다. 우리가 구현하는 함수의 버전은 기존의 절차의 끝 부분에 한 단계를 추가하기 위한 것이므로, 함수 첫 줄에 Super::BeginPlay()를 호출한다.

 

그리고 여기서는 UUserWidget을 사용하기 위해서, HowTo_UMGGameModeBase.cpp 상단에 "Blueprint/UserWidget.h"를 포함시켜 주어야 한다.

 

#include "Blueprint/UserWidget.h"

 

계속 해서, 메뉴 간의 전환 방식을 구현해야 한다. 뷰포트에 활성화된 유저 위젯이 있다면 제거하고 난 다음에 유저 위젯을 새로 만들어 뷰포트에 추가해주도록 구현한다.

 

void AHowTo_UMGGameModeBase::ChangeMenuWidget(TSubclassOf NewWidgetClass)
{
    if (CurrentWidget != nullptr)
    {
        CurrentWidget->RemoveFromViewport();
        CurrentWidget = nullptr;
    }

    if (NewWidgetClass != nullptr)
    {
        CurrentWidget = CreateWidget(GetWorld(), NewWidgetClass);
        if (CurrentWidget != nullptr)
        {
            CurrentWidget->AddToViewport();
        }
    }
}

 

함수 구현할 때도, 변경된 선언에 맞춰서 매개변수 타입을 아래와 같이 수정하자.

 

void AHowTo_UMGGameModeBase::ChangeMenuWidget(TSubclassOf<UUserWidget> NewWidgetClass)

 

이 코드는 제공된 위젯 인스턴스를 만들어 화면에 넣는다. 언리얼 엔진은 한 번에 다수의 위젯을 표시하고 상호작용처리가 가능하며, 한 번에 하나만 활성화 되도록 제거를 할 수도 있다. 하지만 위젯을 직접 소멸시킬 필요는 없는데, 뷰포트에서의 제거 밑 레퍼런싱하는 모든 변수 소거(또는 변경) 작업은 언리얼 엔진의 가비지 컬렉션 시스템에서 해주기 때문이다.

 

마지막으로 Player Controller 클래스에 입력 모드를 설정해야 한다. 그러기 위해서 Player Controller를 기반으로 새로운 C++ 클래스를 추가하자. 이 클래스 안해서 게임이 시작될 때 함수 하나를 추가로 호출해주기만 하면 UI 요소와 상호작용이 가능하도록 할 수 있다.

 

 

 

HowTo_UMGPlayerController.h에서 클래스에 다음 오버라이드를 추가하고 .cpp에 구현한다.

 

public:
    virtual void BeginPlay() override;

 

void AHowTo_UMGPlayerController::BeginPlay()
{
    Super::BeginPlay();
    SetInputMode(FInputModeGameAndUI());
}

 

메뉴 생성 및 표시와 필요없어진 메뉴를 제거하기 위한 코드 프레임워크를 완성했다. 이제 언리얼 에디터로 돌아가 메뉴 에셋을 디자인 해보자.

 

 

 

 

3. 메뉴 위젯 블루프린트 생성(문서)

 

언리얼 에디터에서 컴파일 버튼을 누르면 수정된 코드가 빌드된다. 이를 통해서 유저 위젯을 메뉴로 사용할수 있게 된다.

 

 

이제 게임 모드가 메뉴로 사용할 유저 위젯을 생성해보자. 콘텐츠 브라우저의 "신규 추가" 버튼을 누르고 유저 인터페이스 카테고리에서 위젯 블루프린트(Widget Blueprint) 클래스를 선택해서, "MainMenu"와 "NewGameMenu"라는 이름으로 두 개의 유저 위젯을 만든다.

 

 

방금 만든 "MainMenu" 위젯을 더블클릭하면 블루프린트 디자이너 창이 열리며, 여기서 메뉴 레이아웃을 만들 수 있다.

 

팔레트 패널의 일반 섹션에서 버튼(Button)과 텍스트(Text)를 끌어 그래프에 배치한다. 이 버튼은 새 게임 메뉴를 여는데 사용될 것이다.

 

 

버튼의 위치와 크기를 다음과 같이 수정하고, 함수성 연결을 해줄 때 알아보기 쉽게 하기 위해서 이름을 "NewGameButton"으로 변경한다.

 

 

그리고 이 버튼이 무슨 버튼인지 보여주기 위해서 텍스트 블록(Text Block)을 버튼 위로 끌어다 놓고 디테일을 다음과 같이 수정한다.

 

- Text를 "New Game"으로 변경

 

- Visibility를 Hit Test Visibility로 변경한다. 그러면 버튼을 누르려는 클릭을 텍스트 블록이 막지 않는다.

 

- 이름을 "NewGameText"로 변경한다. 필수는 아니지만 나중에 계층구조에서 어떤 UI인지 찾기 쉬워지기 때문에 들여두면 좋은 습관이 된다.

 

 

 

두 번째 버튼과 텍스트 블록을 만들어서 "Quit"(종료) 기능을 만든다. 버튼 이름은 "QuitButton", 버튼 위치는 (600, 100), 텍스트 블록 이름은 "QuitText"로 설정한다.

 

그 다음은, 버튼을 클릭했을 때, 코드가 실행되도록 버튼에 이벤트를 추가하는 작업을 해야한다. 디테일 패널에서 적합한 이벤트의 이름 옆에 "+"버튼을 찾아서 누르면 되는데 이 경우에는 "OnClicked" 이벤트를 추가하면 된다.

 

 

NewGameButton의 OnClicked 이벤트를 다음과 같이 구성한다.

 

 

QuitButton의 OnClicked 이벤트를 다음과 같이 구성한다.

 

 

 

메인 메뉴를 만들었으니, 레벨이 시작되면 메인 메뉴를 로드하는 게임 모드 애셋을 구성하면 된다.

 

 

4. 게임 모드 환경설정(문서)

 

콘텐츠 브라우저에서 프로젝트의 게임 모드에 맞는 블루프린트 클래스를 두 개 추가할 것이다. 그러면 그 두 클래스에 노출된 변수를 원하는 값으로 설정하는 것이 가능하다.

 

콘텐츠 브라우저에서 신규 추가버튼에서 블루프린트 클래스를 클릭한다.

 

 

부모 클래스로 HowTo_UMGGameModeBase를 선택해서 "MenuGameMode" 블루프린트 클래스를 만든다.

 

 

그리고 게임 내에서 마우스 커서를 보이게 하기 위해서, 플레이어 컨트롤러의 블루프린트 클래스도 만들어 주어야 한다. 콘텐츠 브라우저에서 블루프린트 클래스를 클릭하고 Player Controller 클래스 상속받아서 "MenuPlayerController"라는 이름으로 클래스를 생성하자.

 

"MenuPlayerController" 클래스가 생성되었으면, 콘텐츠 브라우저에서 블루프린트 파일을 더블클릭해서 블루프린트 에디터를 연다. 그리고 디테일 창에서 "Show Mouse Cursor" 박스를 체크한다.

 

 

다음은 "MenuGameMode"를 편집한다.

 

Starting Widget Class를 "MainMenu" 애셋으로 설정해서 게임 시작시 메뉴가 뜨도록 만든다.

 

Default Pawn Class를 Default Pawn이 아닌 Pawn으로 설정해서 플레이어가 메뉴에 있을 때, 이리저리 날아다니지 않도록 만든다.

 

Player Controller Class를 방금 만든 "MenuPlayerController" 애셋으로 설정해서 메인 메뉴에서 마우스 커서가 표시되도록 만든다.

 

 

우리가 만든 게임 모드 블루프린트를 사용하려면, 레벨 에디터 창으로 돌아와 세팅 버튼을 통해 현재 레벨에 대한 월드 세팅을 변경해야 한다.

 

 

프로젝트 세팅 메뉴의 맵 & 모드에서도 기본 게임 모드 설정이 가능하다. 이 방법을 사용하면 따로 덮어쓰지 않는 한 모든 레벨에서 기본 게임 모드로 설정된다. 어느 방법을 사용할지는 프로젝트 구성에 따라 달라질 수 있다.

 

월드 세팅 패널에서 Game Mode Override 항목을 "MenuGameMode" 애셋으로 설정한다.

 

 

이제 레벨에 메인 메뉴를 로드하고, 마우스 커서를 표시하는 플레이어 컨트롤러를 사용하도록 환경설정된 커스텀 게임 모드 애셋이 적용되었다. 이제 게임을 실행하면 Quit 버튼은 정상적으로 작동하지만, 아직 New Game 버튼은 빈 메뉴 화면으로 이동한다. 다음 단계에서는 New Game Menu를 구성해주자.

 

 

 

 

5. 2차 메뉴 제작(문서)

 

콘텐츠 브라우저에서 아까 만든 "NewGameMenu" 애셋을 연다. 이 메뉴는 이름을 입력할 수 있는 텍스트 박스와, 이름을 입력하기 전에는 누를 수 없는 '게임 플레이' 버튼, 메인 메뉴로 돌아가는 버튼으로 구성된다.

 

이름 입력 박스를 만들기 위해, 레이아웃에 Text Box(텍스트 박스)를 배치한다.

 

 

텍스트 박스의 설정은 다음과 같다.

 

 

이전 메뉴에서 버튼을 만들었던 것과 같은 방식으로 텍스트 블록 라벨이 있는 게임 플레이 버튼을 만든다.

 

버튼 : 이름은 PlayGameButton, 위치는 200, 300, 크기는 200, 100으로 변경한다.

 

텍스트 블록 : 이름은 PlayGameText, Visibility는 Hit Test Visible로, 내용은 Play Game으로 변경한 다음 PlayGameButton위에 배치한다.

 

게임 플레이 버튼의 경우, 만약 플레이어 이름 입력란이 비어있다면 작동하지 않도록 특수한 기능을 추가한다. UMG의 바인드 기능을 사용하여 (Behavior섹션 아래) "Is Enabled" 칸에 새로운 함수를 만들면 된다.

 

 

텍스트 박스가 공백이 아니어서 버튼이 활성화 될 수 있는 상태인지 확인하려면, 텍스트 박스에서의 텍스트를 스트링으로 변환한 다음 길이가 0보다 큰지 검사하면 된다.

 

 

이제 메인 메뉴로 돌아갈 수 있도록 버튼을 하나 추가해보자. 메인 메뉴에서 게임 플레이 버튼과 비슷하지만, 위치 기준이 좌상단이 아닌 우하단 구석이 될 것이다. 그러기 위해서는 디테일 패널에서 "앵커" 드롭다운을 클릭한 다음, 팝업 메뉴에서 우하단 부분을 나타내는 모양을 선택한다.

 

버튼 이름을 MainMenuButton으로 설정한다.

 

위치를 -400, -200으로 설정한다.

 

크기를 200x100으로 설정한다.

 

 

이제 NewGameMenu 위젯의 버튼들에도 OnClicked 이벤트들을 추가하자

 

 

메인 메뉴 버튼의 경우, 다시 메인 메뉴 위젯을 열어주지만, 게임 플레이 버튼은 누르면 메뉴를 비활성시킨 후, 게임에서 더 이상 아무것도 할 수 없게 만든다. 보통 이 시점에서 첫 레벨을 로드하고, 오프닝 동영상을 재상하거나 폰을 스폰시켜 빙의하는 등의 처리를 하게 된다.

 

모든 작업을 마치고 플레이 해보면 다음 스크린샷과 같은 장면을 얻을 수 있다.

 

 

 

 


 

이번 섹션에서 배운 것

 

1. 언리얼 모듈 종속성

언리얼 엔진의 기능은 다수의 모듈로 나누어져 있고, 그 중에 필요한 모듈을 묶어서 사용하는 방식이다. 이번 섹션 처음 부분에 build.cs파일에서 모듈 종속성을 구성할 때도 보았겠지만, 기본적으로 언리얼은 Core, CoreUObject, Engine, InputCore 모듈을 사용하고 있었고, UI와 관련된 기능을 사용하기 위해서 UMG 모듈과 Slate, SlateCore 모듈을 구성에 추가해주었다.

 

추후의 일이지만, 언리얼 엔진을 커스터마이징하고자 할 때, 새롭게 추가하는 기능을 이러한 모듈로 만들어 덧붙이게 될 것이다.

 

2. TSubClassOf<T>

UClass 타입 안정성을 보장하는 템플릿 클래스. TSubClassOf에 전달된 인수가 템플릿 인자로 받은 타입과 일치하거나 템플릿 인자로 받은 타입을 상속받은 타입인지를 런타임 중에 확인하도록 도와주는 클래스이다.

 
3. UUserWidget
UUserWidget* UserWidget;

Widget Blueprint를 통해서 확장할 수 있는 사용자 위젯.

UserWidget->AddToViewport();

유저 위젯을 뷰 포트에 추가하는 함수.

UserWidget->RemoveToViewport();

유저 위젯을 뷰 포트에서 제거하는 함수.

 

4. AActor::GetWorld()

GetWorld();

UWorld 객체를 가져오는 함수. UWorld는 액터나 컴포넌트들을 포함하는 맵이나 샌드박스의 최상위 객체이다.

 

5. CreateWidget()

CreateWidget(GetWorld(), newWidget);

위젯을 생성하는 함수

 

6. APlayerController::SetInputMode()

SetInputMode(FInputModeGameAndUI());

플레이어 컨트롤러의 입력 모드를 설정하는 함수. Game 입력만 받을지, UI 입력만 받을지, 아니면 둘 다 받을지를 정할 수 있다.

 

7. UPROPERTY()

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UMG_Game")

클래스의 멤버 변수에 붙이는 매크로. 에디터의 노출 수준을 정할 수 있다.

 

EditAnywhere는 에디터 디테일 패널에 노출이 가능하다.

 

BlueprintReadOnly는 블루프린트에서 수정을 불가능하고 읽기만 가능하다.

 

Category는 블루프린트에서 불러올 때, 카테고리를 분류해서 찾기 쉽게 만들어준다.

 

8. UFUNCTION()

UFUNCTION(BlueprintCallable, Category = "UMG_Game")

함수에 붙이는 매크로.

 

BlueprintCallable은 블루프린트에서 호출만 가능하다는 의미이다.

반응형
  1. 흑흑 2020.03.12 20:22

    덕분에 잘 배워갑니다.
    댓글 하나 남기면
    TSubClassOf<UUserWidget> StartingWidgetClass;
    여기에서 TSubclassOf 인데 class 가 Class로 오타가 나있어서 저대로 하면 컴파일이 안돼요
    혹시 저같은 초보자분 계시면 똑같이 헤멜까봐 남겨요

    • wergia 2020.03.12 20:30 신고

      앗...아 감사합니다. 얼른 수정했습니다!

  2. rickey 2020.07.02 14:15

    마지막 정리쪽에

    5. CreateWidge() 이라고 되어있는데 t가 빠진거 같아요

    • wergia 2020.07.13 11:33 신고

      정말 그렇네요! 오타 제보 감사드립니다 ㅎㅎ
      수정했습니다

+ Recent posts