[UE4] Unreal Engine 4에서 델리게이트(Delegate)를 사용하는 방법들
개요
언리얼 엔진4(UE4)에서 Delegate를 사용하는법 입니다.
C++코드에서 뿐만 아니라 블루프린트 에서도 델리게이트를 사용 할 수 있습니다.
델리게이트의 상세 설명은 아래를 참조해주세요
유니티에서 델리게이트 ->유니티
C#에서 델리게이트 ->C#
C++에서 델리게이트 ->C++
언리얼 엔진 공식 문서 -> Delegate in UE
UE4에서 델리게이트의 종류
-
싱글캐스트 델리게이트 (Singlecast Delegates): 하나의 함수만 바인딩할 수 있는 Delegate입니다. 특정 이벤트가 발생했을 때 단 하나의 함수만 호출하고 싶을 때 사용합니다. 마치 “1:1 전화” 처럼, 싱글캐스트 델리게이트는 특정 함수를 직접 호출합니다.
-
멀티캐스트 델리게이트 (Multicast Delegates): 여러 개의 함수를 바인딩할 수 있는 Delegate입니다. 특정 이벤트가 발생했을 때 여러 개의 함수를 동시에 호출하고 싶을 때 사용합니다. 마치 “단체 전화” 처럼, 멀티캐스트 델리게이트는 여러 함수를 동시에 호출합니다.
-
다이나믹 델리게이트 (Dynamic Delegates): UObject에 바인딩되어 가비지 컬렉션(Garbage Collection)에 의해 관리되는 Delegate입니다. 블루프린트와 C++ 간의 상호 작용에 필수적입니다. 마치 “공용 전화” 처럼, 다이나믹 델리게이트는 블루프린트와 C++에서 모두 접근할 수 있습니다.
주의사항
-
IsBound() 확인: Delegate를 실행하기 전에 IsBound() 함수를 사용하여 바인딩된 함수가 있는지 확인해야 합니다. 바인딩되지 않은 Delegate를 실행하려고 하면 크래시가 발생할 수 있습니다.
-
UFUNCTION() 매크로: UObject의 멤버 함수를 Delegate에 바인딩하려면 해당 함수에 UFUNCTION() 매크로를 붙여야 합니다. UFUNCTION() 매크로는 해당 함수를 언리얼 엔진에 등록하여 Delegate에 바인딩할 수 있도록 합니다.
-
메모리 관리: UObject에 바인딩된 Delegate는 가비지 컬렉션에 의해 관리되므로, 명시적으로 해제할 필요가 없습니다. 하지만, 람다 함수를 사용하는 경우 캡처된 객체의 수명 주기를 고려해야 합니다. 마치 “자동 삭제” 처럼, 가비지 컬렉션은 사용하지 않는 Delegate를 자동으로 해제합니다.
-
멀티캐스트 델리게이트의 순서: 멀티캐스트 델리게이트에 바인딩된 함수의 호출 순서는 보장되지 않습니다. 특정한 순서로 함수를 실행해야 하는 경우에는 싱글캐스트 델리게이트를 여러 개 사용하는 것이 좋습니다.
-
델리게이트 시그니처 일치: Delegate의 시그니처와 바인딩하려는 함수의 시그니처가 정확히 일치해야 합니다. 반환 타입과 매개변수 개수, 타입이 모두 같아야 합니다.
-
BindUFunction 사용 시: BindUFunction을 사용하는 경우, 함수 이름은 정확해야 합니다. 오타가 있는 경우 바인딩에 실패합니다. 또한, 이 방법은 UFUNCTION() 매크로가 없는 함수를 바인딩할 때 유용하지만, 일반적으로는 BindUObject를 사용하는 것이 권장됩니다.
사용 방법
C++에서 사용
- 싱글캐스트 델리게이트
[선언]
// 헤더 파일 (.h)
DECLARE_DELEGATE(FMyDelegate); // 매개변수 없음
DECLARE_DELEGATE_OneParam(FMyDelegateWithParam, int32); // int32 매개변수 하나
DECLARE_DELEGATE_TwoParams(FMyDelegateWithTwoParams, int32, FString); // int32, FString 매개변수 두 개
[사용]
// 헤더 파일 (.h)
UPROPERTY(BlueprintAssignable)
FMyDelegate MyEvent;
UFUNCTION()
void MyFunction();
UFUNCTION()
void MyFunctionWithParam(int32 Value);
UFUNCTION()
void MyFunctionWithTwoParams(int32 Value, FString Text);
// 소스 파일 (.cpp)
void AMyActor::BeginPlay()
{
// 바인딩
OnMyEvent.BindUObject(this, &AMyActor::MyFunction);
OnMyEvent.BindUFunction(this, FName("MyFunction")); // UFUNCTION() 매크로가 없는 경우
// 람다 함수 바인딩
OnMyEvent.BindLambda([this](){
UE_LOG(LogTemp, Warning, TEXT("Lambda function called!"));
});
// 매개변수 있는 델리게이트 바인딩
FMyDelegateWithParam MyDelegateInstance;
MyDelegateInstance.BindUObject(this, &AMyActor::MyFunctionWithParam);
FMyDelegateWithTwoParams MyDelegateWithTwoParamsInstance;
MyDelegateWithTwoParamsInstance.BindUObject(this, &AMyActor::MyFunctionWithTwoParams);
}
void AMyActor::SomeEventOccurs()
{
// 실행 (델리게이트가 바인딩되어 있는지 확인하는 것이 중요)
if (OnMyEvent.IsBound())
{
OnMyEvent.Execute();
}
if(MyDelegateInstance.IsBound()){
MyDelegateInstance.Execute(10);
}
if(MyDelegateWithTwoParamsInstance.IsBound()){
MyDelegateWithTwoParamsInstance.Execute(20, TEXT("Hello"));
}
}
- 멀티캐스트 델리게이트
[선언]
// 헤더 파일 (.h)
DECLARE_MULTICAST_DELEGATE(FMyMulticastDelegate);
[사용]
// 헤더 파일 (.h)
UPROPERTY(BlueprintAssignable)
FMyMulticastDelegate OnMyMulticastEvent;
// 소스 파일 (.cpp)
void AMyActor::BeginPlay()
{
// 바인딩 (여러 함수를 바인딩 가능)
OnMyMulticastEvent.AddUObject(this, &AMyActor::MyFunction);
OnMyMulticastEvent.AddLambda([this](){
UE_LOG(LogTemp, Warning, TEXT("Multicast Lambda function called!"));
});
}
void AMyActor::SomeEventOccurs()
{
// 실행 (모든 바인딩된 함수가 순차적으로 호출됨)
OnMyMulticastEvent.Broadcast();
//Clear를 통해 모든 바인딩을 제거
OnMyMulticastEvent.Clear();
//Remove를 통해 특정 함수 바인딩 제거
OnMyMulticastEvent.Remove(this, &AMyActor::MyFunction);
}
- 다이나믹 델리게이트
[선언]
// 헤더 파일 (.h)
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FMyDynamicDelegate);
[사용]
// 헤더 파일 (.h)
UPROPERTY(BlueprintAssignable)
FMyDynamicDelegate OnMyDynamicEvent;
// 소스 파일 (.cpp)
void AMyActor::SomeEventOccurs()
{
OnMyDynamicEvent.Broadcast();
}