관리 메뉴

기억을 위한 기록들

[UE-C++] 델리게이트들과 이벤트 본문

UnrealEngine/UnrealEngine C++ 관련

[UE-C++] 델리게이트들과 이벤트

에드윈H 2022. 12. 1. 20:33

 

https://docs.unrealengine.com/4.26/ko/ProgrammingAndScripting/ProgrammingWithCPP/UnrealArchitecture/Delegates/

 

 

먼저 Delegate의 사전적 의미로는 "대리자 혹은 위임자" 라는 뜻이 있다.

 


델리게이트

설명 : Delegate (델리게이트)로 C++ 오브젝트 상의 멤버 함수 호출을 일반적이고 유형적으로 안전한 방식으로 할 수 있습니다.
델리게이트를 사용하여 임의 오브젝트의 멤버 함수에 동적으로 바인딩시킬 수 있으며, 그런 다음 그 오브젝트에서 함수를 호출할 수 있습니다. 호출하는 곳에서 오브젝트의 유형을 몰라도 말이지요.

델리게이트 오브젝트는 복사해도 완벽히 안전하다.

델리게이트는 값으로 전달 가능하나 보통 추천할 만 하지는 않는데, heap 에 메모리를 할당해야 하기 때문입니다. 가급적이면 델리게이트는 항상 참조 전달해야 합니다.

델리게이트는 싱글-캐스트(형 변환)와 멀티-캐스트 모두 지원되며, 디스크에 안전하게 Serialize 시킬 수 있는 "다이내믹" 델리게이트도 물론입니다.

1. 선언 방법

DECLARE_DELEGATE_<N>Params(DelegateName, const FString&, const int);

- DECLARE_DELEGATE - 전달값 X

- DECLARE_DELEGATE_<N>Params- 전달값 N개

  • DECLARE_DELEGATE_<N>Params 으로 N이 숫자를 영어로 One,Two,Three… 이렇게 올라가면서 Nine인 9개까지 가능하다.

2-1. 사용 예)

DECLARE_DELEGATE_TwoParams(DeleMyFunction, const FString&, const int);
//MyClass.h

public:
DeleMyFunction myDelegate;
myDelegate.BindStatic(&SomethingClass::OnReceivedDelegateStaticFunction); //static 함수
myDelegate.BindUObject(this, &MyClass::SomethingFunction); //UOject 기반 멤버함수/..

등등… 바인딩 방법은 상황에 따라 다양하고 필요 해제 시 UnBind 해줘야 한다…

 
DeleMyFunction somethingDelegate;
somethingDelegate.BindLambda([](const FString& str, const int number)
			{
				//DoSomething;
			});

실행시

myDelegate.execute(TEXT("Hellow",32);

이렇게 실행을 어디선가 받게 된다면 Bind 된 곳들에서 수신(?)받는다.

실행방법

Execute(); //실행한다

ExecuteIfBound(); //Bind 되어있는지 확인 후 실행

IfBound(); //Bind 되어있는지 상태 확인 return bool

DECLARE_DELEGATE_RetVal_TwoParams (이 글을 쓴이유.. RetVal 때문에 헷갈려서 정리 겸 작성한다…)

2-2 사용 예)

DECLARE_DELEGATE_RetVal_TwoParams(bool,MyDelegateWithRet, const FString&, const FFileDeliveryClothPath&);
MyDelegateWithRet somethingDelegate;
somethingDelegate.BindLambda([](const FString& str, const int number)/* -> bool  return 값 표현 생략가능*/
			{
				//DoSomething;
				
				return true;
			});

이렇게 값을 return 해줄 수 있다.

그렇게 된다면 호출 한 곳에서

bool bSucceed = anotherDelegate.execute(TEXT(“Hellow“), 32);

Bind 함수의 return 값을 이렇게 받을 수 있다.

하지만 잠깐 사용 결과 디버깅이 복잡해지고, 의도치 않은 결과를 가져올 수 있다… 유용한 듯 하지만 사용할거면 잘 사용해야한다.

실행방법

Execute(); //Retval은 ExecuteIfBound 사용을 못한다.

IfBound(); // 확인만 따로 해줘야한다.

 


멀티캐스트 델리게이트

DECLARE_MULTICAST_DELEGATE

위의 Delegate와 거의 동일하다. 그러나 Retval(반환값 지정)은 안된다.

그런데 멀티라는 이름이 붙은것처럼 한 Delegate의 여러 함수를 바인딩하여 실행 시킬 수 있다.

 

하지만 여기도 이상하게도 AddLambda 및 AddWeakLambda에 대한 설명이 없다. 이것도 선언 방법은 그냥 델리게이트와 거의 유사 하긴하다

DECLARE_MULTICAST_DELEGATE_TwoParams(MyMultiDelegate, const FString&, const FFileDeliveryClothPath&);
MyMultiDelegate somethingDelegate;
somethingDelegate.AddLambda([](const FString& str, const int number)
			{
				//DoSomething;			
			});
anotherDelegate.execute(TEXT(“Hellow MultiCast“), 29);

결론: 그냥 델리게이트멀티캐스트 델리게이트는 거의 같은데, 그냥 델리게이트는 Bind 라는 명칭으로 추가해주고, 멀티캐스트 델리게이트는 여러개를 할 수 있다보니 Add라는 수식어로 함수를 붙여서 사용한다.

실행방법

Broadcast(); // 전파한다의 이 델리게이트를 만료되었을 수도 있는 것을 제외하고, 바인딩된 모든 오브젝트에 뿌립니다.

이벤트

DECLARE_EVENT

  1. 어느 클래스도 이벤트 바인딩이 가능하지만, 이벤트를 선언한 클래스만이 이벤트의 Broadcast, IsBound, Clear 함수를 호출가능. 즉, 이벤트가 사용되는 곳은, 순수 추상 클래스의 콜백 포함하기, 외부 클래스의 Broadcast, IsBound, Clear 함수 호출 제한시키기 입니다.
  2. 선언방법
DECLARE_EVENT_OneParam( OwningType /*소유 클래스 or 인터페이스*/, EventName, Param1Type )

DECLARE_EVENT_<N>Params 으로 N이 숫자를 영어로 One,Two,Three… 이렇게 올라가면서 9(Nine)까지 가능하다.

사용 ex)

DECLARE_EVENT_NineParams(UMyCommonPopup, ENineEvent,bool one, bool two, bool three, bool four, bool five, bool six, bool seven, bool eight, bool nine );
/* AActor.h */

public:
  	ENineEvent&	GetNineTestCallBack() { return _TestEventNine; }
private:
  	ENineEvent _TestEventNine;
/*Another class */

AActor* myActor;

//...

myActor->GetNineTestCallBack().AddWeakLambda(this, [this](bool one, bool two, bool three, bool four, bool five, bool six, bool seven, bool eight, bool nine)
		{
			/*Do Something*/
		});

발견한점 : EventName이 F로 시작 해야 하는 줄 알았는데 아니 였다. 기준 같은 건 없다

3. 실행방법 ex)

_TestEventNine.Broadcast();

다이나믹 델리게이트 / 다이나믹 멀티캐스트 델리게이트

- DECLARE_DYNAMIC_DELEGATE
- DECLARE_DYNAMIC_MULTICAST_DELEGATE

 

이 두개는 다이나믹이라는 수식어가 붙은이유로 serialize 가능하면서 리플렉션도 지원하는 델리게이트라서 그렇다.

다이나믹은 블루프린트 객체에서도 호출 및 사용 가능하다.

그래서 바인딩되는 함수를 블루프린트에서도 할수 있고, C++에서도 할 수 있는데 C++에서 할 경우 UFUNCTION을 지정 해줘야한다.

(블루프린트 객체는 멤버함수에 대한 정보를 저장하고 로딩하는 직렬화 매커니즘이 들어있기 때문에 일반 c++ 언어가 관리하는 방법으로 멤버함수를 관리할 수 없다. Bind 및 Add말고 BindDynamic과 AddDynamic를 사용한다.

사용 예)

DECLARE_DYNAMIC_DELEGATE(FDynamicDele)
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDynamicMultiDele)

UCLASS()
class TestProject_API ASampleActor : public AActor
{
	GENERATED_BODY()
    
public :
	FDynamicDele OnAttackStartDelegate;
	FDynamicMultiDele OnAttackEndDelegate;
};
USampleAnim::NativeInitializeAnimation()
{
	Super::NativeInitializeAnimation();
    
    ASampleActor* pActor = Cast<ASampleActor>(TryGetPawnOwner());
    
    pActor->OnAttackStartDelegate.BindDynamic(this, &USampleAnim::AttackStart); //이 함수들은 UFUNCTION() 이 있어야한다.
    
    pActor->OnAttackEndDelegate.AddDynamic(this, &USampleAnim::AttackEnd); //이 함수들은 UFUNCTION() 이 있어야한다.
    pActor->OnAttackEndDelegate.AddDynamic(this, &USampleAnim::UpdatePlayer); //이 함수들은 UFUNCTION() 이 있어야한다.
    pActor->OnAttackEndDelegate.AddDynamic(this, &USampleAnim::UpdatePlayerStat); //이 함수들은 UFUNCTION() 이 있어야한다.
}

다이나믹 델리게이트의 실행방법

실행방법

Execute(); //실행한다

ExecuteIfBound(); //Bind 되어있는지 확인 후 실행

IfBound(); //Bind 되어있는지 상태 확인 return bool

멀티캐스트 다이나믹 델리게이트의 실행방법

실행방법

Broadcast(); // 전파한다의 이 델리게이트를 만료되었을 수도 있는 것을 제외하고, 바인딩된 모든 오브젝트에 뿌립니다.

서칭한 결과 이렇게 블루프린트 객체와도 연동하는 델리게이트를 다이내믹 델리게이트라고 하고,

다이내믹 델리게이트는 이러한 동작원리 때문에 일반 델리게이트보다 다소 느릴 수 있습니다.

BP에서도 호출 및 bind 할수있다

 

 

 

https://dokuro.moe/ue4-cpp-how-to-use-delegate/

 

【UE4 C++】デリゲートの使い方まとめ | ドクロモエ

この記事では、Unreal Engine の C++ でデリゲートを扱う方法についてまとめています。 執筆時に扱った Unreal Engine のソースコードのバージョンは 4.25.4 プラットフォームは Windows 10 (64ビット版)

dokuro.moe

 

https://darkcatgame.tistory.com/66

 

UE4 C++ Delegate 정리 & 샘플 프로젝트

개인적으로 UE4 C++에서 Delegate를 사용할 때 처음에 굉장히 에러를 많이 겪었습니다, 그래서 이번 포스팅은 UE4 C++에서 Delegate를 사용하는 방법에 대해 정리하고 샘플프로젝트도 만들었습니다. https

darkcatgame.tistory.com