UE 4.27 2022 06 20
델리게이트(Deleagte)란?
델리게이트는 호출할 메서드와 선택적으로 메서드를 호출할 개체를 지정합니다. 대리자는 무엇보다도 콜백 빛 이벤트 리스너를 구현하는 데 사용됩니다. 대리자 개체는 메서드에 대한 참조를 캡슐화합니다. 따라서 호출할 메서드를 컴파일 타임에 알 필요 없이 참조된 메서드를 호출할 수 있는 코드에 대리자 개체를 전달할 수 있습니다.
델리게이트를 사용하여 임의 오브젝트의 멤버 함수에 동적으로 바인딩시킬 수 있으며, 그런 다음 그 오브젝트에서 함수를 호출할 수 있습니다.
구독자가 신문사에게 신문을 받아보겠다는 구독 의사를 밝히고 등록하면, 신문이 발행될 때마다 동일한 시간에 구독한 모든 구독자의 집으로 신문을 배달해주듯이, 특정 이벤트가 발생하면 델리게이트에 등록된 모든 함수를 한꺼번에 호출할 수 있습니다.
- 싱글 케스트는 가장 기본적인 Delegate로 함수 1개를 바인드하여 사용합니다.
- 멀티 케스트는 싱글 케스트와 동일하지만 여러 함수를 바인드 할 수 있습니다.
- 이벤트는 멀티 케스트와 동일하지만 전역으로 설정할 수 없어 외부 클래스에서 추가 델리게이트 선언이 불가능합니다.
- 다이나믹은 다이나믹 델리게이트는 직렬화 되어 블루프린트에서 이용가능합니다.
- 블루프린트 오브젝트는 멤버 함수에 대한 정보를 저장하고 로딩하는 직렬화 매커니즘이 있습니다. 따라서 블루프린트에서 델리게이트를 연동하기 위해서는 다이나믹 델리게이트를 필요로 합니다.
- 직렬화(Serialization)이란 정보를 다른 환경에서 불러와 동일한 상황으로 만드는 기법으로 언리얼에서 직렬화의 동작은 2단계로 구분됩니다.
- 객체와 속성 정보를 저장, 보관 -> 패키징
- 데이터가 필요한 플랫폼에서 패키징 데이터를 로딩
델리게이트 선언하기
델리게이트의 선언은 제공되어 있는 선언 매크로중 하나를 사용하여 이루어집니다. 사용되는 매크로는 델리게이트에 바인딩되는 함수의 시그니처에 따라 결정됩니다. 시스템에서는 델리게이트 유형을 선언해 낼 수 있는 범용 함수 시그너처의 다양한 조합을 미리 정의, 이를 통해 반한값과 파라미터에 대한 유형 이름을 채웁니다.
// CoreMinimal에서 include되어 있습니다.
//#include "Delegates/DelegateCombinations.h" 입니다.
델리게이트 선언 매크로는 델리게이트 선언하기에서 읽을 수 있습니다.
- …\Engine\Source\Runtime\Core\Public\Delegates\DelegateCombinations.h 에서 선언을 확인 할 수 있습니다.
델리게이트 바인딩하기
델리게이트 오브젝트는 복사할 수 있으며, 값으로 전달 가능하나 heap 메모리를 할당하기 때문에 참조로 전달하는 것이 바람직합니다.
델리게이트는 싱글-캐스트와 멀티 캐스트 모두 지원되며, 디스크에 안전하게 Serialize 시킬 수 있는 다이내믹 델리케이트도 지원합니다.
- Bind는 기존 델리게이트 오브젝트에 바인딩합니다.
- BindState은 raw C++ 포인터 글로벌 함수 델리게이트를 바인딩합니다.
- BindRaw는 raw C++ 포인터를 델리게이트에 바인딩합니다. 날 포인터는 어떠한 종류의 레퍼런스도 사용하지 않아, 만약 오브젝트가 델리게이트에 아래에서 삭제될 경우 안전하지 않을 수 있습니다.
- BindSP는 공유 포인터 기반 멤버 함수를 델리게이트에 바인딩합니다. 공유 포인터 델리게이트는 오브젝트로의 약한 레퍼런스를 유지합니다.
- BindUObject는 UObject기반 멤버 함수를 델리게이트에 바인딩합니다. UObject 델리게이트는 오브젝트로의 약한 레퍼런스를 유지합니다.
- UnBind는 바인딩을 제거합니다.
\Engine\Source\Runtime\Core\Public\Templates\DelegateSignatureImpl.ini에서 확인할 수 있습니다.
델리게이트 사용하기
- 콜백, 이벤트에 많이 사용됩니다.
- 발행/구독 모델처럼 사용할 때는 MULTICAST계열 매크로를 사용합니다.
- 델리게이트는 모든 유형의 함수에 사용할 수 없습니다.
- 바인딩할 성격에 따라 다양한 API가 존재합니다.
- Create함수를 사용해서 즉석에서 델리게이트를 제작해 넘겨주는 것도 가능합니다.
- 블루프린트와 연동시에는 DYNAMIC_MULTICAST계열 매크로를 사용합니다.
콜백을 지정하는 Delegate를 사용할 때 주의사항
- Delegate는 함수가 바인딩 되어 있는지 확인하는 IsBound()함수가 있습니다.
- 바인드 되지 않은 델리게이트를 Execute() 혹은 Broadcast()시 런타임 에러가 발생합니다.
- Clear()는 바인드 된 함수를 모두 제거하는 데 바인드된 함수가 없어도 런타임 에러가 발생하지 않습니다.
- Dlegate로 설정할 바탕 함수는 UFUNCTION으로 등록해 에진이 찾을 수 있어야 합니다.
델리게이트에 바인딩된 함수는 델리게이트의 Execute()함수를 호출하여 실행됩니다. 델리게이트를 실행하기 전 “바인딩”되었는지 반드시 확인해야 합니다.
몽타주 재생을 C++로 실행할 때
애님 인스턴스 클래스에 선언되어 있는 델리게이트를 사용할 수 있습니다.
{
Montage_Play(..., 1.0f);
FOnMontageEnded BlendOutDelegate;
BlendOutDelegate.BindUObject(this, &UObject::Func);
Montage_SetBlendOutDelegate(BlendOutDelegate, rollMontage);
FOnMontageBlendingOutStarted CompleteDelegate;
CompleteDelegate.BindUObject(this, &UPlayerAnimINstance::RollMontageComplete);
Montage_SetEndDelegate(CompleteDelegate, rollMontage);
}
FScriptDelegate이란
UFUNCTION(BlueprintCallable)
void PlayMainMenuToPrepareAnimation()
{
UnbindAllFromAnimationFinished(MainMenuToPrepareAnimation);
FScriptDelegate StartScriptDelegate;
StartScriptDelegate.BindUFunction(this, FName("Prepare"));
BindToAnimationStarted(MainMenuToPrepareAnimation, FWidgetAnimationDynamicEvent(StartScriptDelegate));
UnbindAllFromAnimationFinished(MainMenuToPrepareAnimation);
FScriptDelegate FinishScriptDelegate;
FinishScriptDelegate.BindUFunction(this, FName("PlayReadyToPlayAnimation"));
BindToAnimationFinished(MainMenuToPrepareAnimation, FWidgetAnimationDynamicEvent(FinishScriptDelegate));
PlayAnimation(MainMenuToPrepareAnimation);
}
UFUNCTION(BlueprintCallable)
void PlayMainMenuToExitAnimation()
{
UnbindAllFromAnimationFinished(MainMenuToExitAnimation);
FScriptDelegate FinishScriptDelegate;
FinishScriptDelegate.BindUFunction(this, FName("ExitGame"));
BindToAnimationFinished(MainMenuToExitAnimation, FWidgetAnimationDynamicEvent(FinishScriptDelegate));
PlayAnimation(MainMenuToExitAnimation);
}
FScriptDelegate 어디다 사용하는지 궁금함.
Binding blueprint method/event to C++ delegate
UPROPERTY(BlueprintAssignable)
FExampleDelegate_OnSomething ExampleDelegateVariable;
- Delegate는 Object에 있어야 합니다. Struct에 구현하면, 블루프린트에서 통신하기 위해서 직접 감싸야 합니다.
델리게이트를 호출할 때는 IsBound를 검사해야 합니다.