블루프린트에서 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++ 클래스를 설계하려면 다음을 고려하세요.
- 가상 함수 사용
- 보호된(protected) 멤버 변수 활용
- 블루프린트 이벤트 제공
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++ 함수와 속성을 오버라이드하려면,
- 가상 함수로 선언
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++ 클래스의 인스턴스를 생성하고 조작하는 방법
- 생성자 함수 노출
- 팩토리 함수 제공
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++와 블루프린트 간의 효율적인 데이터 교환을 위해서는,
- 구조체(USTRUCT) 활용
- 인터페이스(UINTERFACE) 사용
- 데이터 테이블(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++의 블루프린트 확장 시 설계 패턴
- 템플릿 메소드 패턴
- 전략 패턴
- 옵저버 패턴
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++와 블루프린트를 혼용할 때의 성능 고려사항
- 블루프린트는 C++보다 약간 느림
- 빈번한 C++-블루프린트 경계 넘나들기 피하기
- 성능 중요 로직은 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++와 블루프린트 혼용 시 디버깅 전략
- C++ 디버거 활용
- 블루프린트 비주얼 디버깅 사용
- 로깅 및 화면 메시지 활용
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);
}
대규모 팀에서의 효과적인 협업 방법
- 명확한 인터페이스 정의
- 문서화 및 주석 작성
- 코드 리뷰 및 스타일 가이드 준수
협업을 위한 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++ 클래스를 블루프린트에 노출시키고 가상 함수와 이벤트를 통해 블루프린트에서 쉽게 확장할 수 있는 구조를 만드는 것이 중요합니다.
또한 효율적인 데이터 교환을 위해 구조체, 인터페이스, 데이터 테이블을 활용하는 것이 좋습니다.