게임 엔진/Unreal

[Unreal] [Example] C++에서 Blueprint 호출, Blueprint에서 C++ 호출

AlgorFati 2020. 11. 16. 15:52

1. C++에서 Blueprint 함수를 호출하는 방법

UFUNCTION(BlueprintImplementableEvent, Category = "Blueprint")
void K2_CreatePickupWidget(AActor* InOwner, TSubclassOf<UUserWidget> WidgetClass, APickupActor* PickupActor);
    
void CreatePickupWidget(AActor* InOwner, TSubclassOf<UUserWidget> WidgetClass, APickupActor* PickupActor)
{
	K2_CreatePickupWidget(InOwner, WidgetClass, PickupActor);
}

이후 구체적인 구현은 상속된 blueprint 에서 마무리 지어준다.

호출은 c++에서 가능하다.

 

 

 

2. Blueprint 에서 C++ 함수를 호출하는 방법

UFUNCTION(BlueprintCallable)
bool IsRotateOnPressed() const { return bRotateOnPressed; }

 

 

3. Blueprint에서 C++함수를 override 하는 방법

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, meta = (DisplayName = "OnHit", ScriptName = "OnHit"), Category = "Hittable")
    void K2_OnHit(float InDamage, int InHitIdx);

virtual void K2_OnHit_Implementation(float InDamage, int InHitIdx) override { OnHit(InDamage, InHitIdx); }

구체적인 구현은 c++에서 마무리 지어둔다.

호출은 blueprint에서 가능하다.

 

 

 

4. 어떤 객체가 C++ 에서 다른 객체로부터 생성되어 값이 초기화되고,

Blueprint 에서 초기화 과정에 관여해야하는 경우

c++ 레벨에서 어떤 객체를 다른 객체로부터 생성시키는 경우, 값을 세팅시키면서 생성시킬 방법이 없다.

(Blueprint에서는 가능하지만, c++에서는 불가능)

그러므로, 생성시킨 후 값을 세팅하도록 하는 방향으로 설계를 하는데,

이 경우 BeginPlay의 호출이 값 세팅보다 빠르기 때문에,

값 세팅이 되지 않은 상태로 초기화 로직이 수행되고, 이는 문제를 일으킨다.

 

그렇기 때문에 외부로부터 생성&세팅되는 객체의 경우 BeginPlay의 사용을 자제하고,

새로운 초기화 함수(NativeInit)를 만들도록 한다. 

하지만 여전히 문제가 남아있다.

c++ 레벨에서 virtual로 사용되는 함수는 blueprint 레벨에서 override되지 못하기 때문에, 혹은 다른 방향으로 가능하더라도 코드가 매우 지저분해지기 때문에, blueprint 레벨에 지원할 새로운 통로가 필요하다. 

그러므로 K2_Init이라는 blueprint용 함수를 지원하고, NativeInit과 K2_Init을 감싸는 새로운 Init함수를 구현한다.

NativeInit은 c++ 내부 override를 위한 함수이므로 private으로 숨겨주고,

K2_Init은 blueprint에서 override를 위한 함수이므로 public으로 빼 준다.

Init은 c++에서 자유롭게 호출될 초기화 함수이므로 public으로 빼 준다.

 

 

생성될 객체

UCLASS()
class AAbilityBase : public AActor
{
GENERATED_BODY()
//..
protected:
	// c++ 레벨에서 사용될 초기화 함수
	// 이 객체가 다른 객체로부터 생성된 후에 따로 호출해준다.
	virtual void NativeInit(UAbilityComponent* InAbilityComponent);
    
public:
	// blueprint 레벨에서 사용될 초기화 함수
	// blueprint 제작 후 이 함수를 override 한다.
	// 초기화 과정 중에 blueprint에서 해주어야 할 작업을 수행한다.
	UFUNCTION(BlueprintImplementableEvent, Category = "Blueprint", meta = (DisplayName = "Init", ScriptName = "Init"))
	void K2_Init();
    
	// c++ 레벨에서 실질적으로 호출되는 초기화 함수
	// NativeInit을 통해 c++ 레벨의 모든 override된 함수들을 다루고,
	// K2_Init을 통해 blueprint 레벨의 모든 override된 함수들을 다룬다.
	void Init(UAbilityComponent* InAbilityComponent) { NativeInit(InAbilityComponent); K2_Init(); }
//..
}

 

생성할 객체

AAbilityBase* Ability = GetWorld()->SpawnActor<AAbilityBase>(AbilityClass, FTransform::Identity, Params);
Ability->Init(this);

 

Blueprint