게임 개발 (언리얼 엔진)

UE4 생존게임 제작 - 16 (각종 UI 제작)

언린이 2020. 11. 21. 18:01

1. 아이템 설명 텍스트 창 제작

 

 

위젯 블루프린트를 생성한 후,

 

 

 

간단하게 아이템 설명 텍스트 창을 꾸며주었습니다.

 

 

 

그리고 나서 전에 만들어두었던 인벤토리 아이템 위젯에 붙여주었습니다.

 

 

 

이때, 아이템 설명 텍스트 창은 Collapsed(안보이는 상태)로 설정하였습니다.

사용자가 아이템에 마우스를 올렸을 때만 보이는 상태로 해줄 것입니다.

 

 

void UInventoryItem::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
	Super::NativeTick(MyGeometry, InDeltaTime);

	// 마우스를 아이템에 올려놓았을 때, 아이템 설명 텍스트 창 보이게 설정
	if (BackImage->IsHovered() || NameText->IsHovered() || CountText->IsHovered() || IconImage->IsHovered())
	{
		if (!DescriptionText->IsVisible())
			DescriptionText->SetVisibility(ESlateVisibility::Visible);
	}

	// 그렇지 않은 경우 안보이게 설정
	else
	{
		if (DescriptionText->IsVisible())
			DescriptionText->SetVisibility(ESlateVisibility::Collapsed);
	}
}

 

이제 인벤토리 아이템 클래스의 NativeTick 함수에서 사용자가 마우스를 아이템에 올려놓았는지 감지하였습니다.

만약 마우스를 아이템에 올려놓았다면, 아이템 설명 텍스트 창을 보이는 상태로 변경해주었습니다.

 

 

void UUIItemDescription::SetItemDescription(const FString& strDescription)
{
	DescriptionText->SetText(FText::FromString(strDescription));
}

 

 

마지막으로 아이템 설명 텍스트 창의 부모 클래스로 지정해줄 클래스를 생성한 후,

SetItemDescription 함수를 정의하여 다른 곳에서 텍스트 창의 내용을 조작할 수 있도록 해주었습니다.

이제 이 함수를 사용하여 아이템마다 다른 설명을 적어주면 됩니다.

 

 

 

아이템에 마우스를 올려놓으면 아이템에 대한 설명이 뜨는 모습을 확인할 수 있습니다.

 

 

 

제작 아이템에 대한 설명도 똑같이 구현하였습니다.

 

 

2. 메뉴 창 제작

 

 

위젯 블루프린트를 생성한 후,

 

 

 

캔버스 패널 내부에 버튼 3개를 만들어 주었습니다.

 

 

 

그리고 나서 간단하게 메뉴 창을 꾸며주었습니다.

 

 

 

메인 화면 UI에 만들어준 메뉴 창을 띄우고 안보이는 상태로 설정해주었습니다.

 

 

 

Q 키를 입력하면 메뉴 창이 뜨도록 만들기 위해 프로젝트 세팅의 입력에서 설정해주었습니다.

 

 

	PlayerInputComponent->BindAction(TEXT("OpenSetting"), EInputEvent::IE_Pressed, this, &APlayerSurvivor::OpenSetting);

 

// 메뉴창을 여는 함수
void APlayerSurvivor::OpenSetting()
{
	// 보일 때는 안보이게 만든다
	if (Setting->IsVisible())
		Setting->VisibleSetting(ESlateVisibility::Collapsed);
	
	// 안보일때는 보이게 만든다
	else
		Setting->VisibleSetting(ESlateVisibility::Visible);

	UGameplayStatics::PlaySound2D(this, OpenSound);
}

 

SetupPlayerInputComponent 함수에서 키 입력을 하면 호출될 함수를 설정해준 후, 해당 함수에서 메뉴 창의 상태를 조작해주었습니다.

 

 

 

Q를 누르면 메뉴 창이 뜨는 모습을 확인할 수 있습니다.

 

 

protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	class UButton* PlayButton;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	class UButton* SaveButton;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	class UButton* ExitButton;

 

이제 메뉴 창을 띄웠으니 사용자가 버튼을 눌렀을 때 발생할 이벤트를 처리하기 위해 먼저 버튼들을 선언해주었습니다.

 

 

// 위젯 클래스의 생성자
void UUISetting::NativeConstruct()
{
	Super::NativeConstruct();

	// 위젯 블루프린트의 버튼을 이름을 통해 가져온다
	PlayButton = Cast<UButton>(GetWidgetFromName(TEXT("PlayButton")));
	SaveButton = Cast<UButton>(GetWidgetFromName(TEXT("SaveButton")));
	ExitButton = Cast<UButton>(GetWidgetFromName(TEXT("ExitButton")));

	// 버튼 클릭시 호출될 델리게이트에 함수를 등록한다
	PlayButton->OnClicked.AddDynamic(this, &UUISetting::PlayButtonCallback);
	SaveButton->OnClicked.AddDynamic(this, &UUISetting::SaveButtonCallback);
	ExitButton->OnClicked.AddDynamic(this, &UUISetting::ExitButtonCallback);
}

 

GetWidgetFromName 함수를 사용하여 위젯 블루프린트의 버튼을 이름을 통해 불러왔습니다.

그리고 나서 버튼 클릭시 호출될 델리게이트에 함수를 등록해주었습니다.

 

 

// Play 버튼 클릭시 실행될 함수
void UUISetting::PlayButtonCallback()
{
	// 메뉴 창을 안보이게 설정한다
	VisibleSetting(ESlateVisibility::Collapsed);
}

// Save 버튼 클릭시 실행될 함수
void UUISetting::SaveButtonCallback()
{
	// 이곳에서 게임 저장을 해줘야한다
}

// Exit 버튼 클릭시 실행될 함수
void UUISetting::ExitButtonCallback()
{
	// Start 레벨로 넘겨준다
	UGameplayStatics::OpenLevel(GetWorld(), TEXT("Start"));
}

 

Play 버튼을 눌렀을 때는 메뉴 창을 안보이게 설정해주었습니다.

그리고 Exit 버튼을 눌렀을 때는 레벨을 Start 레벨로 넘겨주었습니다.

 

Save 버튼을 눌렀을 때는 게임을 저장해줘야합니다. 게임 저장은 SaveGameObject를 사용하여 해줄 것입니다.

이 부분은 다음 글에서 다루도록 하겠습니다.

 

 

3. 플레이어 스탯 창 제작

 

 

위젯 블루프린트를 생성한 후, 내부를 꾸며주었습니다.

그리고 나서 다른 UI들과 똑같이 메인 화면 UI에 추가해주었습니다.

 

 

protected:
	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	class UTextBlock* AttackPower;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	class UTextBlock* ArmorPower;

	UPROPERTY(VisibleAnywhere, BlueprintReadWrite, meta = (AllowPrivateAccess = "true"))
	class UTextBlock* MoistureReduction;

 

public:
	void SetAttackPower(const FString& strName);
	void SetArmorPower(const FString& strName);
	void SetMoistureReduction(const FString& strName);

 

변하는 텍스트 블럭 3개를 변수로 선언해주고 해당 텍스트 블럭에 텍스트를 세팅하는 함수를 선언해주었습니다.

 

 

// 위젯 클래스의 생성자
void UUISurvivorStatWindow::NativeConstruct()
{
	Super::NativeConstruct();

	// 위젯 블루프린트의 텍스트 블럭을 이름을 통해 가져온다
	AttackPower = Cast<UTextBlock>(GetWidgetFromName(TEXT("AttackPower")));
	ArmorPower = Cast<UTextBlock>(GetWidgetFromName(TEXT("ArmorPower")));
	MoistureReduction = Cast<UTextBlock>(GetWidgetFromName(TEXT("MoistureReduction")));
}

 

// Attack 스탯에 텍스트를 세팅하는 함수
void UUISurvivorStatWindow::SetAttackPower(const FString& strName)
{
	AttackPower->SetText(FText::FromString(strName));
}

// Armor 스탯에 텍스트를 세팅하는 함수
void UUISurvivorStatWindow::SetArmorPower(const FString& strName)
{
	ArmorPower->SetText(FText::FromString(strName));
}

// Moisture Reduction Time에 텍스트를 세팅하는 함수
void UUISurvivorStatWindow::SetMoistureReduction(const FString& strName)
{
	MoistureReduction->SetText(FText::FromString(strName));
}

 

생성자에서 텍스트 블럭을 가져온 후, 각각의 텍스트 블럭에 텍스트를 세팅하는 함수를 정의해주었습니다.

 

 

	SurvivorStatWindow = SurvivorStateWidget->GetSurvivorStatWindow();

 

	// BeginPlay 함수에서 스탯 창 초기화
	if (IsValid(SurvivorStatWindow))
	{
		SurvivorStatWindow->SetAttackPower(FString::Printf(TEXT("%d"), (int32)SurvivorState.fAttack));
		SurvivorStatWindow->SetArmorPower(FString::Printf(TEXT("%d"), (int32)SurvivorState.fArmor));
		SurvivorStatWindow->SetMoistureReduction(FString::Printf(TEXT("%d"), (int32)MoistureMax));
	}

 

이제 플레이어의 BeginPlay 함수에서 스탯 창을 가져온 후, 초기 플레이어의 스탯으로 초기화해줍니다.

 

 

 

게임을 실행하면 스탯 창이 초기화된 모습을 확인할 수 있습니다.

 

 

	case 13:
		// Armor Up
		if (Data->GetItemCount() > 0)
		{
			SurvivorState.fArmor += 10.f;

			// 방어력은 20을 넘지 못한다
			if (SurvivorState.fArmor > 20.f)
				SurvivorState.fArmor = 20.f;
			else
				UGameplayStatics::PlaySoundAtLocation(this, ArmorUpSound, GetActorLocation(), 3.5f);

			// 스탯 창을 초기화한다
			if (IsValid(SurvivorStatWindow))
				SurvivorStatWindow->SetArmorPower(FString::Printf(TEXT("%d"), (int32)SurvivorState.fArmor));

			Data->SetItemCount(Data->GetItemCount() - 1);
		}
		break;
	case 14:
		// Attack Up
		if (Data->GetItemCount() > 0)
		{
			SurvivorState.fAttack += 10.f;

			// 공격력은 30을 넘지 못한다
			if (SurvivorState.fAttack > 30.f)
				SurvivorState.fAttack = 30.f;
			else
				UGameplayStatics::PlaySoundAtLocation(this, AttackUpSound, GetActorLocation(), 0.5f, 1.f, 0.5f);

			// 스탯 창을 초기화한다
			if (IsValid(SurvivorStatWindow))
				SurvivorStatWindow->SetAttackPower(FString::Printf(TEXT("%d"), (int32)SurvivorState.fAttack));

			Data->SetItemCount(Data->GetItemCount() - 1);
		}
		break;

 

Armor Up 아이템과 Attack Up 아이템을 사용할 때마다 스탯 창을 초기화해주었습니다.

 

 

	// 햇빛 가리개
	else if (Index == 10)
	{
		UInventoryItemData* Sunscreen = Cast<UInventoryItemData>(List->GetItemAt(10));

		if (Sunscreen->GetItemCount() == 0)
		{
			UInventoryItemData* Leather = Cast<UInventoryItemData>(List->GetItemAt(8));

			if (Leather->GetItemCount() >= 3)
			{
				Sunscreen->SetItemCount(1);
				Leather->SetItemCount(Leather->GetItemCount() - 3);
				bMakeItem = true;

				// 수분 게이지 줄어드는 속도 감소
				MoistureMax *= 2.f;

				// 스탯 창을 초기화해준다
				if (IsValid(SurvivorStatWindow))
					SurvivorStatWindow->SetMoistureReduction(FString::Printf(TEXT("%d"), (int32)MoistureMax));
			}
		}
	}
	// 망토
	else if (Index == 11)
	{
		UInventoryItemData* Cloak = Cast<UInventoryItemData>(List->GetItemAt(11));

		if (Cloak->GetItemCount() == 0)
		{
			UInventoryItemData* HardLeather = Cast<UInventoryItemData>(List->GetItemAt(9));

			if (HardLeather->GetItemCount() >= 3)
			{
				Cloak->SetItemCount(1);
				HardLeather->SetItemCount(HardLeather->GetItemCount() - 3);
				bMakeItem = true;

				// 수분 게이지 줄어드는 속도 감소
				MoistureMax *= 2.f;

				// 스탯 창을 초기화해준다
				if (IsValid(SurvivorStatWindow))
					SurvivorStatWindow->SetMoistureReduction(FString::Printf(TEXT("%d"), (int32)MoistureMax));
			}
		}
	}

 

또한, Sunscreen 아이템과 Cloak 아이템을 제작할 때마다 스탯 창을 초기화해주었습니다.

 

 

 

아이템을 사용하거나 제작하면 스탯 창이 초기화되는 모습을 확인할 수 있습니다.

 

 

 

마지막으로 프로젝트 세팅의 입력에서 스탯 창을 열었다 닫았다할 키 입력을 설정해준 후, 다른 UI들과 마찬가지로 처리해주었습니다.

 

 

다음에 해야할 일

 

SaveGameObject를 사용한 게임 저장 및 각종 UI 제작