콘텐츠로 이동

UE5 Blueprint & C++ 연동

Unreal Engine에서 C++와 Blueprint는 긴밀하게 연동됩니다. 엔진 매크로(UFUNCTION, UPROPERTY, UCLASS)를 올바르게 사용하면 C++의 성능과 Blueprint의 유연성을 동시에 활용할 수 있습니다.


Blueprint에서 호출 가능한 C++ 함수를 노출합니다.

UCLASS()
class AMyActor : public AActor
{
GENERATED_BODY()
public:
// Blueprint에서 호출 가능
UFUNCTION(BlueprintCallable, Category="Combat")
void TakeDamage(float Amount);
// Pure Function — 실행 핀 없음 (값 반환만)
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Stats")
float GetHealthPercent() const;
// 월드 컨텍스트 자동 바인딩 (static 함수용)
UFUNCTION(BlueprintCallable, Category="Utils",
meta=(WorldContext="WorldContextObject"))
static AMyActor* SpawnMyActor(UObject* WorldContextObject, FVector Location);
};

C++에서 선언하고 Blueprint에서만 구현하는 이벤트입니다. C++ 바디 없이 선언만 합니다.

// C++ — 선언만 (구현 없음)
UFUNCTION(BlueprintImplementableEvent, Category="Events")
void OnEnemySpotted(AActor* Enemy);
// 호출은 C++에서 가능
void AMyAI::DetectEnemy(AActor* Enemy)
{
OnEnemySpotted(Enemy); // Blueprint가 구현한 이벤트 호출
}

C++ 기본 구현을 제공하고 Blueprint에서 오버라이드 가능하게 합니다.

// 헤더 — 선언 (함수명 그대로)
UFUNCTION(BlueprintNativeEvent, Category="Combat")
float CalculateDamage(float BaseDamage);
// .cpp — 기본 구현 (_Implementation 접미사)
float AMyCharacter::CalculateDamage_Implementation(float BaseDamage)
{
return BaseDamage * DamageMultiplier;
}

Blueprint에서 오버라이드하지 않으면 _Implementation이 호출됩니다.


UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
float MaxHealth = 100.f;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Stats")
float MoveSpeed = 600.f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
UStaticMeshComponent* MeshComp;
지정자에디터 편집Blueprint 접근
EditAnywhere인스턴스·CDO 모두
EditDefaultsOnlyCDO만
EditInstanceOnly인스턴스만
BlueprintReadWrite읽기+쓰기
BlueprintReadOnly읽기만
VisibleAnywhere읽기 전용 표시

인터페이스를 C++로 정의하면 Blueprint와 C++ 모두에서 구현할 수 있습니다.

// 인터페이스 선언
UINTERFACE(MinimalAPI, Blueprintable)
class UInteractable : public UInterface
{
GENERATED_BODY()
};
class IInteractable
{
GENERATED_BODY()
public:
// Blueprint에서 구현 가능
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="Interaction")
void Interact(AActor* Interactor);
};
// C++에서 구현
UCLASS()
class AChest : public AActor, public IInteractable
{
GENERATED_BODY()
public:
virtual void Interact_Implementation(AActor* Interactor) override;
};
void AChest::Interact_Implementation(AActor* Interactor)
{
OpenChest();
}
// 인터페이스 호출 — C++에서
if (Actor->Implements<UInteractable>())
{
IInteractable::Execute_Interact(Actor, this);
}

Dispatch — C++에서 Blueprint 이벤트 바인딩

섹션 제목: “Dispatch — C++에서 Blueprint 이벤트 바인딩”
// 헤더 — Delegate 선언
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float, NewHealth);
UCLASS()
class AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable, Category="Events")
FOnHealthChanged OnHealthChanged;
void SetHealth(float NewHealth)
{
Health = NewHealth;
OnHealthChanged.Broadcast(Health); // Blueprint에서 바인딩한 이벤트 호출
}
private:
float Health = 100.f;
};

Blueprint에서 OnHealthChanged 이벤트 노드에 UI 업데이트 로직을 연결할 수 있습니다.


상황권장 방식
성능 중요 로직C++ 구현, BlueprintCallable로 노출
레벨 디자이너 커스텀BlueprintImplementableEvent
기본값 제공 + 오버라이드 허용BlueprintNativeEvent
시스템 간 결합 제거DECLARE_DYNAMIC_MULTICAST_DELEGATE
컴포넌트 간 통신Blueprint Interface (C++ 정의)

FTableRowBase를 상속한 구조체를 DataTable 에셋과 연동하면 기획자가 에디터/CSV에서 데이터를 편집하고 C++에서 타입 안전하게 읽을 수 있습니다.

ItemData.h
USTRUCT(BlueprintType)
struct FItemData : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FText DisplayName;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MaxStack = 99;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Weight = 0.5f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSubclassOf<AActor> PickupActorClass;
};
// C++에서 DataTable 행 읽기 및 Actor 스폰
UPROPERTY(EditDefaultsOnly, Category = "Data")
TObjectPtr<UDataTable> ItemDataTable;
void AInventoryManager::SpawnItem(FName ItemID, FVector Location)
{
if (!ItemDataTable) return;
static const FString Context(TEXT("SpawnItem"));
FItemData* Row = ItemDataTable->FindRow<FItemData>(ItemID, Context);
if (!Row || !Row->PickupActorClass) return;
GetWorld()->SpawnActor<AActor>(
Row->PickupActorClass, Location, FRotator::ZeroRotator);
}

Blueprint에서는 Get Data Table Row 노드로 동일한 데이터에 접근할 수 있어 C++/Blueprint 간 데이터 공유가 자연스럽습니다.


TSubclassOf — 타입 안전 클래스 참조

섹션 제목: “TSubclassOf — 타입 안전 클래스 참조”

TSubclassOf<T>는 에디터 드롭다운에서 T의 서브클래스만 선택 가능하도록 제한하는 클래스 참조 타입입니다.

UCLASS()
class ASpawner : public AActor
{
GENERATED_BODY()
// 에디터에서 AEnemy 서브클래스만 선택 가능
UPROPERTY(EditDefaultsOnly, Category = "Spawning")
TSubclassOf<AEnemy> EnemyClass;
UPROPERTY(EditDefaultsOnly, Category = "Spawning")
int32 SpawnCount = 3;
public:
void SpawnEnemies()
{
if (!EnemyClass) return;
for (int32 i = 0; i < SpawnCount; ++i)
{
FVector Location = GetActorLocation() +
FVector(FMath::RandRange(-500.f, 500.f), FMath::RandRange(-500.f, 500.f), 0.f);
GetWorld()->SpawnActor<AEnemy>(EnemyClass, Location, FRotator::ZeroRotator);
}
}
};