icon안동민 개발노트

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++와 블루프린트 간 데이터 전달

  1. 구조체를 통한 복잡한 데이터 전달
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;
};
  1. 델리게이트를 통한 이벤트 기반 통신
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();
};
  1. 인터페이스를 활용한 유연한 설계
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);
  1.  버전 관리 주의 : C++ 변경이 블루프린트에 영향을 줄 수 있으므로 주의 필요

  2.  성능 프로파일링 : 블루프린트 노출로 인한 성능 저하 모니터링

Best Practices

  1. 일관된 명명 규칙 사용
UPROPERTY(BlueprintReadOnly, Category="Character")
FString CharacterName;
 
UFUNCTION(BlueprintCallable, Category="Character")
void SetCharacterName(const FString& NewName);
  1. 카테고리를 활용한 체계적인 구조화
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Character|Stats")
float Strength;
 
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Character|Stats")
float Agility;
  1. 메타데이터를 활용한 추가 정보 제공
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon", meta=(DisplayName="발사 속도", ClampMin="0.1", ClampMax="10.0"))
float FireRate;
  1. 열거형을 활용한 선택 옵션 제공
UENUM(BlueprintType)
enum class EWeaponType : uint8
{
    Melee,
    Ranged,
    Magic
};
 
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Weapon")
EWeaponType WeaponType;
  1. 블루프린트 함수 라이브러리 활용
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++ 코드를 블루프린트에 노출시키고, 구조체와 델리게이트를 통해 복잡한 데이터와 이벤트를 효과적으로 전달할 수 있습니다.

 항상 성능과 유지보수성을 고려하여 C++와 블루프린트 사이의 적절한 균형을 찾는 것이 중요합니다. 지속적인 리팩토링과 최적화를 통해 게임 개발 과정에서 C++와 블루프린트의 장점을 최대한 활용할 수 있습니다.