언리얼엔진

언리얼엔진 Composition 사용법

silbaram 2025. 4. 7. 19:30
728x90

컴포지션(Composition)은 상속(Inheritance) 대신 여러 개의 작은 모듈(컴포넌트)을 조합하여 객체의 기능을 확장하는 방법입니다. 언리얼 엔진에서는 Actor Component를 사용하여 액터에 다양한 기능(예: 체력, 무기, 인터랙션 등)을 부여하는 방식으로 컴포지션을 구현합니다.

컴포지션의 장점은 다음과 같습니다:

  • 유연성: 각 기능을 독립된 컴포넌트로 만들어 여러 액터에서 재사용할 수 있습니다.
  • 유지보수: 기능이 분리되어 있어 코드 수정 및 확장이 쉽습니다.
  • 의존성 감소: 상속 계층이 깊어지지 않아 클래스 간 의존성이 줄어듭니다.

아래 예제는 체력(Health) 기능을 가진 컴포넌트를 만들어, 이를 액터에 추가하는 방식을 보여줍니다.


1. UHealthComponent (체력 컴포넌트) 만들기

HealthComponent.h

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "HealthComponent.generated.h"

UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class MYPROJECT_API UHealthComponent : public UActorComponent
{
    GENERATED_BODY()

public:    
    UHealthComponent();

protected:
    virtual void BeginPlay() override;

public:    
    // 최대 체력
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Health")
    float MaxHealth;

    // 현재 체력
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Health")
    float CurrentHealth;

    // 데미지를 입는 함수
    UFUNCTION(BlueprintCallable, Category = "Health")
    void TakeDamage(float DamageAmount);
};

HealthComponent.cpp

#include "HealthComponent.h"

UHealthComponent::UHealthComponent()
{
    PrimaryComponentTick.bCanEverTick = false;
    MaxHealth = 100.f;
    CurrentHealth = MaxHealth;
}

void UHealthComponent::BeginPlay()
{
    Super::BeginPlay();
}

void UHealthComponent::TakeDamage(float DamageAmount)
{
    CurrentHealth = FMath::Clamp(CurrentHealth - DamageAmount, 0.f, MaxHealth);
    UE_LOG(LogTemp, Log, TEXT("Damage Taken: %f, Current Health: %f"), DamageAmount, CurrentHealth);
}

2. AMyActor에 UHealthComponent 추가하기

컴포지션 방식으로 AMyActor에 체력 기능을 추가하려면, AMyActor의 멤버 변수로 UHealthComponent를 선언하고 생성자에서 생성합니다.

MyActor.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "HealthComponent.h"  // 체력 컴포넌트 포함
#include "MyActor.generated.h"

UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
    GENERATED_BODY()

public:    
    AMyActor();

protected:
    virtual void BeginPlay() override;

public:    
    // 컴포지션: 체력 기능을 담당하는 컴포넌트
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
    UHealthComponent* HealthComp;
};

MyActor.cpp

#include "MyActor.h"

AMyActor::AMyActor()
{
    PrimaryActorTick.bCanEverTick = false;

    // 생성자에서 HealthComponent 생성 및 기본 서브오브젝트로 등록
    HealthComp = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComponent"));
}

void AMyActor::BeginPlay()
{
    Super::BeginPlay();

    // 예시: 액터 시작 시 체력 컴포넌트에 데미지 적용
    if (HealthComp)
    {
        HealthComp->TakeDamage(25.f);
    }
}

3. 결론

이 예제에서는 컴포지션을 사용하여 AMyActor가 체력 관련 기능을 직접 구현하지 않고, 별도의 UHealthComponent를 포함함으로써 기능을 확장했습니다. 이를 통해 여러 액터에 동일한 기능을 손쉽게 재사용할 수 있으며, 각 기능이 독립적이므로 코드 유지보수와 확장이 더욱 용이해집니다.

728x90