icon안동민 개발노트

블루프린트에서 C++ 클래스 사용


 C++로 작성된 클래스를 블루프린트에서 확장하고 사용하는 것은 언리얼 엔진의 강력한 기능 중 하나입니다.

 이 절에서는 C++ 클래스를 블루프린트와 효과적으로 통합하는 방법을 살펴보겠습니다.

UCLASS, UPROPERTY, UFUNCTION

 C++ 클래스를 블루프린트에서 사용 가능하게 만들려면 적절한 매크로를 사용해야 합니다.

UCLASS(Blueprintable, BlueprintType)
class MYGAME_API AMyActor : public AActor
{
    GENERATED_BODY()
 
public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MyProperties")
    float MyFloat;
 
    UFUNCTION(BlueprintCallable, Category = "MyFunctions")
    void MyFunction(int32 MyParameter);
 
    UFUNCTION(BlueprintImplementableEvent, Category = "MyEvents")
    void MyBlueprintEvent();
 
    UFUNCTION(BlueprintNativeEvent, Category = "MyEvents")
    void MyNativeEvent();
};
 
void AMyActor::MyFunction(int32 MyParameter)
{
    // 구현...
}
 
void AMyActor::MyNativeEvent_Implementation()
{
    // 기본 구현...
}

블루프린트 상속을 위한 C++ 클래스 설계

 블루프린트에서 쉽게 확장할 수 있는 C++ 클래스를 설계하려면 다음을 고려하세요.

  1. 가상 함수 사용
  2. 보호된(protected) 멤버 변수 활용
  3. 블루프린트 이벤트 제공
UCLASS(Blueprintable)
class MYGAME_API AMyExtendableActor : public AActor
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, Category = "Gameplay")
    virtual void PerformAction();
 
protected:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
    float Health;
 
    UFUNCTION(BlueprintImplementableEvent, Category = "Events")
    void OnActionPerformed();
};
 
void AMyExtendableActor::PerformAction()
{
    // 기본 동작...
    OnActionPerformed();
}

C++ 코드를 블루프린트에서 오버라이드

 블루프린트에서 C++ 함수와 속성을 오버라이드하려면,

  1. 가상 함수로 선언
  2. BlueprintOverride 지정자 사용
UCLASS(Blueprintable)
class MYGAME_API AMyOverridableActor : public AActor
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Overrides")
    void CustomFunction();
 
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Overrides")
    float OverridableValue;
};
 
void AMyOverridableActor::CustomFunction_Implementation()
{
    // 기본 구현...
}

블루프린트에서 C++ 인스턴스 사용

 블루프린트에서 C++ 클래스의 인스턴스를 생성하고 조작하는 방법

  1. 생성자 함수 노출
  2. 팩토리 함수 제공
UCLASS(Blueprintable)
class MYGAME_API UMyObject : public UObject
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, Category = "Factory")
    static UMyObject* CreateMyObject(UObject* Outer);
 
    UFUNCTION(BlueprintCallable, Category = "Manipulation")
    void Initialize(float InitialValue);
};
 
UMyObject* UMyObject::CreateMyObject(UObject* Outer)
{
    return NewObject<UMyObject>(Outer);
}
 
void UMyObject::Initialize(float InitialValue)
{
    // 초기화 로직...
}

C++ 코드와 블루프린트 간의 데이터 교환

 C++와 블루프린트 간의 효율적인 데이터 교환을 위해서는,

  1. 구조체(USTRUCT) 활용
  2. 인터페이스(UINTERFACE) 사용
  3. 데이터 테이블(UDataTable) 활용
USTRUCT(BlueprintType)
struct FMyData
{
    GENERATED_BODY()
 
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FString Name;
 
    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    int32 Value;
};
 
UINTERFACE(MinimalAPI, Blueprintable)
class UMyInterface : public UInterface
{
    GENERATED_BODY()
};
 
class IMyInterface
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
    void ProcessData(const FMyData& Data);
};
 
UCLASS()
class MYGAME_API UMyDataTableFunctionLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, Category = "Data")
    static FMyData GetDataFromTable(UDataTable* DataTable, FName RowName);
};

C++의 블루프린트 확장 시 설계 패턴

  1. 템플릿 메소드 패턴
  2. 전략 패턴
  3. 옵저버 패턴
UCLASS(Blueprintable)
class MYGAME_API AMyGameplayActor : public AActor
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, Category = "Gameplay")
    void ExecuteGameplayLogic();
 
protected:
    UFUNCTION(BlueprintNativeEvent, Category = "Gameplay")
    void PreExecute();
 
    UFUNCTION(BlueprintNativeEvent, Category = "Gameplay")
    void PostExecute();
 
private:
    void ExecuteCore();
};
 
void AMyGameplayActor::ExecuteGameplayLogic()
{
    PreExecute();
    ExecuteCore();
    PostExecute();
}
 
void AMyGameplayActor::PreExecute_Implementation()
{
    // 기본 구현...
}
 
void AMyGameplayActor::PostExecute_Implementation()
{
    // 기본 구현...
}
 
void AMyGameplayActor::ExecuteCore()
{
    // 핵심 로직...
}

C++와 블루프린트 혼용 시의 성능 영향

 C++와 블루프린트를 혼용할 때의 성능 고려사항

  1. 블루프린트는 C++보다 약간 느림
  2. 빈번한 C++-블루프린트 경계 넘나들기 피하기
  3. 성능 중요 로직은 C++로 구현

 성능 최적화 예

UCLASS()
class MYGAME_API UMyOptimizedClass : public UObject
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, Category = "Optimization")
    void PerformBatchOperation(const TArray<AActor*>& Actors);
 
private:
    void ProcessSingleActor(AActor* Actor);
};
 
void UMyOptimizedClass::PerformBatchOperation(const TArray<AActor*>& Actors)
{
    for (AActor* Actor : Actors)
    {
        ProcessSingleActor(Actor);
    }
}
 
void UMyOptimizedClass::ProcessSingleActor(AActor* Actor)
{
    // 최적화된 C++ 로직...
}

디버깅 전략

 C++와 블루프린트 혼용 시 디버깅 전략

  1. C++ 디버거 활용
  2. 블루프린트 비주얼 디버깅 사용
  3. 로깅 및 화면 메시지 활용
UCLASS()
class MYGAME_API UMyDebugHelper : public UObject
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, Category = "Debug")
    static void LogDebugMessage(const FString& Message);
 
    UFUNCTION(BlueprintCallable, Category = "Debug")
    static void DrawDebugSphere(UWorld* World, FVector Center, float Radius, FColor Color, float Duration);
};
 
void UMyDebugHelper::LogDebugMessage(const FString& Message)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *Message);
    GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, Message);
}

대규모 팀에서의 효과적인 협업 방법

  1. 명확한 인터페이스 정의
  2. 문서화 및 주석 작성
  3. 코드 리뷰 및 스타일 가이드 준수

 협업을 위한 C++ 클래스 예

UCLASS(Blueprintable, Abstract)
class MYGAME_API AGameplayActorBase : public AActor
{
    GENERATED_BODY()
 
public:
    UFUNCTION(BlueprintCallable, Category = "Gameplay")
    virtual void PerformAction();
 
    UFUNCTION(BlueprintImplementableEvent, Category = "Gameplay")
    void OnActionCompleted();
 
protected:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay")
    float ActionDuration;
 
    UFUNCTION(BlueprintNativeEvent, Category = "Gameplay")
    void PrepareForAction();
};
 
void AGameplayActorBase::PerformAction()
{
    PrepareForAction();
    // 액션 수행 로직...
    OnActionCompleted();
}
 
void AGameplayActorBase::PrepareForAction_Implementation()
{
    // 기본 준비 로직...
}

 C++로 작성된 클래스를 블루프린트에서 효과적으로 활용하면 개발 효율성과 유연성을 크게 향상시킬 수 있습니다.

 C++의 성능과 타입 안전성, 그리고 블루프린트의 빠른 이터레이션과 시각적 스크립팅의 장점을 모두 활용할 수 있습니다.

 UCLASS, UPROPERTY, UFUNCTION 매크로를 적절히 사용하여 C++ 클래스를 블루프린트에 노출시키고 가상 함수와 이벤트를 통해 블루프린트에서 쉽게 확장할 수 있는 구조를 만드는 것이 중요합니다.

 또한 효율적인 데이터 교환을 위해 구조체, 인터페이스, 데이터 테이블을 활용하는 것이 좋습니다.