C++에서 블루프린트 노출 속성 설정
C++와 블루프린트의 효과적인 통합은 언리얼 엔진 개발의 핵심입니다.
이 절에서는 C++ 코드를 블루프린트에 노출시키는 다양한 방법과 고급 기법을 살펴보겠습니다.
UPROPERTY 매크로의 고급 사용법
UPROPERTY 매크로는 C++ 속성을 블루프린트에 노출시키는 데 사용됩니다.
주요 Specifiers
- BlueprintReadWrte : 블루프린트에서 읽기/쓰기 가능
- BlueprintReadOnly : 블루프린트에서 읽기만 가능
- EditAnywhere : 인스턴스와 기본값 모두 편집 가능
- EditDefaultsOnly : 기본값만 편집 가능
- VisibleAnywhere : 읽기 전용으로 표시
예시
UCLASS()
class MYGAME_API AMyActor : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats")
float Health;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Info")
FString ActorName;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Config")
int32 MaxLevel;
};
고급 사용
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats", meta=(ClampMin="0.0", ClampMax="100.0", ToolTip="체력 (0-100)"))
float Health;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Inventory", meta=(DisplayName="무기 목록"))
TArray<TSubclassOf<AWeapon>> WeaponClasses;
UFUNCTION 매크로의 고급 사용법
UFUNCTION 매크로는 C++ 함수를 블루프린트에 노출시킵니다.
주요 Specifiers
- BlueprintCallable : 블루프린트에서 호출 가능
- BlueprintPure : 사이드 이펙트 없는 순수 함수
- BlueprintImplementableEvent : 블루프린트에서 구현 가능한 이벤트
- BlueprintNativeEvent : C++에서 기본 구현을 제공하고 블루프린트에서 오버라이드 가능
예시
UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="Combat")
void Attack();
UFUNCTION(BlueprintPure, Category="Stats")
float GetHealthPercentage() const;
UFUNCTION(BlueprintImplementableEvent, Category="Events")
void OnLevelUp();
UFUNCTION(BlueprintNativeEvent, Category="Interaction")
void Interact(AActor* OtherActor);
};
고급 사용
UFUNCTION(BlueprintCallable, Category="Combat", meta=(DisplayName="강력한 공격", ToolTip="대미지 2배의 강력한 공격 수행"))
void PowerAttack();
UFUNCTION(BlueprintCallable, Category="Items", meta=(DeterminesOutputType="ItemClass"))
UObject* SpawnItem(TSubclassOf<UObject> ItemClass);
블루프린트 오버라이드 가능한 함수 생성
BlueprintNativeEvent를 사용하여 C++에서 기본 구현을 제공하고 블루프린트에서 오버라이드 가능한 함수를 만들 수 있습니다.
UFUNCTION(BlueprintNativeEvent, Category="Character")
void TakeDamage(float DamageAmount);
void TakeDamage_Implementation(float DamageAmount)
{
// C++ 기본 구현
Health -= DamageAmount;
}
블루프린트에서 이 함수를 오버라이드하면 블루프린트 구현이 호출되고 필요한 경우 C++ 구현을 부모 함수 호출을 통해 실행할 수 있습니다.
C++와 블루프린트 간 데이터 전달
- 구조체를 통한 복잡한 데이터 전달
USTRUCT(BlueprintType)
struct FCharacterInfo
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FString Name;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 Level;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Experience;
};
UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="Character")
void SetCharacterInfo(const FCharacterInfo& Info);
UFUNCTION(BlueprintPure, Category="Character")
FCharacterInfo GetCharacterInfo() const;
};
- 델리게이트를 통한 이벤트 기반 통신
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChangedSignature, float, NewHealth);
UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable, Category="Events")
FOnHealthChangedSignature OnHealthChanged;
UFUNCTION(BlueprintCallable, Category="Health")
void SetHealth(float NewHealth);
};
void AMyCharacter::SetHealth(float NewHealth)
{
Health = NewHealth;
OnHealthChanged.Broadcast(Health);
}
C++ 블루프린트 하이브리드 워크플로우
1. 핵심 기능은 C++로 구현 : 성능이 중요한 부분, 복잡한 로직, 재사용 가능한 시스템은 C++로 구현
2. 게임플레이 로직과 빠른 프로토타이핑은 블루프린트로 구현 : 게임 규칙, AI 행동, UI 로직 등
3. C++ 기본 클래스 생성 후 블루프린트로 확장
UCLASS(Blueprintable)
class MYGAME_API ABaseEnemy : public ACharacter
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, Category="AI")
void PerformAttack();
};
4. 인터페이스를 활용한 유연한 설계
UINTERFACE(Blueprintable)
class MYGAME_API UInteractableInterface : public UInterface
{
GENERATED_BODY()
};
class IInteractableInterface
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintNativeEvent, Category="Interaction")
void Interact(AActor* Interactor);
};
성능 및 유지보수 고려사항
1. 과도한 블루프린트 노출 피하기 : 필요한 속성과 함수만 노출하여 인터페이스를 깔끔하게 유지
2. 대규모 데이터나 복잡한 연산은 C++에서 처리 : 블루프린트는 상대적으로 성능이 낮음
3. 명확한 문서화
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats", meta=(ToolTip="캐릭터의 최대 체력"))
float MaxHealth;
UFUNCTION(BlueprintCallable, Category="Combat", meta=(ToolTip="대상에게 데미지를 입힙니다"))
void DealDamage(AActor* Target, float Amount);
4. 버전 관리 주의 : C++ 변경이 블루프린트에 영향을 줄 수 있으므로 주의 필요
5. 성능 프로파일링 : 블루프린트 노출로 인한 성능 저하 모니터링
Best Practices
- 일관된 명명 규칙 사용
UPROPERTY(BlueprintReadOnly, Category="Character")
FString CharacterName;
UFUNCTION(BlueprintCallable, Category="Character")
void SetCharacterName(const FString& NewName);
- 카테고리를 활용한 체계적인 구조화
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Character|Stats")
float Strength;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Character|Stats")
float Agility;
- 메타데이터를 활용한 추가 정보 제공
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon", meta=(DisplayName="발사 속도", ClampMin="0.1", ClampMax="10.0"))
float FireRate;
- 열거형을 활용한 선택 옵션 제공
UENUM(BlueprintType)
enum class EWeaponType : uint8
{
Melee,
Ranged,
Magic
};
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
EWeaponType WeaponType;
- 블루프린트 함수 라이브러리 활용
UCLASS()
class MYGAME_API UMyBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="Math", meta=(DisplayName="고급 수학 함수"))
static float AdvancedMathFunction(float A, float B);
};
C++와 블루프린트의 효과적인 통합은 언리얼 엔진 개발의 핵심 요소입니다.
C++의 성능과 유연성, 그리고 블루프린트의 빠른 이터레이션과 시각적 스크립팅의 장점을 결합하여 강력하고 유지보수가 용이한 게임 시스템을 구축할 수 있습니다.
UPROPERTY와 UFUNCTION 매크로를 적절히 활용하여 C++ 코드를 블루프린트에 노출시키고 구조체와 델리게이트를 통해 복잡한 데이터와 이벤트를 효과적으로 전달할 수 있습니다.