1.델리게이트(Delegate)란?
- 델리게이트는 특정 이벤트가 발생했을 때 호출될 함수를 지정하는 방식입니다. 이는 C++의 함수 포인터와 유사하지만 더 안전하고 유연합니다
- 델리게이트와 이벤트 시스템의 차이점
- 델리게이트는 함수 포인터의 역할을 하며, 특정 시점에 함수를 호출할 수 있게 합니다.
- 이벤트는 델리게이트를 기반으로 하며, 여러 개의 델리게이트를 바인딩하여 특정 이벤트 발생 시 여러 함수를 호출할 수 있습니다.
- 델리게이트의 활용 예제
- UI 버튼 클릭 이벤트 처리: UI 버튼이 클릭되었을 때 특정 함수를 호출하도록 설정.
- 캐릭터 상태 변경: 캐릭터의 상태가 변경될 때마다 해당 상태에 맞는 함수를 호출.
- 델리게이트의 메모리 관리
- 델리게이트는 자동으로 메모리를 관리하지만, 바인딩된 객체가 소멸될 때 바인딩을 해제하는 것이 중요합니다.
1) 델리게이트의 종류
Single-cast Delegate:
- 하나의 함수만을 호출(바인딩)하는 델리게이트입니다.
- 비교적 가볍고 성능이 뛰어납니다
- 컴파일 타임에 바인딩되어야 하며, 런타임에 바인딩을 변경할 수 없습니다.
사용시기
- 이벤트가 발생했을 때 한 가지 작업만 수행해야 할 때.
- 성능이 중요한 상황에서 델리게이트를 사용할 때.
- 런타임에 델리게이트 바인딩을 변경할 필요가 없을 때.
기본형태
// 델리게이트 선언
DECLARE_DELEGATE(FSimpleDelegate);
// 델리게이트 변수 정의
FSimpleDelegate MyDelegate;
// 함수 바인딩
MyDelegate.BindUObject(this, &MyClass::MyFunction);
// 델리게이트 호출
MyDelegate.ExecuteIfBound();
Multi-cast Delegate:
- 여러 개의 함수를 바인딩할 수 있습니다.
- 한 번의 이벤트 발생 시 여러 개의 콜백을 실행할 수 있습니다.
- 컴파일 타임에 바인딩되어야 하며, 런타임에 바인딩을 변경할 수 없습니다.
사용시기
- 이벤트가 발생했을 때 여러 작업을 동시에 수행해야 할 때.
- 여러 객체가 같은 이벤트를 청취하고 반응해야 할 때.
- 런타임에 델리게이트 바인딩을 변경할 필요가 없을 때.
기본형태
// 델리게이트 선언
DECLARE_MULTICAST_DELEGATE(FSimpleMulticastDelegate);
// 델리게이트 변수 정의
FSimpleMulticastDelegate MyDelegate;
// 함수 바인딩
MyDelegate.AddUObject(this, &MyClass::MyFunction);
// 델리게이트 호출
MyDelegate.Broadcast();
Dynamic (Single or Multi)-cast Delegate:
- 특징
- 블루프린트에서 사용 가능합니다.
- 런타임에 바인딩을 변경할 수 있습니다.
- 싱글캐스트와 멀티캐스트 형태로 모두 사용할 수 있습니다.
- 런타임 성능이 비교적 낮으며, 리플렉션 시스템을 사용합니다.
- 사용 시기
- 블루프린트에서 이벤트를 처리해야 할 때.
- 런타임에 델리게이트 바인딩을 동적으로 변경할 필요가 있을 때.
- 게임 플레이 로직에서 블루프린트와 C++ 간의 상호작용이 필요한 경우.
// 1. 싱글캐스트 다이나믹 델리게이트
// 델리게이트 선언
DECLARE_DYNAMIC_DELEGATE(FSimpleDynamicDelegate);
// 델리게이트 변수 정의
FSimpleDynamicDelegate MyDelegate;
// 함수 바인딩
MyDelegate.BindDynamic(this, &MyClass::MyFunction);
// 델리게이트 호출
MyDelegate.ExecuteIfBound();
// 2. 멀티캐스트 다이나믹 델리게이트
// 델리게이트 선언
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSimpleDynamicMulticastDelegate);
// 델리게이트 변수 정의
FSimpleDynamicMulticastDelegate MyDelegate;
// 함수 바인딩
MyDelegate.AddDynamic(this, &MyClass::MyFunction);
// 델리게이트 호출
MyDelegate.Broadcast();
2) 파라미터가 있는 델리게이트
각각 델리게이트는 파라미터의 개수에 따라서 선언하는 형태가 다음과 같이 달라진다
//---------------------------SingleCast----------------------------------
//1. 기본형태
DECLARE_DELEGATE(FSimpleDelegate); // 함수인자 없는 함수 호출
//2. 파라미터가 있는 형태
DECLARE_DELEGATE_OneParam(FOneParamDelegate, int32); // 함수인자가 하나인 파라미터 호출
DECLARE_DELEGATE_TwoParams(FTwoParamsDelegate, int32, float);
DECLARE_DELEGATE_ThreeParams(FThreeParamsDelegate, int32, float, FString);
//....
//-------------------------------MultiCast-------------------------------
//1. 기본형태
DECLARE_MULTICAST_DELEGATE(FSimpleMulticastDelegate);
//2. 파라미터가 있는 형태
DECLARE_MULTICAST_DELEGATE_OneParam(FOneParamMulticastDelegate, int32);
DECLARE_MULTICAST_DELEGATE_TwoParams(FTwoParamsMulticastDelegate, int32, float);
DECLARE_MULTICAST_DELEGATE_ThreeParams(FThreeParamsMulticastDelegate, int32, float, FString);
//...
//--------------------------Dynamic---------------------------
//1. 싱글캐스트 다이나믹 델리게이트
DECLARE_DYNAMIC_DELEGATE(FSimpleDynamicDelegate);
//2. 멀티캐스트 다이나믹 델리게이트
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSimpleDynamicMulticastDelegate);
//3. 파라미터가 있는 다이나믹 델리게이트
DECLARE_DYNAMIC_DELEGATE_OneParam(FOneParamDynamicDelegate, int32);
DECLARE_DYNAMIC_DELEGATE_TwoParams(FTwoParamsDynamicDelegate, int32, float);
DECLARE_DYNAMIC_DELEGATE_ThreeParams(FThreeParamsDynamicDelegate, int32, float, FString);
//4. 파라미터가 있는 다이나믹 멀티개스트 델리게이트
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOneParamDynamicMulticastDelegate, int32);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FTwoParamsDynamicMulticastDelegate, int32, float);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FThreeParamsDynamicMulticastDelegate, int32, float, FString);
델리게이트 호출시 파라미터에 값을 입력하기
//example
MyDelegate.Broadcast(42);
그 외 함수를 바인딩 할 수 있는 여러가지 방법들
FSimpleDelegate MyDelegate;
MyDelegate.BindUObject(this, &MyClass::MyFunction); // 외부 클래스 레퍼런스 참조 후 멤버 함수 호출 // 기본형태
MyDelegate.BindUFunction(this, FName("MyFunctionWithParam")); // 클래스 내부 함수 이름으로 호출
2)실제 사용 예제
여기서 하나의 간단한 예제를 통해 델리게이트를 구현해 보겠습니다.
Step 1: 델리게이트 선언 및 바인딩
먼저, MyActor 클래스에서 델리게이트를 선언하고 바인딩해 보겠습니다.
// MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnSomethingHappened);// 델리게이트 선언
UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
GENERATED_BODY()
// ... 생략//
UPROPERTY(BlueprintAssignable, Category = "Events")
FOnSomethingHappened OnSomethingHappened; // 델리게이트 변수로 선언
void TriggerEvent();
};
// MyActor.cpp
#include "MyActor.h"
// 트리거 이벤트 함수가 호출될때, 델리게이트 실행
void AMyActor::TriggerEvent()
{
OnSomethingHappened.Broadcast();
}
이제 다른 클래스에서 해당 델리게이트에 함수를 바인딩하고 이벤트를 발생시켜 보겠습니다.
// 다른 액터(여기서는 MyOtherActor로 이름지음)에서 델리게이트를 선언한 헤더파일을 참조 MyActor.h
// MyOtherActor.cpp
#include "MyOtherActor.h"
#include "MyActor.h"
void AMyOtherActor::BeginPlay()
{
Super::BeginPlay();
// MyActor 인스턴스를 찾고 델리게이트 바인딩
for (TActorIterator<AMyActor> It(GetWorld()); It; ++It)
{
AMyActor* MyActor = *It;
if (MyActor)
{
MyActor->OnSomethingHappened.AddDynamic(this, &AMyOtherActor::OnMyActorSomethingHappened);
// 여기에서 바인딩할 함수를 지정
}
}
}
void AMyOtherActor::OnMyActorSomethingHappened()
{
// 이벤트 발생 시 실행될 코드
UE_LOG(LogTemp, Warning, TEXT("Something happened in MyActor!"));
}
델리게이트의 내부 코드를 따라가보자
DECLARE_DELEGATE(FSuccessConnect); //델리게이트 선언
-------f12---------->
/** Declares a delegate that can only bind to one native function at a time */
#define DECLARE_DELEGATE( DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, void )
// 아하 여기서 보면 #define으로 델리게이트 매크로를 전처리 했다.
//여기서의 실제 몸체는 FUNC_DECLARE_DELEGATE 매크로에 있는 것을 확인할 수 있다..
-------f12---------->
/**
* Declares a delegate that can only bind to one native function at a time
*
* @note: The last parameter is variadic and is used as the 'template args' for this delegate's classes (__VA_ARGS__)
* @note: To avoid issues with macro expansion breaking code navigation, make sure the type/class name macro params are unique across all of these macros
*/
#define FUNC_DECLARE_DELEGATE( DelegateName, ReturnType, ... ) \
typedef TDelegate<ReturnType(__VA_ARGS__)> DelegateName;
// 여기서도 전처리된 FUNC_DELCARE_DELGATE를 볼 수 있다.
//typedef를 활용해서 델리게이트의 구현부를 작성했다.
//그럼 TDelegate는 도대체뭘까?-------f12---------->
/**
* Unicast delegate template class.
*/
template <typename DelegateSignature, typename UserPolicy = FDefaultDelegateUserPolicy>
class TDelegate
{
static_assert(sizeof(UserPolicy) == 0, "Expected a function signature for the delegate template parameter");
};
// 클래스로 static_asset를 가지고 있다.
//template를 활용하여 DelegateSignature를 활용하자
'개발이야기 > 언리얼 c++' 카테고리의 다른 글
언리얼 C++: TScriptInterface (0) | 2024.05.28 |
---|---|
언리얼 C++ : Ensure와 EnsureMsgf란? (0) | 2024.05.27 |
언리얼 C++: #define (0) | 2024.05.24 |
언리얼 C++ : typedef와 typedef struct는 왜 사용하는 걸까? (1) | 2024.05.24 |
언리얼C++: MINIMAL_WINDOWS_API란? (0) | 2024.05.24 |