UE UFUNCTION(BlueprintNativeEvent)

 BlueprintNativeEvent : would have the C++ and Blueprint version.

 BlueprintImplementableEvent : only has a Blueprint version.

 BlueprintCallable : create function which is callable in Blueprint.


0. 서문

이 글을 읽기에 앞서, UE4의 Reflection에 대한 이해가 없다면, 꼭 아래 문서부터 읽도록 하자.

함수는 일반 C++ 함수와 UFUNCTION, 두 가지의 기본적 형태로 존재 가능하다.
UFUNCTION은 전용 문법이 있어, 함수 지정자를 통해 함수에 대한 부가 정보를 선언부에 지정할 수 있다.

  1. UFUNCTION([specifier, specifier, ...][meta(key=value, key=value, ...)])
  2. ReturnType FunctionName([Parameter, Parameter, ...])

UE4의 함수 전반적인 내용과 모든 specifier, meta에 대한 내용은 아래 문서를 참고하기 바란다.

이후 문서엔 자주 사용되는 specifier 위주로만 조금 더 자세히 정리하였다.
(UFUNCTION specifier 열거값들은 ObjectMacro.h의 namespace UF에서 확인할 수 있다)


1. BlueprintPure

(const) getter의 성격에 해당하는 함수를 블루프린트 그래프에 노출시킬 때 사용하면 된다.

  1. // Return whether or not the pickup is active
  2. UFUNCTION(BlueprintPure, Category = "Pickup")
  3. bool IsActive() const { return bIsActive; }


2. BlueprintCallable

블루프린트 그래프에서 실행 가능한 가장 일반적인 specifier.
C++의 구현 내용을 블루프린트에서 재정의할 수 없으며, 호출만 가능하기에 대체적으로 setter 성격의 함수에 많이 사용된다.

  1. // Set the pickup active or not
  2. UFUNCTION(BlueprintCallable, Category = "Pickup")
  3. void SetActive(bool active) { bIsActive = active; }


3. BlueprintNativeEvent

C++ 네이티브 구현이 존재하지만, 필요시 블루프린트에서 override 할 수 있게 해주는 지정자이다.
UHT는 해당 함수의 블루프린트 재지정이 존재하면 블루프린트의 그것을, 존재하지 않으면 C++의 함수가 호출되도록 처리해준다.

[FunctionName] 대신 [FunctionName]_Implementation 이라는 이름의 바디를 제공해 주고, 자동 생성 코드에는 필요할 때 구현 메쏘드를 호출하는 썽크가 포함된다.

예제부터 먼저 살펴보는 것이 나을 듯 하다.

  1. // Pickup.h
  2. UCLASS(Abstract)
  3. class BATTERYCOLLECTOR_API APickup
  4. : public AActor
  5. {
  6.    // ...
  7.  
  8.    // Declaration - 딱 이런 형식이다
  9.    UFUNCTION(BlueprintNativeEvent)
  10.    void OnCollection();
  11.    virtual void OnCollection_Implementation();
  12.  
  13.    // ...
  14. };
  15.  
  16. // BatteryPickup.h
  17. UCLASS()
  18. class BATTERYCOLLECTOR_API ABatteryPickup
  19. : public APickup
  20. {
  21.     // ...
  22.  
  23.     // Declaration
  24.     // OnCollection의 오버라이드
  25.     // OnCollection 함수가 BlueprintNativeEvent이기에 Implementation을 오버라이드 한다
  26.     // BlueprintNativeEvent 함수는 반드시 _Implementation suffix가 붙은 가상 함수를 추가해 줘야 한다.
  27.     virtual void OnCollection_Implementation() override;
  28.  
  29.     // ...
  30. };
  31.  
  32. // Pickup.cpp
  33. // Definition : [FunctionName]_Implementation()만 정의
  34. void APickup::OnCollection_Implementation()
  35. {
  36.     FString pickupDebugString = GetName();
  37.     UE_LOG(LogClass, Log, TEXT("You have collected %s")*pickupDebugString);
  38. }
  39.  
  40. // BatteryPickup.cpp
  41. // Definition : [FunctionName]_Implementation()만 정의
  42. void ABatteryPickup::OnCollection_Implementation()
  43. {
  44.     Super::OnCollection_Implementation();
  45.  
  46.     Destroy();
  47. }
  48.  
  49.  
  50. // BatteryCollectorCharacter.cpp
  51. void ABatteryCollectorCharacter::TryCollectPickups()
  52. {
  53.     // ...
  54.  
  55.     for (auto actor : collectedActor)
  56.     {
  57.         if (APickup* pickup = Cast<APickup>(actor))
  58.         {
  59.             // OnCollection_Implementation은 바디이고, 선언은 OnCollection으로 되었으니
  60.             // 함수 호출은 선언된 시그너처를 사용하는 것이 당연지사.
  61.             pickup->OnCollection();
  62.         }
  63.     }
  64.  
  65.     // ...
  66. }

선언 형식이 조금 낯설텐데, 익숙해지는 방법 밖에는 없다.

예제에서 살펴본 형식을 정리하면 다음과 같다.
  • 선언부에 선언형식의 시그너쳐와 바디형식의 시그너쳐를 모두 작성한다.
  • 바디형식의 시그너쳐는 정확하게 "_Implementation" suffix를 가져야 한다.
  • 외부에서의 함수 호출시에는 선언형식의 시그너쳐를 따른다.


4. BlueprintImplementableEvent

이 지정자는 UHT(언리얼 헤더 툴)에게 블루프린트에 의해 구현될 빈 함수를 만들라고 알려준다.
즉, C++에서는 시그너쳐 선언만 하고 내용은 블루프린트에서만 구현 가능케 하는 함수 지정자이다.

  1. UFUNCTION(BlueprintImplementableEvent, Category = Power)
  2. void UpdatePowerEffect();

예제의 UpdatePowerEffect() 함수는 시그너쳐 선언만 C++에서 하고, 바디 구현은 블루프린트에서만 가능하다.
이후, C++에서의 함수 호출은 자유롭다.

댓글

이 블로그의 인기 게시물

About AActor!!! "UObject" has no member "BeginPlay"

UNREAL Android build information

C++ 생성자 위임 (delegating constructor)