칸나와 적의 대사를 자막처럼 넣어, 게임이 덜 심심하도록 해볼 것이다.
제일 먼저, ConversationManager 클래스를 만들었다. GameManager와 같이 SubSystem을 상속받은 클래스이며, 대사를 칠 캐릭터들은 ConversationManager의 SetConversation만을 호출하면 되도록 할 것이다.
ConversationManager.h:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "ConversationManager.generated.h"
class UConversation;
/**
*
*/
UCLASS()
class KANNATPS_API UConversationManager : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
// 인자로 대사의 인물, 대사의 내용을 받는다.
UFUNCTION(BlueprintCallable)
void SetConversation(const FString& Speaker, const FString& Content);
void SetConversationWidget(UConversation* Widget);
private:
UPROPERTY()
UConversation* ConversationWidget;
};
ConversationManager.cpp:
// Fill out your copyright notice in the Description page of Project Settings.
#include "Managers/ConversationManager.h"
#include "HUD/Conversation.h"
void UConversationManager::SetConversation(const FString& Speaker, const FString& Content)
{
ConversationWidget->SetConversation(Speaker, Content);
}
void UConversationManager::SetConversationWidget(UConversation* Widget)
{
ConversationWidget = Widget;
}
UConversation은 실제로 대사의 출력을 담당할 UserWidget을 상속받은 클래스이다. 자세한 내용은 후술할 것이다.
보시다시피, UConversationManager는 단순히 출력할 대사의 인물과 내용을 UConversation에 전달하기만 한다.
또한 단순히 문장이 한번에 뜨지 않고, 원작처럼 글자가 한 글자씩 나타나도록 할 것이다. (typewriter 효과)
먼저 대사를 담당하는 위젯 블루프린트 WBP_Conversation을 만들었다.
SpeakerText는 인물명으로, 대사가 트리거될 시 바로 완성된다. 우측 정렬되어있다.
ContentText는 대사 내용으로, 대사가 트리거될 시 한 글자씩 출력된다. 좌측 정렬되어있다.
완료된 대사의 페이드아웃 애니메이션도 만들었다. DamageIndicator의 애니메이션과 100% 똑같다.
우측 상단을 보면 부모 클래스가 Conversation.h로 되어있는데, 상술했던 그 클래스이다. 대사가 한 글자씩 출력되는 기능과 끝난 대사가 페이드아웃되는 기능은 저 C++ 클래스에서 구현할 것이다.
Conversation 클래스에 대한 설명은 코드의 주석으로 대체한다.
Conversation.h:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Conversation.generated.h"
class UTextBlock;
/**
*
*/
UCLASS()
class KANNATPS_API UConversation : public UUserWidget
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override; //BeginPlay와 같음.
void SetConversation(const FString& Speaker, const FString& Content);
protected:
UPROPERTY(BlueprintReadOnly, Transient, meta = (BindWidgetAnim)) // Transient 붙여야함.
class UWidgetAnimation* FadeAnim; // WBP_Conversation의 페이드 애니메이션.
private:
void SetContentAsSubstring(); //한 글자씩 늘려서 출력해주는 함수.
void PlayFadeAnim(); // 애니메이션 재생 함수
UPROPERTY(meta = (BindWidget))
UTextBlock* SpeakerText;
UPROPERTY(meta = (BindWidget))
UTextBlock* ContentText;
// 현재 출력 중인 대사의 전체 / 일부.
FString FullContent;
FString CurrentContent;
FTimerHandle TypewriterTimerHandle; //한 글자씩 치기 위한 타이머
FTimerHandle ClearContentHandle; // 대사가 끝난 뒤 페이드아웃을 위한 타이머
};
Conversation.cpp:
// Fill out your copyright notice in the Description page of Project Settings.
#include "HUD/Conversation.h"
#include "Managers/ConversationManager.h"
#include "Components/TextBlock.h"
void UConversation::NativeConstruct()
{
// 자기 자신을 UConversationManager에 등록한다.
GetGameInstance()->GetSubsystem<UConversationManager>()->SetConversationWidget(this);
SetRenderOpacity(0.f); // 초기 투명도는 0 (안보임)
}
void UConversation::SetConversation(const FString& Speaker, const FString& Content)
{
//타이머 초기화.
GetWorld()->GetTimerManager().ClearTimer(TypewriterTimerHandle);
GetWorld()->GetTimerManager().ClearTimer(ClearContentHandle);
//화자 텍스트는 한번에 설정, 내용 텍스트는 일단 비워둠.
SpeakerText->SetText(FText::FromString(Speaker));
ContentText->SetText(FText::GetEmpty());
// 투명도 1
SetRenderOpacity(1.f);
// 전체 대사 저장.
FullContent = Content;
// 0.05초마다 SetContentAsSubstring을 호출한다.
GetWorld()->GetTimerManager().SetTimer(TypewriterTimerHandle, this, &UConversation::SetContentAsSubstring, 0.05f, true);
}
void UConversation::SetContentAsSubstring()
{
// 현재 내용의 길이에서 1 증가한 것을 현재 길이로
int CurrLength = CurrentContent.Len() + 1;
// *** Mid는 Substring과 같다. ***
CurrentContent = FullContent.Mid(0, CurrLength);
ContentText->SetText(FText::FromString(CurrentContent));
// 끝까지 다 출력했다면
if (CurrLength == FullContent.Len())
{
GetWorld()->GetTimerManager().ClearTimer(TypewriterTimerHandle); // 타이머 클리어
// 2초 뒤 페이드아웃 애니메이션 재생
GetWorld()->GetTimerManager().SetTimer(ClearContentHandle, this, &UConversation::PlayFadeAnim, 2.f, false);
}
}
void UConversation::PlayFadeAnim()
{
PlayAnimation(FadeAnim);
}
테스트를 위해 KannaCharacter의 BeginPlay에서 ConversationManager를 통해 대사를 출력하도록 해봤다.
원작과 비슷하게 한 글자씩 다다다닥 잘 나오는 것을 볼 수 있었다.
'언리얼 엔진 5 > 개발 일지' 카테고리의 다른 글
[UE5] 블루아카이브 TPS게임 개발일지 (63) - 맵 연결 (Level Streaming) (0) | 2024.02.25 |
---|---|
[UE5] 블루아카이브 TPS게임 개발일지 (62) - 대사 기능 적용 (0) | 2024.02.24 |
[UE5] 블루아카이브 TPS게임 개발일지 (60) - GameManager로 적 관리 (0) | 2024.02.17 |
[UE5] 블루아카이브 TPS게임 개발일지 (59) - 사망 연출 제작 3 (0) | 2024.02.16 |
[UE5] 블루아카이브 TPS게임 개발일지 (58) - 사망 연출 제작 2 (0) | 2024.02.16 |