TIL (Today I Learned) - 언리얼 C++ 코드 구조와 데이터 연결 방식 학습
1. 컴포넌트 간 의존성을 줄이는 연결 방식
오늘 배운 핵심은 하나의 클래스가 모든 기능을 처리하지 않고, 필요한 컴포넌트를 찾아 연결하는 방식이다.
예시:
DeckComp = GetOwner() ? GetOwner()->FindComponentByClass<UDeckComponent>() : nullptr;
사용된 방식
GetOwner()
- 현재 컴포넌트가 붙어있는 액터를 가져온다.
FindComponentByClass<T>()
- 같은 액터에 붙어있는 특정 컴포넌트를 검색한다.
즉:
PlayerCharacter
|
├── DeckComponent
|
└── SkillSlotComponent
구조에서 SkillSlotComponent가 DeckComponent를 직접 생성하거나 관리하지 않고 필요할 때 찾아서 사용한다.
장점:
- 컴포넌트 간 결합도를 낮출 수 있음
- 재사용 가능성이 높아짐
- 하나의 클래스가 너무 많은 책임을 가지는 것을 방지
2. TObjectPtr을 이용한 언리얼 객체 참조
헤더에서:
UPROPERTY(Transient)
TObjectPtr<UDeckComponent> DeckComp;
사용.
TObjectPtr 역할
언리얼 UObject를 안전하게 참조하기 위한 포인터 방식.
기존:
UDeckComponent* DeckComp;
대신:
TObjectPtr<UDeckComponent> DeckComp;
사용.
UPROPERTY()와 함께 사용하면:
- 가비지 컬렉터 추적 가능
- 에디터 직렬화 지원
- 언리얼 객체 생명주기 관리 개선
3. DataTable Row 검색 방식
스킬 데이터를 찾을 때:
CardDataTable->FindRow<FCardDataTableRow>(
SkillRowName,
TEXT("SkillSlot")
);
사용.
구조:
DataTable
Row Name
|
↓
FCardDataTableRow
FindRow()는 Row Name을 기준으로 구조체 데이터를 가져온다.
예:
DT_Card
Trueshot
├ CardName
├ Description
└ SkillRowName
에서:
FindRow("Trueshot")
하면 해당 Row의 구조체 데이터를 반환한다.
4. const 포인터 반환 방식
사용된 코드:
const FCardDataTableRow* GetSkillDataInSlot(int32 SlotIndex) const;
그리고:
const FCardDataTableRow* SkillToUse =
GetSkillDataInSlot(SlotIndex);
의미
데이터를 복사하지 않고 원본 데이터를 읽기 전용으로 참조한다.
기존 방식:
FCardDataTableRow Data = ...
이면 구조체 전체 복사 발생.
하지만:
const FCardDataTableRow*
는 주소만 전달.
장점:
- 불필요한 복사 방지
- 원본 데이터 변경 방지
- 큰 구조체 처리 효율 증가
5. 델리게이트(Dynamic Delegate) 이벤트 연결 방식
사용 코드:
BoundPlayerState->OnAvailableSkillSlotsChanged.AddUniqueDynamic(
this,
&USkillSlotComponent::HandleAvailableSkillSlotsChanged
);
방식:
PlayerState
|
| 값 변경 이벤트 발생
↓
SkillSlotComponent 함수 호출
AddUniqueDynamic
의미:
- 델리게이트에 함수 등록
- 중복 등록 방지
연결된 함수:
UFUNCTION()
void HandleAvailableSkillSlotsChanged(
int32 PreviousCount,
int32 NewCount
);
6. 함수 포인터를 이용한 Timer Callback
사용 코드:
GetWorld()->GetTimerManager().SetTimer(
SlotCooldownTimers[SlotIndex],
[this, SlotIndex]()
{
this->OnSlotCooldownFinished(SlotIndex);
},
SkillCooldown,
false
);
사용 방식:
람다 함수(Lambda)를 Timer에 전달.
구조:
시간 종료
↓
람다 실행
↓
OnSlotCooldownFinished 호출
7. TSubclassOf를 이용한 클래스 참조
스킬 데이터:
TSubclassOf<APlayerSkillBase> SkillClass;
투사체:
TSubclassOf<APlayerProjectileBase> ProjectileClass;
역할
특정 부모 클래스를 상속받은 클래스만 선택 가능하도록 제한한다.
예:
가능:
APlayerProjectileBase
↑
BP_SonicVoltProjectile
불가능:
ACharacter
같은 관계가 아닌 클래스.
8. SpawnActor를 이용한 런타임 객체 생성
사용 코드:
World->SpawnActor<APlayerProjectileBase>(
ProjectileClass,
SpawnLocation,
FRotator::ZeroRotator,
SpawnParams
);
동작:
Class 정보
↓
SpawnActor()
↓
실제 Actor 생성
즉 에디터에서 배치하지 않고 게임 실행 중 객체 생성.
9. Override를 이용한 확장 구조
부모:
virtual void ExecuteSkill(
const FVector& PlayerLocation,
const FVector& TargetLocation
);
자식:
virtual void ExecuteSkill(...) override;
구조:
APlayerSkillBase
↑
APlayerProjectileSkillBase
부모는 기본 인터페이스만 제공하고,
자식 클래스가 실제 동작을 구현한다.
오늘 사용한 주요 C++ 패턴 정리
방식사용 목적
| FindComponentByClass | 컴포넌트 검색 |
| TObjectPtr | UObject 안전 참조 |
| FindRow | DataTable 데이터 검색 |
| const 포인터 | 읽기 전용 참조 전달 |
| Delegate | 이벤트 기반 호출 |
| Lambda | Timer Callback 처리 |
| TSubclassOf | 클래스 타입 제한 |
| SpawnActor | 런타임 객체 생성 |
| Virtual / Override | 상속 기반 확장 |
오늘 구현한 시스템의 핵심은 단순히 스킬을 실행하는 것이 아니라, DataTable → Component → Actor 생성으로 이어지는 언리얼 C++ 객체 연결 구조를 이해한 것이다.
'내일배움캠프_언리얼9기' 카테고리의 다른 글
| 내일배움캠프 59일차 TIL 2026/07/15 (0) | 2026.07.15 |
|---|---|
| 내일배움캠프 58일차 TIL 2026/07/14 (0) | 2026.07.14 |
| 내일배움캠프 55일차 TIL 2026/07/09 (0) | 2026.07.09 |
| 내일배움캠프 54일차 TIL 2026/07/08 (0) | 2026.07.08 |
| 내일배움캠프 53일차 TIL 2026/07/07 (0) | 2026.07.07 |