1. 개요
델리게이트가 무엇이며 어떻게 내부적으로 작동하는지 살펴보자
2. 델리게이트
1. 델리게이트란?
어떤 이벤트가 발생하였을 때 등록된 객체들에게 "이벤트 발생했어요!"라고 알리는 기능(브로드캐스트)을 말한다.

SubObject는 이벤트를 감지하는 오브젝트이다.
옵저버 리스트를 보유하고 있으며 이벤트 발생시 리스트를 순회하며 콜백함수를 호출해준다.
Observer는 이벤트가 발생되었을 때 콜백 함수가 호출되길 원하는 오브젝트이다.
콜백 함수를 보유하고 있으며 SubObject에 의해 콜백함수를 호출받는다.
게임이 시작되었을 때
Observer는 SubObject에게 델리게이트를 등록하고 이벤트가 발생하면 호출받을 수 있다.

이는 디자인 패턴 중 '관찰자 패턴(Observer Pattern)'과 동일하다.
트위터에서 특정 대상을 팔로우(Follow)하면 대상이 글을 작성할 때마다 팔로워들에게 게시글 알림이 전송된다.
2. 델리게이트 장점
Subobject 오브젝트는 Observer가 어떤 오브젝트인지 알지 못해도 콜백함수를 호출해 줄 수 있다.
Subobect에서 필요로 하는 콜백함수를 정의한다. (매개변수, 반환타입)
Observer는 Subject가 정의한 콜백함수에 맞게 함수를 정의하여 등록하면 이벤트 발생시 함수를 호출받을 수 있다.
객체들간의 의존도가 낮으며 향후 코드 변경이 수월해 진다는 장점이 있다.
3. 델리게이트 활용 단계
델리게이트를 활용하는 방법은 다음과 같다.
- 관찰 대상자 (Suboject)
- 델리게이트 정의하기
- 델리게이트 변수 선언하기
- 델리게이트 브로드캐스트하기
- 옵저버 (Observer)
- 콜백함수 선언 및 정의하기
- 델리게이트에 콜백함수 바인드하기
1. 델리게이트 정의하기
델리게이트 정의는 아래와 같은 형태를 유지한다.
DECLARE_{연결 관계}_{바인드 범위}_DELEGATE_{반환타입 유무}_{매개변수 유무} ()
연결 관계
연결 관계는 관찰 대상자와 옵저버가 어떤 연결 관계를 가지는지 말한다.
// 1:1 관계일 경우
DECLARE_DELEGATE() /* 기본값으로 변경된 것이 없다. */
// 1:N 관계일 경우
DECLARE_MULTICAST_DELEGATE()
바인드 범위
콜백 함수의 바인드 범위를 블루프린트까지 허용할 것인지를 말한다.
// C++ Only 바인드 가능
DECLARE_DELEGATE() /* 기본값으로 변경된 것이 없다. */
// C++ or Blueprint 바인드 가능
DECLARE_DYNAMIC_DELEGATE()
반환타입 유무
콜백함수에 반환타입 있을 경우 "RetVal"을 붙여준다.
// 콜백 함수의 반환타입이 있는 경우
DECLARE_DELEGATE_RetVal()
// 콜백 함수의 반환타입이 없는 경우
DECLARE_DELEGATE() /* 기본값으로 변경된 것이 없다. */
// 예외) MULTICAST는 반환타입을 지정할 수 없다.
DECLARE_MULTICAST_DELEGATE_RetVal() X
매개변수 유무
매개변수의 개수에 따라 "_Param"을 붙여준다.
// 콜백함수의 매개변수가 없다.
DECLARE_DELEGATE()
// 콜백함수의 매개변수가 하나 있다.
DECLARE_DELEGATE_OneParam()
// 콜백함수의 매개변수가 두 개 있다.
DECLARE_DELEGATE_TwoParams()
그렇다면 예시를 통해 정리해보자.
// C++ Only & 1:1 관계 & 반환 타입 X & 매개 변수 X
DECLARE_DELEGATE(FSignature);
// C++ Only & 1:N 관계 (MULTICAST) & 반환 타입 X & 매개 변수 X
DECLARE_MULTICAST_DELEGATE(FSignature2);
// C++ or Blueprint (DYNAMIC) & 1:1 관계 & 반환 타입 O (RetVal) & 매개 변수 X
DECLARE_DYNAMIC_DELEGATE_RetVal(float, FSignature3);
// C++ or Blueprint (DYNAMIC) & 1:N 관계 (MULTICAST) & 반환 타입 X & 매개 변수 X
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSignature4);
// C++ or Blueprint (DYNAMIC) & 1:N 관계 (MULTICAST) & 반환 타입 X & 매개 변수 1 (OneParam)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSignature5, float, NewValue);
2. 델리게이트 변수 선언하기
관찰 대상자의 델리게이트는 변수 선언은 아래 코드와 같다.
// 델리게이트 매크로 정의
DECLARE_MULTICAST_DELEGATE_OneParam(FOnAttributeChangedSignature, float);
// 델리게이트 변수 선언 1
FOnAttributeChangedSignature OnHealthChanged;
// 델리게이트 변수 선언 2 (블루프린트에서 바인드 가능)
UPROPERTY(BlueprintAssignable)
FOnAttributeChangedSignature OnHealthChanged2;
3. 델리게이트 브로드캐스트하기
브로드캐스트는 옵저버 객체들의 콜백함수를 순회하며 호출하는 작업을 말한다.
즉, 이벤트가 발생하였을 때 옵저버들에게 알리는 기능이다.
OnHealthChanged.Broadcast(AuraAttributeSet->Get_health());
옵저버
1. 콜백함수 등록하기
옵저버 클래스에서 델리게이트 정의에 맞게 함수를 선언한다.
// DECLARE_DYNAMIC_MULTICAST_OneParam(FSignatured, float);
void HandledCurrentChanged(float InChangedHP);
2. 델리게이트에 콜백함수 바인드하기
델리게이트 바인드 함수는 다양하게 제공된다.

하나씩 차근차근 살펴보자
위 리스트는 호출 가능한 바인드 함수들이다.
바인드 함수는 크게 2가지로 분류할 수 있다.
- Bind-
- Add-
Bind는 1:1 관계를 가진 델리게이트의 바인드 함수들이다.
Add는 1:N 관계를 가진 델리게이트의 바인드 함수들이다.
// 1:1 관계
DECLARE_DELEGATE(FSignature);
FSignature OneByOneSignature;
// 1:1 관계에서는 Bind함수가 호출 가능하다.
OneByOneSignature.Bind~();
// 1:N 관계
DECLARE_MULTICAST_DELEGATE(FSignature);
FSignature OneByManySignature;
// 1:N 관계에서는 Add함수가 호출 가능하다.
OneByManySignature.Add~();
그 다음으로 접미사(Raw, SP, Static, Lambda)는 아래과 같다.
- Raw - 콜백함수로 원시 포인터의 멤버 함수를 지정한다.
- SP - 콜백함수로 스마트 포인터의 멤버 함수를 지정한다.
- Static - 콜백함수로 정적 함수를 지정한다.
- Lambda - 콜백함수로 임시 함수를 지정한다.
- Dynamic - 콜백함수로 UObject 기반의 멤버 함수를 지정한다.
즉, 정의한 콜백 함수의 생김새에 따라 바인드 함수가 정해진다고 생각하면 편하다.
예시를 살펴보자
/* 1:1 관계 */
// Raw 포인터를 사용하여 멤버 함수를 바인딩
MyDelegate.BindRaw(this, &MyClass::MyFunction);
// 스마트 포인터를 사용하여 멤버 함수를 바인딩
MyDelegate.BindSP(MySharedPointer, &MyClass::MyFunction);
// 전역 함수 또는 정적 멤버 함수를 바인딩
MyDelegate.BindStatic(&GlobalFunction);
// 람다 함수를 바인딩
MyDelegate.BindLambda([]() { UE_LOG(LogTemp, Warning, TEXT("Lambda called!")); });
/* 1:N 관계 */
// Raw 포인터를 사용하여 멤버 함수를 추가.
MyMulticastDelegate.AddRaw(this, &MyClass::MyFunction);
// 스마트 포인터를 사용하여 멤버 함수를 추가
MyMulticastDelegate.AddSP(MySharedPointer, &MyClass::MyFunction);
// 전역 함수 또는 정적 멤버 함수를 추가
MyMulticastDelegate.AddStatic(&GlobalFunction);
// 람다 함수를 추가
MyMulticastDelegate.AddLambda([]() { UE_LOG(LogTemp, Warning, TEXT("Lambda called!")); });
// UObject 기반 멤버 함수를 런타임 추가(필수: UFUNCTION)
MyDynamicMulticastDelegate.AddDynamic(this, &UMyClass::MyFunction);
4. 정리
델리게이트는 게임 개발시 다양하게 활용된다.
- 피격시 HP 변경 후 UI에 반영할 때
- AI가 플레이어 감지 후 다른 AI에게 알릴 때
- 스킬 사용 후 MP 변경 후 UI에 반영할 때
많이 사용되는 만큼 잘 익혀서 게임 개발에 녹여낼 수 있도록 하자.
참고
Observer Design Pattern | Code Pumpkin
Observer Design Pattern is useful when you are interested in the state of an object and want to get notified whenever there is any change.
codepumpkin.com
'Unrael > Basic' 카테고리의 다른 글
| [UE/Basic] 자료구조 - TArray (0) | 2025.01.22 |
|---|---|
| [UE/Basic] 액터의 라이프 사이클 (1) | 2025.01.21 |
| [UE/Basic] 액터 (Actor) (0) | 2024.12.20 |
| [UE/Basic] 캐릭터 클래스 (Character) (0) | 2024.12.20 |
| [UE/Basic] 액터의 이동 (0) | 2024.12.11 |