게임 개발/학습 일지

언리얼 C++ - UI 애니메이션 효과 및 3D 위젯 UI 구현하기

이개 2026. 4. 29. 09:57
  1. 머리위에 체력표시
  2. 메뉴창 끝날 때 게임오버 텍스트 출력 및 애니메이션 적용
  3. 총점 표시

MainMenu에 Text 두 개 추가하고, GameOverText와 TotlaScoreText라고 이름붙인다.

 

Game Over 설정
Total Score 설정

 

UI 애니메이션 생성하기

MainMenu 블루프린트에서 Animation 탭을 연다.

 

 

Detail 창에서 Visible을 Hidden으로 지정한다.

 

GameOverText를 선택하고 +Animation 버튼을 눌러 Anim_TimeOver를 추가한다.

 

 

Anim_TimeOver를 누른 후 +Add를 클릭한다.

 

 

+Add를 눌러 GameOverText를 선택한다.
+를 눌러 Render Opacity를 적용한다.
키프레임을 옮기고 강도를 조절하면 자동으로 키가 생성된다. 1.0 -> 0.2 -> 0.0 -> 0.2 -> 1.0으로 지정한다.

 

재생하면 깜빡거리는 효과가 적용된다.

 

재생 시간을 조절하고 컴파일한다.

 

UI 애니메이션 설정하기

GameOverText의 IsValriable에 체크해준다.

 

그래프에서 PlayGameOverAnim 함수를 생성한다.
GameOverText에 Set Visibillity를 연결하고 Visible로 설정한다. 만든 애니메이션을 Play Animation에 연결한다.
Total Score도 IsVariable 체크하고, Visibillity를 Hidden으로 해준다.
Total Score에도 Set Visibillity를 설정해주다.

 

 

SpartaController.cpp 수정

ShowMainMenu 함수를 수정한다.

if (UTextBlock* ButtonText = Cast<UTextBlock>(MainMenuWidgetInstance->GetWidgetFromName(TEXT("StartButtonText"))))
{
    // 시작과 재시작 구분
    if (bIsRestart)
    {
        ButtonText->SetText(FText::FromString(TEXT("Restart")));
    }
    else
    {
        ButtonText->SetText(FText::FromString(TEXT("Start")));
    }
}

if (bIsRestart)
{
    UFunction* PlayAnimFunc = MainMenuWidgetInstance->FindFunction(FName("PlayGameOverAnim")); // PlayGameOverAnim이라는 이름을 가진 함수 찾아서 저장
    if (PlayAnimFunc)
    {
        MainMenuWidgetInstance->ProcessEvent(PlayAnimFunc, nullptr); // 인자가 없는 함수일 경우에는 nullptr 붙이고 ProcessEvent로 실행한다.
        if (UTextBlock* TotalScoreText = Cast<UTextBlock>(MainMenuWidgetInstance->GetWidgetFromName("TotalScoreText")))
        {
            if (USpartaGameInstance* SpartaGameInstance = Cast <USpartaGameInstance>(UGameplayStatics::GetGameInstance(this)))
            {
                TotalScoreText->SetText(FText::FromString(FString::Printf(TEXT("Total Score: %d"), SpartaGameInstance->TotalScore)));
            }
        }
    }
}

 

테스트를 위해 GameState에서 LevelDuration을 10초로 변경한다.

ASpartaGameState::ASpartaGameState()
{
	// 변수 초기화
	Score = 0;
	SpawnedCoinCount = 0; 
	CollectedCoinCount = 0;
	LevelDuration = 10.0; // 30-> 테스트를 위해 10으로 변경
	CurrentLevelIndex = 0;
	MaxLevels = 3;
}

 

게임에서 적용사항을 확인한다.

 

캐릭터 위에 체력바 구현하기

3D Widget Component 구현

새 블루프린트 위젯 컴포넌트를 만든다. 이름은 WBP_HP이다.

 

만든 블루프린트에서 Text를 하나 생성해준다.
요소 이름은 OverHeadHP, Size 40, Justification 가운데 맞춤으로 해준다.

 

위젯 붙이기

UI는 스크린과 월드의 두 종류가 있다.

스크린은 항상 화면에 평면적으로 표시하는 것이고, 월드는 각도에 따라 달라보이게 만든 것이다. 따라서 2D처럼 3D UI를 적용하기 위해서는 스크린 모드로 고정해주어야한다.

 

SpartaCharacter.h

public:
	// Sets default values for this character's properties
	ASpartaCharacter();
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	USpringArmComponent* SpringArmComp;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
	UCameraComponent* CameraComp;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI")
	UWidgetComponent* OverheadWidget; // 위젯 컴포넌트

	UFUNCTION(BlueprintPure, Category = "Health")
	float GetHealth() const;

	UFUNCTION(BlueprintCallable, Category = "Health")
	void AddHealth(float Amount);
	void UpdateOverhaedHP(); // HP 위젯을 업데이트 해준다.

	void BeginPlay() override;

 

cpp

void ASpartaCharacter::UpdateOverhaedHP()
{
	if (!OverheadWidget) return;
	UUserWidget* OverheadWidgetInstance = OverheadWidget->GetUserWidgetObject();
	if (!OverheadWidgetInstance) return;
	if (UTextBlock* HPText = Cast<UTextBlock>(OverheadWidgetInstance->GetWidgetFromName(TEXT("OverHeadHP"))))
	{
		HPText->SetText(FText::FromString(FString::Printf(TEXT("%0.f / %.0f"), Health, MaxHealth)));
	}
}

 

 

캐릭터 블루프린트에서 WBP_HP를 선택해준다.

 

Space를 World로 하여 보이게 만든 후, 위치와 크기를 조절해준다.
조정을 완료한 뒤에는 스크린 모드로 변경해준다.

 

캐릭터 위에 위젯이 뜨게 된다.

체력이 0 이하가 되었을 때 게임 오버

SpartaGameState.cpp

void ASpartaGameState::OnGameOver()
{
	// UpdateHUD();
	// UE_LOG(LogTemp, Warning, TEXT("Game Over!!"));
	// MainMenu UI 열기
	if (APlayerController* PlayerController = GetWorld()->GetFirstPlayerController())
	{
		if (ASpartaPlayerController* SpartaPlayerController = Cast<ASpartaPlayerController>(PlayerController))
		{
			SpartaPlayerController->SetPause(true); // 일시정지
			SpartaPlayerController->ShowMainMenu(true); // 레벨이 오픈될 때마다 UI는 HUD로 전환
		}
	}

}

 

SpartaPlayerController.cpp

void ASpartaPlayerController::StartGame()
{
	// 시작시 인스턴스 초기화
	if (USpartaGameInstance* SpartaGameInstance = Cast<USpartaGameInstance>(UGameplayStatics::GetGameInstance(this)))
	{
		SpartaGameInstance->CurrentLevelIndex = 0;
		SpartaGameInstance->TotalScore = 0;
	}

	UGameplayStatics::OpenLevel(GetWorld(), FName("BasicLevel")); // 월드에 BasicLevel 오픈
	SetPause(false); // 일시정지 해제
}