Unreal - 대화 Npc

2025. 12. 22. 06:04·Unreal 프로젝트 다이어리/두번째 프로젝트

미리보기

 

구현내용

현재 퀘스트를 건네주는 Npc에게 물건 전달하기 라는 퀘스트가 존재한다

퀘스트를받고 물건을 건네받을 Npc가 필요했다.

해당 Npc는 평소에는 정해진 말만 반복하다가

퀘스트를 의뢰중이라면 퀘스트 전용 대사로 변경된다

대사를 타이핑하고 G키를 누르면 다음 대사로 넘어가거나

대사중에 G키를눌러 대사를 스킵 할수 있다.

 

사용된 클래스

클래스 이름 사용 목적
BaseNpc(캐릭터) 플레이어의 입력(G)키를 받아 Npc와의 상호작용 흐름을 관리하는
공통 부모 클래스
NpcCiel(캐릭터) BaseNpc를 상속받아 실제 특정 Npc의 대사, 진행-스킵
로직을 구현한 Ciel이란 이름의 Npc클래스
NpcWidget(위젯) Npc 의 대사를 화면에 표시하고 타이핑 / 스킵 같은
UI 연출을 담당하는 위젯 클래스

 

구현

구현방식은 문자열 인덱싱 기반 상태 머신 방식으로 제작하였습니다

 

간단하게 설명해서

대사 전체 문자열을 보관해두고, 타이머로 인덱스를 1씩 증가시키며 문자열을 부분적으로 렌더링 하는 시스템입니다

 

구현 C++

먼저 Npc에서 퀘스트를 받았는지 안 받았는지 확인하고 대사를 컨트롤 하게 구현하였습니다

일반대사 배열과 퀘스트 대사 배열로 나누었습니다

원하는 대사를 원하는 페이지만큼 쉽게 수정이 가능하다

 

public:
	UPROPERTY(EditAnywhere, Category = "Conversation")
	TArray<FText> normalConversations;

	UPROPERTY(EditAnywhere, Category = "Conversation")
	TArray<FText> questConversations;

	int32 currentTalkIndex = 0;
	bool bQuestAccepted = false;

	UFUNCTION()
	void OnQuestAccepted(int32 questID);

	UFUNCTION()
	void StartCurrentConversation();

	UFUNCTION()
	void CielQuestComplete();

public:
	UFUNCTION()
	void HandleNextTalkPage();
    
    
//구현부
//--------------------------------------
    void ANpcCiel::Interact(AMainCharacterController* inController)
{
	Super::Interact(inController);


	if (!inController)
		return;
	mainCon = inController;
	mainCon->currentNpcCiel = this;
	currentTalkIndex = 0;


	FInputModeGameAndUI inputMode;
	inputMode.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
	inputMode.SetHideCursorDuringCapture(false);

	mainCon->SetInputMode(inputMode);
	mainCon->bShowMouseCursor = true;


	GetWorld()->GetTimerManager().SetTimer(th_WidgetDelayTimer,
		[this]()
		{
			WidgetSet(true);
			UNpcWidget* selfWidget = mainCon->npcWidget;
			selfWidget->SetNextPageAnim(false);
			StartCurrentConversation();
			
		}, 0.5f, false);
}

void ANpcCiel::OnQuestAccepted(int32 questID)
{
	if (questID == 3)
		bQuestAccepted = true;

}

void ANpcCiel::StartCurrentConversation()
{
	UNpcWidget* selfWidget = mainCon->npcWidget;
	if (!selfWidget)
		return;

	const TArray<FText>& talkArr = bQuestAccepted ? questConversations : normalConversations;

	if (!talkArr.IsValidIndex(currentTalkIndex))
	{
		EndInteraction(mainCon);
		return;
	}

	selfWidget->onTypingFinishedCallBack = [this]()
		{
			mainCon->npcWidget->SetNextPageAnim(true);
		};

	selfWidget->StartTyping(talkArr[currentTalkIndex]);

}

void ANpcCiel::CielQuestComplete()
{
	playerChar->invenComp->RemoveItem(18, 1);
	playerChar->questComp->OnDeliverItem(18, 1);
	bQuestAccepted = false;
}

void ANpcCiel::HandleNextTalkPage()
{
	UNpcWidget* selfWidget = mainCon->npcWidget;

	if (!selfWidget)
		return;

	const TArray<FText>& talkArr = bQuestAccepted ? questConversations : normalConversations;

	// 1. 타이핑 중이면 즉시 완료
	if (selfWidget->IsTyping())
		selfWidget->FinishTypingImmediately();
	else
	{
		// 2. 타이핑 끝났으면 다음 대사 진행
		selfWidget->SetNextPageAnim(false);
		currentTalkIndex++;

		if (!talkArr.IsValidIndex(currentTalkIndex))
		{
			if (bQuestAccepted)
				CielQuestComplete();

			EndInteraction(mainCon);
			return;
		}

		StartCurrentConversation();
	}
}

 

 

그리고 위젯에서는 타이핑 시스템을 구현하였습니다

구현된 내용은 이와같습니다

  • 문자열을 한글자씩 랜더링 하며 타이핑한다
  • G키를 눌러 즉시 지금 대화를 다음으로 넘기거나 타이핑을 스킵할수 있다

 

void UNpcWidget::StartTyping(const FText& sayText)
{
	GetWorld()->GetTimerManager().ClearTimer(th_typingMainHandle);

	fullConversationText = sayText;
	fullConversationString = sayText.ToString();

	CurrentTypingString.Empty();
	typingIdx = 0;

	TextBlock_MainConversation->SetText(FText::GetEmpty());

	GetWorld()->GetTimerManager().SetTimer(th_typingMainHandle, this, &UNpcWidget::TypingTick, typingInterval, true);
}

void UNpcWidget::TypingTick()
{
	if (typingIdx >= fullConversationString.Len())
	{
		// 타이핑 종료
		GetWorld()->GetTimerManager().ClearTimer(th_typingMainHandle);

		if (onTypingFinishedCallBack)
			onTypingFinishedCallBack();
		return;
	}

	// 한 글자씩 추가하기
	CurrentTypingString.AppendChar(fullConversationString[typingIdx]);
	typingIdx++;

	TextBlock_MainConversation->SetText(FText::FromString(CurrentTypingString));
}

void UNpcWidget::SetNextPageAnim(bool bActive)
{
	if(bActive)
		PlayAnimation(Next, 0.f, 0, EUMGSequencePlayMode::Forward, 3.f);
	else
	{
		StopAnimation(Next);
		SetAnimationCurrentTime(Next, 0.f);
	}
}

bool UNpcWidget::IsTyping() const
{
	return typingIdx < fullConversationString.Len();
}

void UNpcWidget::FinishTypingImmediately()
{
	GetWorld()->GetTimerManager().ClearTimer(th_typingMainHandle);
	CurrentTypingString = fullConversationString;
	typingIdx = fullConversationString.Len();
	TextBlock_MainConversation->SetText(fullConversationText);

	if (onTypingFinishedCallBack)
		onTypingFinishedCallBack();
}

 

onTypingFinishedCallBack은 타이핑 효과가 끝났을 때 외부 로직을 호출하기 위한

콜백 함수입니다

TFunction<void()> onTypingFinishedCallBack;

 

결과

Npc와 상호작용하면 대사가 첫번쨰 인덱스부터 타이핑 형식으로 출력됩니다

또한 타이핑이 완료되면 우측하단의 Press G키 애니메이션이 작동됩니다.

 

타이핑 도중 G키를 누르면 대사를 스킵할수 있습니다

 

G키를 누르면 다음 대사로 넘어갈 수 있습니다

 

 

 

영상

 

 

저작자표시 비영리 변경금지 (새창열림)

'Unreal 프로젝트 다이어리 > 두번째 프로젝트' 카테고리의 다른 글

Unreal - 퀘스트 시스템2  (0) 2025.12.22
Unreal - 가이드 마커  (0) 2025.12.22
Unreal - 퀘스트 시스템  (0) 2025.12.19
Unreal - 상호작용 프롬프트  (4) 2025.12.19
Unreal - 상점 Npc  (1) 2025.12.17
'Unreal 프로젝트 다이어리/두번째 프로젝트' 카테고리의 다른 글
  • Unreal - 퀘스트 시스템2
  • Unreal - 가이드 마커
  • Unreal - 퀘스트 시스템
  • Unreal - 상호작용 프롬프트
lucodev
lucodev
언리얼 포폴개발 일기
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (236)
      • Unreal 프로젝트 다이어리 (132)
        • 첫번째 프로젝트 (73)
        • 두번째 프로젝트 (59)
      • Unreal 팁 (8)
      • Unreal 디버깅 (8)
      • C++ 프로그래머스 (52)
        • Stack,Queue (7)
        • Hash (4)
        • Heap (2)
        • Sort (5)
        • Exhaustive search (5)
        • Greedy (2)
        • BFS , DFS (7)
        • Graph (2)
        • Dynamic Programming (1)
        • C++ Math (2)
        • 기타 문제 (14)
      • C++ 백준 (5)
      • C++ 팁 (1)
      • 개인 코테 & 스타디 <비공개> (29)
        • 코드 개인보관함 (9)
        • 코딩테스트+@ (11)
        • 알고리즘 스타디 (6)
        • 알고리즘 스타디 과제 (3)
        • 비공개 (0)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 태그

    언리얼 파쿠르
    unreal 상호작용
    언리얼 ui
    unreal
    언리얼 behavior tree
    언리얼 상호작용
    unreal 인벤토리
    언리얼 세키로
    unreal 세키로
    언리얼 인터렉션
    unreal 파쿠르
    unreal npc
    언리얼 parkour
    언리얼 시퀀스
    언리얼 컷씬
    언리얼
    언리얼 비헤이비어트리
    언리얼 인벤토리
    언리얼 behaviortree
    unreal inventory
  • hELLO· Designed By정상우.v4.10.3
lucodev
Unreal - 대화 Npc
상단으로

티스토리툴바