* 정의
일반적으로 델리게이트(delegate)는 함수를 안전하게 호출할 수 있는 기능을 의미하며 콜백 및 이벤트 리스너를 구현하는데 사용된다.
언리얼 엔진에서는 바인드 할 수 있는 함수의 수에 따라 싱글, 멀티 캐스트로 구분하며 블루프린트와 연동할 수 있는 다이나믹 델리게이트를 추가로 지원하고 있다.
델리게이트는 객체의 멤버 함수에 동적으로 바인딩 되어 호출자가 객체의 유형을 알지 못해도 나중에 객체의 함수를 호출할 수 있다. 복사에 대해 안전하지만 값으로 넘겨줄 경우 힙에 추가 할당을 하게 되니 참조로 넘겨주는게 좋다.
* 동작 방식
- 선언
언리얼 엔진에서는 델리게이트 타입을 선언하기 위한 여러가지 매크로를 제공한다. 이러한 매크로는 델리게이트 타입의 이름, 반환형, 매개 변수를 포함하고 있으며 상황에 따라 적절한 조합을 사용해야한다.
현재는 다음과 같은 것들을 제공하고 있다.
- 값을 반환하는 함수
- const로 선언된 함수
- 최대 4개의 페이로드 변수
- 최대 8개까지의 함수 매개변수
실제 사용하는 델리게이트 매크로는 다음과 같다.
| 함수 형식 | 델리게이트 타입 선언 매크로 |
| void Function() | DECLARE_DELEGATE(DelegateName) |
| void Function(Param1) | DECLARE_DELEGATE_OneParam(DelegateName, Param1Type) |
| void Function(Param1, Param2) | DECLARE_DELEGATE_TwoParams(DelegateName, Param1Type, Param2Type) |
| void Function(Param1, Param2, ...) | DECLARE_DELEGATE_<Num>Params(DelegateName, Param1Type, Param2Type, ...) |
| <RetValType> Function() | DECLARE_DELEGATE_RetVal(RetValType, DelegateName) |
| <RetValType> Function(Param1) | DECLARE_DELEGATE_RetVal_OneParam(RetValType, DelegateName, Param1Type) |
| <RetValType> Function(Param1, Param2) | DECLARE_DELEGATE_RetVal_TwoParams(RetValType, DelegateName, Param1Type, Param2Type) |
| <RetValType> Function(Param1, Param2, ...) | DECLARE_DELEGATE_RetVal_<Num>Params(RetValType, DelegateName, Param1Type, Param2Type, ...) |
사용 예시는 다음과 같다.
UDELEGATE(BlueprintAuthorityOnly)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FInstigatedAnyDamageSignature, float, Damage, const UDamageType*, DamageType, AActor*, DamagedActor, AActor*, DamageCauser);
Dynamic, Multi-Cast 형식의 델리게이트가 존재하며 이에 대한 설명은 다음과 같다.
https://create-new-worlds.tistory.com/174
[UnrealEngine] Dynamic Delegate, Multicast Delegate
* Dynamic Delegate - 정의 다이나믹 델리게이트는 직렬화될 수 있고 리플렉션을 지원하는 델리게이트이다. 함수들을 이름으로 찾기 때문에 일반적인 델리게이트보다 느리다. - 선언 일반적인 델리게
create-new-worlds.tistory.com
- 바인딩
델리게이트 시스템은 특정 객체 타입에 대해 이해하고 있으며 이를 관리할 때 추가 처리를 해준다.
만약 UObject나 SharedPtr의 멤버에 델리게이트를 바인딩하면 델리게이트는 이를 약 참조(weak reference)로 유지한다. 만약 이러한 객체가 파괴되면 IsBound나 ExecuteIfBound 함수를 호출하여 이를 처리할 수 있다.
바인딩 함수는 다음과 같다.
| 함수 | 설명 |
| Bind | 존재하는 델리게이트 객체에 바인딩한다. |
| BindStatic | 전역 생 함수 포인터를 바인딩한다. |
| BindRaw | 생 포인터를 바인딩한다. 생 포인터는 어떤 참조도 사용하지 않기 때문에 삭제된 객체에 대해 Execute나 ExcuteIfBound를 안전하게 사용할 수 없다. |
| BindLambda | 주로 람다 함수를 바인딩한다. |
| BindSP | 공유 포인터 기반 멤버 함수를 바인딩한다. 공유 포인터 델리게이트는 바인딩한 객체를 약 참조로 관리한다. ExcuteIfBound 함수를 통해 안전하게 사용할 수 있다. |
| BindUObject | UObject 멤버 함수를 바인딩한다. UObject 델리게이트는 해당 UObject를 약 참조로 관리한다. ExcuteIfBound 함수를 통해 안전하게 사용할 수 있다. |
| UnBind | 언바인딩한다. |
- 페이로드
// 페이로드라는 용어를 사용한 이유는 바로 함수 호출에 사용되지 않고 저장되어 실제 함수 호출 때 함수 인자로 전송되기 때문인 것 같다. 페이로드라는 용어로 보아 직렬화된 데이터를 델리게이트 내부에 유지하지 않을까 싶다.
델리게이트에 바인딩할 때 넘겨주는 데이터를 의미하며 바인딩된 함수가 호출될 때 해당 함수로 직접 전달된다. 페이로드는 델리게이트 내부에 저장되며 Dynamic을 제외한 모든 델리게이트에서 자동으로 페이로드 변수를 지원한다. 이러한 추가 인수들은 반드시 델리게이트의 매개변수 인수 뒤에 위치해야한다.
- 실행
델리게이트에 바인딩된 함수는 Execute라는 함수를 통해 호출된다. 실행하기 전에 무조건 델리게이트가 바인딩 되었는 지 확인 해야한다. 이와 같은 방식으로 실행하면 특히 델리게이트에 초기화되지 않고 접근되는 반환값, 출력 매개변수가 있는 경우 더욱 안전하게 처리할 수 있다.
바인딩되지 않은 델리게이트를 수행하면 메모리를 망칠 수 있기 때문에 IsBound 함수를 호출하여 체크 후에 안전하기 Execute를 호출한다. 만약 반환값이 없다면 ExecuteIfBound를 사용할 수 있다.
| 실행 함수 | 설명 |
| Execute | 바인딩 체크를 하지 않고 델리게이트를 실행한다. |
| ExecuteIfBound | 델리게이트가 바인딩되었는 지 확인하고 Execute함수를 호출한다. |
| IsBound | 델리게이트의 바인딩 여부를 체크한다. 보통 Execute함수 전에 호출한다. |
'게임 엔진 > Unreal Engine' 카테고리의 다른 글
| [UnrealEngine] 개발에 필요한 내용 간단 정리 (2) | 2022.10.04 |
|---|---|
| [UnrealEngine] Dynamic Delegate, Multicast Delegate (0) | 2022.04.03 |
| [UnrealEngine] UObject 시스템(UObject System) (0) | 2022.03.30 |
| [UnrealEngine] UObject (0) | 2022.03.30 |
| [UnrealEngine] 속성 지정자(Property Specifiers) (0) | 2022.03.29 |