ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [UE5] 단일 캐스팅 델리게이트를 이용한 다중 동작 이벤트 처리
    UE5 2024. 12. 3. 18:54

    1. 단일 캐스팅(Single-cast Delegate) vs 멀티 캐스팅(Multi-cast Delegate) 델리게이트

    특징 단일 캐스팅 델리게이트 멀티캐스팅 델리게이트
    핸들러 수 한 번에 하나의 함수만 바인딩 가능 여러 함수를 바인딩 가능
    사용 사례 특정 이벤트에 하나의 동작만 필요할 때 하나의 이벤트로 여러 동작을 처리할 때
    유연성 제한적 높은 유연성
    실행 함수 Execute, ExecuteIfBound BroadCast

     

    2. 단일 캐스팅 델리게이트의 다중 동작

    • FonTakeItemDelegate 선언 및 델리게이트를 담아줄 구조체 선언
    DECLARE_DELEGATE_OneParam(FOnTakeItemDelegate, class UABItemData* /*InItemData*/);
    USTRUCT(BlueprintType)
    struct FTakeItemDelegateWrapper
    {
    	GENERATED_BODY()
    	FTakeItemDelegateWrapper(){}
    	FTakeItemDelegateWrapper(const FOnTakeItemDelegate& InItemDelegate) : ItemDelegate(InItemDelegate) {}
    	
    	FOnTakeItemDelegate ItemDelegate;
    };
    // FTakeItemDelegateWrapper를 담는 리스트 생성
    UPROPERTY()
    TArray<FTakeItemDelegateWrapper> TakeItemActions;

     

    래퍼를 사용하는 이유?

    • 단일 캐스팅 델리게이트를 감싸고, 델리게이트 외에도 추가적인 데이터를 저장하거나 관리
    • 구조화된 관리, 확장성, 유연성 제공
    • 델리게이트와 추가 데이터를 함께 관리할 수 있어 복잡한 로직 처리에 적합.
    • 우선순위 처리, 실행 조건 관리, 메타데이터 저장 등에 사용 가능
    // 단일 캐스팅 델리게이트를 리스트로 관리
    TakeItemActions.Add(FTakeItemDelegateWrapper(FOnTakeItemDelegate::CreateUObject(this, &AABCharacterBase::EquipWeapon))); // 무기 장착
    TakeItemActions.Add(FTakeItemDelegateWrapper(FOnTakeItemDelegate::CreateUObject(this, &AABCharacterBase::DrinkPotion))); // 물약 사용
    TakeItemActions.Add(FTakeItemDelegateWrapper(FOnTakeItemDelegate::CreateUObject(this, &AABCharacterBase::ReadScroll)));  // 스크롤 읽기
    // 조건에 따라 단일 캐스팅 델리게이트 리스트에서 적합한 델리게이트만 실행
    void AABCharacterBase::TakeItem(UABItemData* InItemData)
    {
    	if (InItemData)
    	{
    		TakeItemActions[(uint8)InItemData->Type].ItemDelegate.ExecuteIfBound(InItemData);
    	}
    }

     

    왜 필요한가?

    • 멀티캐스트 델리게이트 사용시 하나의 이벤트에 모든 동작이 묶이게 되어 동작 분리가 어려워짐
    • 각 동작을 독립적으로 관리 가능하며 특정 동작만 제거하거나 추가하기 쉬움
    • 리스트를 통해 각 동작의 실행 순서를 명확히 제어 가능

     

    3. 멀티캐스팅 델리게이트로 조건 분기가 가능할까?

    • 멀티캐스팅 델리게이트 정의
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTakeItem, UABItemData*, InItemData);

     

    • 델리게이트 추가
    class AABCharacterBase : public ACharacter
    {
        GENERATED_BODY()
    
    public:
        UPROPERTY(BlueprintAssignable, Category = "Item Actions")
        FOnTakeItem OnTakeItem; // 멀티캐스팅 델리게이트
    };

     

    • 아이템 유형별 핸들러 등록
    void AABCharacterBase::BeginPlay()
    {
        Super::BeginPlay();
    
        // 무기 장착
        OnTakeItem.AddDynamic(this, &AABCharacterBase::EquipWeapon);
    
        // 물약 사용
        OnTakeItem.AddDynamic(this, &AABCharacterBase::DrinkPotion);
    
        // 스크롤 읽기
        OnTakeItem.AddDynamic(this, &AABCharacterBase::ReadScroll);
    }
    • 핸들러 구현
      • 각 핸들러 내부터에 아이템 유형을 확인하고 조건을 처리
    void AABCharacterBase::EquipWeapon(UABItemData* InItemData)
    {
        if (InItemData && InItemData->Type == EItemType::Weapon)
        {
            UE_LOG(LogTemp, Log, TEXT("Equipping weapon!"));
            // 무기 장착 로직
        }
    }
    
    void AABCharacterBase::DrinkPotion(UABItemData* InItemData)
    {
        if (InItemData && InItemData->Type == EItemType::Potion)
        {
            UE_LOG(LogTemp, Log, TEXT("Drinking potion!"));
            // 물약 사용 로직
        }
    }
    
    void AABCharacterBase::ReadScroll(UABItemData* InItemData)
    {
        if (InItemData && InItemData->Type == EItemType::Scroll)
        {
            UE_LOG(LogTemp, Log, TEXT("Reading scroll!"));
            // 스크롤 읽기 로직
        }
    }

     

    • 아이템 사용 로직
    void AABCharacterBase::TakeItem(UABItemData* InItemData)
    {
        if (InItemData)
        {
            OnTakeItem.Broadcast(InItemData); // 등록된 모든 핸들러 실행
        }
    }

     

    4. 델리게이트는 직렬화가 불가능하다?

    • Delegate wrapper를 사용하는 주된 이유 중 하나는 delegate의 직렬화와 관련된 제약 때문
    • 즉, 언리얼엔진에서 UPROPERTY화 시킬 수 없음
    • 이런 문제를 해결하기 위해 delegate를 감싸는 wrapper 구조체를 사용하면, 구조체를 통해 직렬화를 지원하게 만들어, delegate의 상태를 보다 쉽게 관리할 수 있음

    5. 결론

    • 멀티캐스팅 델리게이트는 다수의 핸들러를 한 이벤트에 연결해야 하는 경우에 적합
    • 멀티캐스팅 델리게이트를 사용하면 모든 핸들러가 호출된 후 조건을 확인하므로 불필요한 호출이 발생할 가능성있음
    • 더군다나, 언리얼엔진의 핵심기능인 UPROPERTY화가 불가능
    • 단일 캐스팅 델리게이트를 리스트화하여 조건에 따라 실행 시키는 것이 조건 기반 실행에 적합하고, 확장성과 관리 측면에서 유용

    'UE5' 카테고리의 다른 글

    [UE5] 네트워크 멀티플레이어  (0) 2024.12.10
    [UE5] 추상클래스와 인터페이스  (0) 2024.12.06
    [UE5] 순수 가상 함수(Pure Virtual Function)  (0) 2024.12.06
    [UE5] 인터페이스의 활용  (0) 2024.12.05
    [UE5] CoreMinimal.h란?  (1) 2024.12.03
Designed by Tistory.