TIL(Today I Learned)

2026/06/15

BreadMushroom 2026. 6. 15. 21:57

TIL 쓰기전 항상 명심 할 것

작성 타이밍: 공부가 다 끝나고 쓰려고 하면 지쳐서 안쓴다. 모르는게 있을 때 즉시 적기

작성 강도: 메모가 절대로 '공부'나 '또 하나의 짐'처럼 무거워지면 안됨.


 

 

[질문] 왜 FText를 FString으로 바꿀까?

  • 내가 몰랐던 것 (문제): SetChatMessageString(Text.ToString()); 왜 입력받은 채팅의 Text 매개변수 자료형을 FText에서 FString으로 변경하는걸까?
  • 원인 (이유):
    • FText는 화면에 보여주기 위한 텍스트에 가깝다.
      비유하면 사용자에게 보여주는 문장
    • FString은 C++에서 문자열을 저장하거나 가공하기 쉬운 형태.
      비유하면 프로그램 내부에서 처리하기 좋은 문자열.
    • UI 표시용 텍스트를 내부로직으로 돌릴 문자열로 변경하기 위함.(변수에 저장해서 서버에 보내줘야 하기 때문)
void UHWUserWidget::OnChatInputTextCommitted(const FText& Text, ETextCommit::Type CommiMethod)
{
	if (CommiMethod == ETextCommit::OnEnter)
	{
		APlayerController* OwningHWPlayerController = GetOwningPlayer();
		if (IsValid(OwningHWPlayerController) == true)
		{
			AHWPlayerController* OwningHWPlayerController = Cast<AHWPlayerController>(OwningHWPlayerController);
			if (IsValid(OwningHWPlayerController) == true)
			{
				OwningHWPlayerController->SetChatMessageString(Text.ToString());

				EditableTextBox_ChatInput->SetText(FText());
			}
		}
	}
}

 

[질문] 왜 FString->FText으로 바꿀땐 .ToText()가 아닐까?

  • 내가 몰랐던 것 (문제): FString 자료형 변수를 FText 자료형으로 사용하는 매개변수에 넘겨주기 위해 변환을 시도 저번에 FText-> FString 변환시 .ToString() 이라는 함수를 사용했으니 이것도 .ToText()함수로 사용하면 되겠지? ->안됨
  • 원인 (이유):FString은 그냥 문자열 데이터이지만 FText는 언리얼에서 UI 표시용 텍스트, 현지화/다국어 처리까지 고려하는 타입 즉, FText범주 안에 FString이 포함되어 있는 것이기 때문에 FString->FText 더 작은 단위에서 큰 단위로 변환하기 때문

void AHWPlayerController::PrintChatMessageString(const FString& InChatMessageString)
{
	//UKismetSystemLibrary::PrintString(this, InChatMessageString, true, true, FLinearColor::Red, 10.0f);
	if (IsValid(ChatInputWidgetInstance) == true)
	{
		ChatInputWidgetInstance->AddChatMessage(FText::FromString(InChatMessageString));
	}
}

 

[디버깅] 왜 PIE 실행시 오류가 생길까?

  • 내가 몰랐던 것 (문제): 채팅기능을 구현하고 PIE 실행시 ensure 델리게이트 오류 발생 
  • 원인 (이유):AddDynamic으로 동적 델리게이트에 함수를 연결하려 했지만,
    연결 대상 함수(OnChatInputTextCommitted)가 UFUNCTION()으로 언리얼 리플렉션 시스템에 등록되어 있지 않아서 발생한 오류
//언리얼 CallStack 창에서 발견한 오류로그

Ensure condition failed: this->IsBound() [File:F:\UE_5.5\Engine\Source\Runtime\Core\Public\Delegates\DelegateSignatureImpl.inl] [Line: 1147] 
Unable to bind delegate to 'OnChatInputTextCommitted' (function might not be marked as a UFUNCTION or object may be pending kill)

2026.06.15-07.03.37:598][443]LogOutputDevice: Error: Ensure condition failed: this->IsBound() 
[File:F:\UE_5.5\Engine\Source\Runtime\Core\Public\Delegates\DelegateSignatureImpl.inl] [Line: 1147]

 

[개념] meta / TObjectPtr

UPROPERTY(meta = (BindWidget))
TObjectPtr<UEditableTextBox> EditableTextBox_ChatInput;

 

meta: 언리얼에게 알려주는 추가 설명서

TObjectPtr: UObject계열 객체를 가리킬 때 사용하는 언리얼식 포인터 

BindWidget: UMG 위젯 이름과 C++ 변수 이름을 맞춰 자동 연결하는 옵션

 

코드 설명: UMG 블루프린트에 있는 EditableTextBox_ChatInput이라는 입력창 위젯을 C++에서 사용할 수 있도록 연결해 둔 변수 선언

주의 할점: UMG에 있는 위젯 이름과 C++ 변수명이 다르면 BindWidget 연결이 안될 수 있다.

 

[개념] TSubclassOf

UPROPERTY(EditDefaultsOnly)
TSubclassOf<UHWUserWidget> ChatInputWidgetClass;

UPROPERTY()
TObjectPtr<UHWUserWidget> ChatInputWidgetInstance;

TSubclassOf: 특정 부모 클래스를 상속한 클래스만 담을 수 있게 제한하는 타입

(이 코드에선 UHWUserWidget 클래스로 제한)

 

코드 설명:

1. 어떤 위젯을 만들지 정한다
   → ChatInputWidgetClass
2. 실행 중에 그 클래스로 실제 위젯을 만든다
   → ChatInputWidgetInstance
3. 만든 위젯을 화면에 추가하거나 조작한다

 

ChatInputWidgetClass 생성할 UI의 설계도

ChatInputWidgetInstance 설계도로 생성된 UI객체

 

[개념] "UMG", "Slate", "SlateCore" 모듈 추가

//프로젝트명.Build.cs

PublicDependencyModuleNames.AddRange(new string[] 
{ 
	// Initial Dependencies
	"Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput",

	// UI
	"UMG", "Slate", "SlateCore",
});

UMG, Slate, SlateCore는 언리얼 UI 기능을 C++에서 사용하기 위해 Build.cs에 추가하는 UI 관련 모듈

주의 할점: UI 관련 클래스 작성시 빌드 에러가 난다면 Build.cs 파일에 모듈이 추가되었는지 확인할 것

 

[개념] Launch Seperate Server 옵션과 Run Under One Process 옵션

  • Launch Seperate Server:
    • true: 독립된 서버 프로세스가 실행. 
    • false: 언리얼 에디터 프로세스가 서버이자 클라. 
  • Run Under One Process:
    • true: 언리얼 에디터 프로세스 내에서 서버와 클라가 동작. (디버깅할 때 사용)
    • false: 서버와 각 클라들이 다른 프로세스로 분기됩니다. (개발할 때 사용)

데디케이티드 서버 기반 개발시

디버깅 시에는 “Launch Seperate Server == false && Run Under One Process == true”

릴리즈 검증 시에는 “Launch Seperate Server == true && Run Under One Process == false”

 

 

[함수 족보] NativeConstruct() / NativeDestruct()

  • 한 줄 요약: 채팅 입력 위젯이 살아있는 동안만 입력 확정 이벤트와 처리 함수를 연결하고, 위젯이 사라질 때 연결을 해제하는 코드
  • 코드설명:
    NativeConstruct:
    - 위젯이 생성되어 사용할 준비가 되었을 때 호출된다.
    - 입력창의 OnTextCommitted 이벤트에 처리 함수를 등록한다.

    NativeDestruct:
    - 위젯이 제거되거나 정리될 때 호출된다.
    - 등록했던 이벤트 함수를 해제한다.

    OnTextCommitted:
    - 텍스트 입력이 확정되었을 때 발생하는 이벤트이다.

    AddDynamic:
    - 이벤트가 발생했을 때 실행할 함수를 등록한다.

    RemoveDynamic:
    - 등록했던 함수를 이벤트에서 제거한다.

    IsAlreadyBound:
    - 같은 함수가 이미 이벤트에 연결되어 있는지 확인한다.
  • 코드:
void UHWUserWidget::NativeConstruct()
{
	Super::NativeConstruct();

	if (EditableTextBox_ChatInput->OnTextCommitted.IsAlreadyBound(this, &ThisClass::OnChatInputTextCommitted) == false)
	{
		EditableTextBox_ChatInput->OnTextCommitted.AddDynamic(this, &ThisClass::OnChatInputTextCommitted);
	}
}

void UHWUserWidget::NativeDestruct()
{
	Super::NativeDestruct();

	if (EditableTextBox_ChatInput->OnTextCommitted.IsAlreadyBound(this, &ThisClass::OnChatInputTextCommitted) == true)
	{
		EditableTextBox_ChatInput->OnTextCommitted.RemoveDynamic(this, &ThisClass::OnChatInputTextCommitted);
	}
}

 

[함수 족보] PublicIncludePaths.AddRange(new string[] { "Homework9" });

  • 한 줄 요약: 새로운 C++클래스의 Path 지정 생성시 경로오류를 해결해주기 위한 함수
  • 언제 써?: 새로운 C++클래스의  Path 지정 생성할 때 build.cs 파일에 한번만 작성해주면 됨
  • 코드:
//프로젝트명.Build.cs

PublicIncludePaths.AddRange(new string[] { "프로젝트명" });

 

[함수 족보] GetOwningPlayer()

  • 한 줄 요약: 이 객체와 연결된 플레이어 컨트롤러를 찾아오는 역할
  • 코드:
APlayerController* OwningPlayerController = GetOwningPlayer();

 

[함수 족보] TActorIterator <>

  • 한 줄 요약: 월드 안의 특정 Actor들을 하나씩 찾아보는 반복 도구
  • 언제 써?: 월드 속의 특정 클래스의 Actor만 찾고 싶을 때 (ex: PlayerController)
  • 코드:
for (TActorIterator<AHWPlayerController> It(GetWorld()); It; ++It)
{
     AHWPlayerController* HWPlayerController = *It;
}


[기능구현] 채팅내역남기기

PlayerController
→ 메시지를 받음
→ ChatInputWidgetInstance->AddChatMessage(메시지)

UHWUserWidget::AddChatMessage
→ TextBlock 생성
→ 메시지 설정
→ ScrollBox에 추가
채팅 내역은 ScrollBox에 TextBlock을 동적으로 추가하는 방식으로 구현했다.
PlayerController의 FString 메시지는 FText::FromString()으로 변환해서 UI 함수에 전달한다.
메시지 추가 후 ScrollToEnd()를 호출해 최신 메시지가 자동으로 보이게 했다.
FText::FromString()
NewObject<UTextBlock>()
ScrollBox->ScrollToEnd()

 

'TIL(Today I Learned)' 카테고리의 다른 글

2026/06/24  (0) 2026.06.24
2026/06/19  (0) 2026.06.19
2026/06/18  (0) 2026.06.18
2026/06/16  (0) 2026.06.16
2026/06/12  (0) 2026.06.12