본문 바로가기

Unreal Engine 4/C++

<Unreal C++> 70 - Action RPG (UserWidget(무기선택))

 

 

필요한 개념


<무기 선택 UI>
메뉴를 클릭하면 전체적으로 게임이 느려지면서 UI창이 나옴, 아이템, 인벤토리 작업을 함
우리도 이런방식으로 UserWidget을 만들고, Ctrl키를 누르면 무기선택이 나옴, 마우스 클릭하면 무기 선택되서 교체됨

- ItemWidget을 만들고 Item을 깔아주는 List를 만듬
-> 마우스로 버튼을 클릭해서 선택하는 작업

* UserWidget을 상속받는 CUserWidget_ActionItem 클래스 생성
아이템이 보여지고 선택할 수 있는 위젯

* WB_ActionItem 생성

 


- CUserWidget_ActionItem으로 부모변경 

 

 

* WB_ActionItem

 


DesiredOnScreen으로 실제 사이즈로 본다.
SizeBox : 사이즈를 조정하면 하위 것들도 전부 사이즈가 조절됨
Border를 추가하고, Border는 변수로 체크한다.
Overlay(오버레이) : 여러개의 이미지를 겹쳐서 올릴 수 있음
Image로 Background 해주고
클릭할 수 있도록 Button 하나 추가한다.(버튼 이미지는 아이템 이미지가 된다.)

 

* Button의 속성

 


* Button의 Style 설명
Normal : 평소 상태
Hoverd : 마우스가 올라갔을 때 상태
Pressed : 마우스로 클릭했을 때 상태
Disabled : 선택할 수 없을 때

* 중요
Button의  디테일->개입->IsFocusable 해제 필수
ImageButton의 Focusable을 해제해야 함
이렇게 해제함으로써 ActionList쪽에서 포커스를 받도록 처리해줘야 ActionList쪽의 클릭이 정상적으로 이루어짐
(반면, ActionList쪽에는 포커스를 활성화 시킴)

각 이미지를 정해준다.

*&nbsp;Button의 속성


DrawAs에는 Image로 설정해줘야 정상적인 텍스쳐 렌더링이 가능
똑같은 아이템 이미지를 설정해주고 Tint의 Alpha값을 조절해 누르거나, 올라갔을때의 느낌을 주면 된다.
ex) Noraml Tint Alpha : 0.5, Hoverd Tint Alpha : 0.75, Pressed Tint Alpha : 1.0을 주면 효과가 보인다.


이벤트 그래프에서 Button의 이벤트를 보면
On Clicked(눌렀다 떼었을때), On Pressed(누름 상태), On Released(키를 떼었을때), On Hoverd(마우스를 올려놓았을 때), On Unhorverd(영역을 벗어났을 때)가 있다.
이런것들을 CUserWidget_ActionItem에서 정의해줌

 

* CUserWidget_CActionItem에 추가

// Implement로 안하는 이유는 이미 거기에 정의되어있는 것을 호출만 해줄 거기때문에
// 그냥 BlueprintCallable(블루프린트에서 콜 가능하도록) 세팅
protected:
	UFUNCTION(BlueprintCallable)
		void Click();
	
	UFUNCTION(BlueprintCallable)
		void Hover();

	UFUNCTION(BlueprintCallable)
		void Unhover();



WB_ActionItem 이벤트 그래프를 보면 Button에서
OnClicked에서는 Click() 호출
OnHover에서는 Hover() 호출
OnUnhover에서는 Unhover() 호출
이렇게 해주면 CUserWidget_CActionItem에 있는 내용이 호출됨

 

* 부모(CUserWidget_CActionItem)의 함수들을 눌렀을 때 콜해줌

* WB_ActionItem 이벤트 그래프



아이템을 선택하는 리스트를 만든다.

* UserWidget을 상속받는 CUserWidget_ActionList 클래스 생성


* WB_ActionList 생성

- 부모 CUserWidget_ActionList로 변경

 

* WB_ActionList


- List 이용해서 그리드를 써봄

- 화면에 1대 1로 설정할 꺼여서 CanvasPanel 유지
- Overlay, Border 추가

Tip) 
오버레이를 이용해서 FHD 해상도(1920x1080)로 크기를 맞춰준다.
뷰포트 게임 플레이에서는 화면 사이즈가 다르므로
정상적으로 채워지지 않을 가능성이 높다.
독립형이나 게임 빌드 결과로 보면 정상적으로 잘 나옴

 

- Grid를 깔기 위해 GridPanel 추가

 

* Grid 속성


나중에 리스트로 얻어와야 하니까 GridPanel은 변수로 체크
가운데 정렬 시키고, Fill Rules에서 행 2개 열 3개로 만듬
열, 행 안에 숫자는 여백을 조정하는 값이다.

 


우리가 만든 WB_ActionItem을 그리드 밑으로 추가시켜준다.
그러면 Grid에 추가됨
각 Item에 Row(행), Column(열)을 조절해서 그리드를 만들어준다.

총 2행 3열이 만들어짐

* Grid에 있는 애들을 다 찾아와서 이미지 연결을 해줄 것이다.
이벤트그래프의 Construct 이벤트에 세팅
이미지 텍스쳐 배열을 만들어서 각 텍스쳐를 세팅하고 그리드의 인덱스마다 해당 텍스쳐를 Normal, Hoverd, Pressed Texture에 세팅한다.

 

* WB_ActionList 이벤트 그래프


* 프로젝트 세팅 -> 입력 -> 위젯 띄우기 위한 액션 매핑 키 세팅
ViewActionList, 왼쪽 Ctrl


* CPlayer에서 위젯 생성

private:
	// 액션 리스트 클래스 세팅가능하도록 설정
	UPROPERTY(EditDefaultsOnly)
		TSubclassOf<class UCUserWidget_ActionList> ActionListClass;

private:
	class UCUserWidget_ActionList* ActionList;

 

// 생성자()
CHelpers::GetClass<UCUserWidget_ActionList>(&ActionList, "WidgetBlueprint'/Game/Widgets/WB_ActionList.WB_ActionList_C'");



// BeginPlay()

ActionList = CreateWidget<UCUserWidget_ActionList, APlayerController>(GetController<APlayerController>(), ActionListClass);
ActionList->AddToViewport();
ActionList->SetVisibility(ESlateVisibility::Hidden);



PlayerInputComponent->BindAction("ViewActionList", EInputEvent::IE_Pressed, this, &ACPlayer::OnViewActionList);
PlayerInputComponent->BindAction("ViewActionList", EInputEvent::IE_Released, this, &ACPlayer::OffViewActionList);




* 입력에 따른 위젯 Visibility 및 마우스 입력 세팅

void ACPlayer::OnViewActionList()
{
	ActionList->SetVisibility(ESlateVisibility::Visible);

	// 마우스 커서 보이게
	GetController<APlayerController>()->bShowMouseCursor = true;
	// UI 모드인지, 게임 모드인지
	// SetInptuMode() : 게임모드인지 UI모드인지를 지정함
	// 게임모드로 하면 포커스가 UI선택이 안되고, UI모드로 하면 게임쪽에서 마우스 선택이 안됨
	// FInputModeGameAndUI() : 이것은 게임모드와 UI모드에서 전부 마우스 입력이 가능하도록 처리
	GetController<APlayerController>()->SetInputMode(FInputModeGameAndUI());

	// 10배정도 시간을 늦춤
	UGameplayStatics::SetGlobalTimeDilation(GetWorld(), 0.1f);
}



void ACPlayer::OffViewActionList()
{
	ActionList->SetVisibility(ESlateVisibility::Hidden);

	GetController<APlayerController>()->bShowMouseCursor = false;
	// FInputModeGameOnly() : 게임모드만 되도록
	GetController<APlayerController>()->SetInputMode(FInputModeGameOnly());
	UGameplayStatics::SetGlobalTimeDilation(GetWorld(), 1.0f);
}



* 결과를 보면 마우스로 위젯 클릭하면 클릭 이벤트가 없어져 꺼져버림(바로 작업할 것임)

ActionList에서 아이템을 선택할 수 있는 것을 구현해봄

* CUserWidget_ActionList에 추가

// 아이템을 클릭했을 때 호출될 델리게이트를 생성
// 어떤 무기를 선택해라 알려줄 애
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FUserWidget_ActionItem_Clicked);



USTRUCT(BlueprintType)
struct FUserWidget_Action_Data
{
GENERATED_BODY()

public:
	class UCUserWidget_ActionItem* Item; // 아이템이 눌렸을때
	FUserWidget_ActionItem_Clicked OnUserWidget_ActionItem_Clicked; // 어떤 이벤트를 발생하라
};

 

protected:
	// BP의 Construct 이벤트 재정의하는 애
	virtual void NativeConstruct() override;

public:
	// ActionItem을 클릭 할시 여기로 넘어오게 만듬
	void Clicked(FString InName);
	void Hovered(FString InName);
	void Unhovered(FString InName);






void UCUserWidget_ActionList::NativeConstruct()
{
	// 그리드를 통해 아이템들을 찾아옴
	// GetWidgetFromName() : 이름으로 위젯을 찾아옴
	UGridPanel* gridPanel = Cast<UGridPanel>(GetWidgetFromName("Grid"));
	// 위젯이 자손을 가질 수 없습니다.라고 뜨는 것들은 GetAllChildren()을 사용할 수 없음
	TArray<UWidget*> widgets = gridPanel->GetAllChildren();

	for (UWidget* widget : widgets)
	{
		FUserWidget_Action_Data data;
		data.Item = Cast<UCUserWidget_ActionItem>(widget);

		Datas.Add(data);
	}


	// BP에 있는 Constuct를 콜하는 거여서 맨 나중에
	Super::NativeConstruct();
}



void UCUserWidget_ActionList::Hovered(FString InName)
{
	for (const FUserWidget_Action_Data& data : Datas)
	{
		// ActionItem의 Border를 불러옴
		UBorder* border = Cast<UBorder>(data.Item->GetWidgetFromName("BG_Border"));

		// 이름이 같다면 선택된 것이다.
		if (data.Item->GetName() == InName)
		{
			// 색상 변경
			border->SetBrushColor(FLinearColor::Red);

			break;
		}
	}
}



void UCUserWidget_ActionList::Unhovered(FString InName)
{
	for (const FUserWidget_Action_Data& data : Datas)
	{
		UBorder* border = Cast<UBorder>(data.Item->GetWidgetFromName("BG_Border"));

		if (data.Item->GetName() == InName)
		{
			// 원래 색상으로
			border->SetBrushColor(FLinearColor::White);

			break;
		}
	}
}








Tip) 클래스를 기본 클래스로 불러올때, 그 클래스를 수정하면 에디터 터짐
-> 그래서 기본 클래스로 불러오는 것들은 비어있도록 그냥 편집가능하도록 세팅해두는게 좋을 수 있다.

또는 Dynamic을 쓴다.


* CUserWidget_ActionItem에 추가

 

private:
	// 액션리스트를 찾아서 가져옴
	class UCUserWidget_ActionList* GetActionList();



* CUserWidget_ActionList는 Player에서 가지고 있기에 Player에서 리턴해주는 함수 세팅

- CPlayer에 추가

FORCEINLINE class UCUserWidget_ActionList* GetActionList() { return ActionList; }




* CUserWidget_ActionItem에 추가

UCUserWidget_ActionList* UCUserWidget_ActionItem::GetActionList()
{
	ACPlayer* player = Cast<ACPlayer>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));

	return player->GetActionList();
}



void UCUserWidget_ActionItem::Click()
{
	GetActionList()->Clicked(GetName());
}



void UCUserWidget_ActionItem::Hover()
{
	GetActionList()->Hovered(GetName());
}

 

void UCUserWidget_ActionItem::Unhover()
{
	GetActionList()->Unhovered(GetName());
}




* 결과를 보면 Horverd 하면 아이템의 Border(배경)이 적색으로 보임, Unhoverd 하면 다시 흰색으로 바뀜


* Click을 할 시 델리게이트에 바인딩된 함수들 콜해줌(클릭 하면 무기 선택 가능하도록 하기 위해)

void UCUserWidget_ActionList::Clicked(FString InName)
{
	for (const FUserWidget_Action_Data& data : Datas)
	{
		// 이름이 같다면 선택된 것이다.
		if (data.Item->GetName() == InName)
		{
			// 연결되어 있는 델리게이션을 콜해줌
			if (data.OnUserWidget_ActionItem_Clicked.IsBound())
				data.OnUserWidget_ActionItem_Clicked.Broadcast();

			// 닫힘
			SetVisibility(ESlateVisibility::Hidden);

			UGameplayStatics::GetPlayerController(GetWorld(), 0)->bShowMouseCursor = false;
			UGameplayStatics::GetPlayerController(GetWorld(), 0)->SetInputMode(FInputModeGameOnly());
			// 원래 게임 속도로
			UGameplayStatics::SetGlobalTimeDilation(GetWorld(), 1.0f);

			break;
		}
	}
}



* ActionItem의 Focus가 들어간게 아니라, ActionList에 포커스가 들어간 것임
-> 그래서 정상적으로 클릭이 잘 됨


<아이템 클릭에 따라 무기 선택하게 설정>
-> ActionList의 델리게이트에 함수를 바인딩 시켜줌

* Get함수 만들어서 Player에서 델리게이트에 함수 연결할 수 있도록 처리

* CUserWidget_ActionList에 추가

public:
	FORCEINLINE FUserWidget_Action_Data& GetData(uint32 InIndex) { return Datas[InIndex]; }





CPlayer에 OnFist(), OnOneHand()....
각종 무기 장착 함수들을 만들어줬었다.
-> 그대로 바인딩 시켜주면 됨


* 델리게이트에 함수 바인딩 시키기 위해 UFUNCTION()을 붙여줌

- CPlayer 수정

private:
	UFUNCTION()
		void OnFist();

	UFUNCTION()
		void OnOneHand();

	UFUNCTION()
		void OnTwoHand();

	UFUNCTION()
		void OnWarp();

	UFUNCTION()
		void OnFireStorm();

	UFUNCTION()
		void OnIceBall();




// BeginPlay()

// 무기 교체
// ActionList 위젯에 클릭 처리 위해 델리게이트에 함수 바인딩
ActionList->GetData(0).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnFist);
ActionList->GetData(1).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnOneHand);
ActionList->GetData(2).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnTwoHand);
ActionList->GetData(3).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnWarp);
ActionList->GetData(4).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnFireStorm);
ActionList->GetData(5).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnIceBall);





* 실제 게임에서는 공격 중에 UI 선택이 되면 공격이 캔슬되고 무기 선택이 됨
그거 일일히 작업하기에는 양이 많아서, Idle모드일때만 ActionList 위젯을 켜줄 수 있도록 처리

// CPlayer의 OnViewActionList()

// Idle모드일때만
CheckFalse(State->IsIdleMode());

 

 

 

 

 

CUserWidget_ActionItem.h


더보기
#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "CUserWidget_ActionItem.generated.h"

UCLASS()
class UONLINE_04_ACTION_API UCUserWidget_ActionItem : public UUserWidget
{
	GENERATED_BODY()

// Implement로 안하는 이유는 이미 거기에 정의되어있는 것을 호출만 해줄 거기때문에
// 그냥 BlueprintCallable(블루프린트에서 콜 가능하도록) 세팅
protected:
		UFUNCTION(BlueprintCallable)
			void Click();

		UFUNCTION(BlueprintCallable)
			void Hover();

		UFUNCTION(BlueprintCallable)
			void Unhover();

private:
	// 액션리스트를 찾아서 가져옴
	class UCUserWidget_ActionList* GetActionList();
};

 

 

 

 

 

 

 

CUserWidget_ActionItem.cpp


더보기
#include "CUserWidget_ActionItem.h"
#include "Global.h"
#include "Characters/CPlayer.h"
#include "CUserWidget_ActionList.h"


void UCUserWidget_ActionItem::Click()
{
	GetActionList()->Clicked(GetName());
}

void UCUserWidget_ActionItem::Hover()
{
	GetActionList()->Hovered(GetName());
}

void UCUserWidget_ActionItem::Unhover()
{
	GetActionList()->Unhovered(GetName());
}

UCUserWidget_ActionList* UCUserWidget_ActionItem::GetActionList()
{
	ACPlayer* player = Cast<ACPlayer>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));

	return player->GetActionList();
}

 

 

CUserWidget_ActionList.h


더보기
#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "CUserWidget_ActionList.generated.h"

// 아이템을 클릭했을 때 호출될 델리게이트를 생성
// 어떤 무기를 선택해라 알려줄 애
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FUserWidget_ActionItem_Clicked);

USTRUCT(BlueprintType)
struct FUserWidget_Action_Data
{
	GENERATED_BODY()

public:
	class UCUserWidget_ActionItem* Item; // 아이템이 눌렸을때
	FUserWidget_ActionItem_Clicked OnUserWidget_ActionItem_Clicked; // 어떤 이벤트를 발생하라
};

UCLASS()
class UONLINE_04_ACTION_API UCUserWidget_ActionList : public UUserWidget
{
	GENERATED_BODY()

public:
	FORCEINLINE FUserWidget_Action_Data& GetData(uint32 InIndex) { return Datas[InIndex]; }

protected:
	// BP의 Construct 이벤트 재정의하는 애
	virtual void NativeConstruct() override;
	
public:
	// ActionItem을 클릭 할시 여기로 넘어오게 만듬
	void Clicked(FString InName);
	void Hovered(FString InName);
	void Unhovered(FString InName);


private:
	TArray<FUserWidget_Action_Data> Datas;
};

 

 

 

 

 

 

 

CUserWidget_ActionList.cpp


더보기
#include "CUserWidget_ActionList.h"
#include "Global.h"
#include "CUserWidget_ActionItem.h"
#include "Components/GridPanel.h"
#include "Components/Border.h"

void UCUserWidget_ActionList::NativeConstruct()
{
	// 그리드를 통해 아이템들을 찾아옴
	// GetWidgetFromName() : 이름으로 위젯을 찾아옴
	UGridPanel* gridPanel = Cast<UGridPanel>(GetWidgetFromName("Grid"));
	// 위젯이 자손을 가질 수 없습니다.라고 뜨는 것들은 GetAllChildren()을 사용할 수 없음
	TArray<UWidget*> widgets = gridPanel->GetAllChildren();

	for (UWidget* widget : widgets)
	{
		FUserWidget_Action_Data data;
		data.Item = Cast<UCUserWidget_ActionItem>(widget);

		Datas.Add(data);
	}


	// BP에 있는 Constuct를 콜하는 거여서 맨 나중에
	Super::NativeConstruct();
}

void UCUserWidget_ActionList::Clicked(FString InName)
{
	for (const FUserWidget_Action_Data& data : Datas)
	{
		// 이름이 같다면 선택된 것이다.
		if (data.Item->GetName() == InName)
		{
			// 연결되어 있는 델리게이션을 콜해줌
			if (data.OnUserWidget_ActionItem_Clicked.IsBound())
				data.OnUserWidget_ActionItem_Clicked.Broadcast();

			// 닫힘
			SetVisibility(ESlateVisibility::Hidden);

			UGameplayStatics::GetPlayerController(GetWorld(), 0)->bShowMouseCursor = false;
			UGameplayStatics::GetPlayerController(GetWorld(), 0)->SetInputMode(FInputModeGameOnly());
			// 원래 게임 속도로
			UGameplayStatics::SetGlobalTimeDilation(GetWorld(), 1.0f);

			break;
		}
	}
}

void UCUserWidget_ActionList::Hovered(FString InName)
{
	for (const FUserWidget_Action_Data& data : Datas)
	{
		// ActionItem의 Border를 불러옴
		UBorder* border = Cast<UBorder>(data.Item->GetWidgetFromName("BG_Border"));

		// 이름이 같다면 선택된 것이다.
		if (data.Item->GetName() == InName)
		{
			// 색상 변경
			border->SetBrushColor(FLinearColor::Red);

			break;
		}
	}
}

void UCUserWidget_ActionList::Unhovered(FString InName)
{
	for (const FUserWidget_Action_Data& data : Datas)
	{
		UBorder* border = Cast<UBorder>(data.Item->GetWidgetFromName("BG_Border"));

		if (data.Item->GetName() == InName)
		{
			// 원래 색상으로
			border->SetBrushColor(FLinearColor::White);

			break;
		}
	}
}

 

 

 

CPlayer.h 수정된 부분


더보기
...

UCLASS()
class UONLINE_04_ACTION_API ACPlayer : public ACharacter, public IICharacter
{
	GENERATED_BODY()

	...

public:
	FORCEINLINE class UCUserWidget_ActionList* GetActionList() { return ActionList; }

private:
	UFUNCTION()
		void OnFist();

	UFUNCTION()
		void OnOneHand();
	
	UFUNCTION()
		void OnTwoHand();
	
	UFUNCTION()
		void OnWarp();
	
	UFUNCTION()
		void OnFireStorm();
	
	UFUNCTION()
		void OnIceBall();
	
    ...
	
    void OnViewActionList();
	void OffViewActionList();

private:
	class UCUserWidget_ActionList* ActionList;
};

 

 

 

 

 

 

 

CPlayer.cpp 수정된 부분


더보기
...

ACPlayer::ACPlayer()
{
	...
    
	CHelpers::GetClass<UCUserWidget_ActionList>(&ActionListClass, "WidgetBlueprint'/Game/Widgets/WB_ActionList.WB_ActionList_C'");
}

void ACPlayer::BeginPlay()
{
	...
    
    
	ActionList = CreateWidget<UCUserWidget_ActionList, APlayerController>(GetController<APlayerController>(), ActionListClass);
	ActionList->AddToViewport();
	ActionList->SetVisibility(ESlateVisibility::Hidden);
    
	// 무기 교체
	// ActionList 위젯에 클릭 처리 위해 델리게이트에 함수 바인딩
	ActionList->GetData(0).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnFist);
	ActionList->GetData(1).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnOneHand);
	ActionList->GetData(2).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnTwoHand);
	ActionList->GetData(3).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnWarp);
	ActionList->GetData(4).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnFireStorm);
	ActionList->GetData(5).OnUserWidget_ActionItem_Clicked.AddDynamic(this, &ACPlayer::OnIceBall);
}

void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	...
	PlayerInputComponent->BindAction("ViewActionList", EInputEvent::IE_Pressed, this, &ACPlayer::OnViewActionList);
	PlayerInputComponent->BindAction("ViewActionList", EInputEvent::IE_Released, this, &ACPlayer::OffViewActionList);
}

void ACPlayer::OnViewActionList()
{
	// Idle모드일때만
	CheckFalse(State->IsIdleMode());

	ActionList->SetVisibility(ESlateVisibility::Visible);

	// 마우스 커서 보이게
	GetController<APlayerController>()->bShowMouseCursor = true;
	// UI 모드인지, 게임 모드인지
	// SetInptuMode() : 게임모드인지 UI모드인지를 지정함
	// 게임모드로 하면 포커스가 UI선택이 안되고, UI모드로 하면 게임쪽에서 마우스 선택이 안됨
	// FInputModeGameAndUI() : 이것은 게임모드와 UI모드에서 전부 마우스 입력이 가능하도록 처리
	GetController<APlayerController>()->SetInputMode(FInputModeGameAndUI());

	// 10배정도 시간을 늦춤
	UGameplayStatics::SetGlobalTimeDilation(GetWorld(), 0.1f);
}

void ACPlayer::OffViewActionList()
{
	ActionList->SetVisibility(ESlateVisibility::Hidden);

	GetController<APlayerController>()->bShowMouseCursor = false;
	// FInputModeGameOnly() : 게임모드만 되도록
	GetController<APlayerController>()->SetInputMode(FInputModeGameOnly());
	UGameplayStatics::SetGlobalTimeDilation(GetWorld(), 1.0f);
}

 

 

 

 

결과