본문 바로가기

Unreal Engine 5

언제 TOptional 과 TMap 을 사용해야할까?

가령 우리가 Actor Component 를 만들고 난 뒤, Actor Component 에서 다음과 같은 함수가 있다고 가정하자.

 

void UCP_Attacks::MagicSpell(FTransform& SpawnTransform, AActor* Target, FDamageInfo& DamageInfo, TSubclassOf<AProjectileBase> ClassToSpawn)
{
    if (!ClassToSpawn) return;

    UWorld* World = GetWorld();
    if (!World) return;

    FActorSpawnParameters SpawnParams;
    SpawnParams.Owner = GetOwner(); // 현재 객체를 Owner로 설정

    AProjectileBase* SpawnedProjectile = World->SpawnActor<AProjectileBase>(ClassToSpawn, SpawnTransform, SpawnParams);

    if (SpawnedProjectile)
    {
        // 스폰된 액터 초기화
        SpawnedProjectile->InitializeProjectile(1000.0f, 0.0f, false, Target);

        // 충돌 이벤트 바인딩
        SpawnedProjectile->OnProjectileImpact.AddDynamic(this, &UCP_Attacks::OnProjectileHit);

        // 이동 중 특정 액터 무시 설정
        if (UPrimitiveComponent* PrimitiveComp = Cast<UPrimitiveComponent>(SpawnedProjectile->GetRootComponent()))
        {
            AActor* OwnerActor = GetOwner();
            if (OwnerActor)
            {
                PrimitiveComp->IgnoreActorWhenMoving(OwnerActor, true);
            }
        }
    }
}
void UCP_Attacks::OnProjectileHit(AActor* OtherActor, const FHitResult& Hit)
{
    FDamageInfo DamageInfo;
    if (OtherActor && OtherActor->GetClass()->ImplementsInterface(UDamageableInterface::StaticClass()))
    {
        // TakeDamage호출
        IDamageableInterface::Execute_TakeDamage(OtherActor,DamageInfo,GetOwner());
    }
    else
    {
        return;
    }


    UAISense_Damage::ReportDamageEvent(
        this,             // WorldContextObject
        OtherActor,     // 공격받은 액터
        GetOwner(),       // 공격한 액터
        DamageInfo.Amount,     // 데미지량
        GetOwner()->GetActorLocation(),    // 이벤트 발생 위치 (보통 Instigator 위치)
        Hit.ImpactPoint,      // 충돌 위치
        NAME_None         // 태그 (필요하면 지정 가능)
    );
    OnAttackEnd.Broadcast();
}

 

 

OnProjectileHit 이 Bind 되어있고, Bind되어있는 함수에 정보를 넘기기 위해선 여러가지 방식이 있을것이다. Delegate 인자를 늘려주거나, 아니면 임시로 ActorComponent 내에 정보를 받아주는 인자를 생성하여, 이것을 넘겨주는 방식이 있을것인데,

 

특정 구조체의 정보를 넘겨주는 상황을 상정하여 어떤 경우에는 어떻게 넘겨주는 것이 좋을지 생각해보자

 

(FDamageInfo) 라는 struct 가 있다고 가정(구조체)

1. TOptional< FDamageInfo > 

 

TOptional - 값이 있을 수도, 없을 수도 있는 단일 데이터 관리

TOptional은 특정 데이터가 설정되었는지 여부를 명확히 표현하고, 간단한 데이터 관리에 유용

 

TOptional<FDamageInfo> DamageInfoMapping;

// 데이터 설정
DamageInfoMapping = FDamageInfo();

// 데이터 접근
if (DamageInfoMapping.IsSet())
{
    FDamageInfo DamageInfo = DamageInfoMapping.GetValue().DamageInfo;
}

 

 

  • 단일 데이터를 관리하는 데 적합.
  • 데이터가 존재하지 않는 상태(IsSet() == false)를 명확히 표현 가능.
  • 메모리 사용량이 적음.
  • 단점: 다수의 객체를 관리하거나 데이터를 매핑해야 하는 경우에는 확장성이 부족.

- 사용 시기

 

  • 단일 Projectile이나 제한된 범위의 데이터를 다룰 때.
  • 데이터가 있을 수도 없을 수도 있는 상태를 표현해야 할 때.
  • 간단한 테스트 코드나 프로토타입 구현 시.

 

 

TMap - 객체와 데이터를 유연하게 매핑

TMap은 키-값 구조를 활용해 다수의 객체와 데이터를 관리할 수 있는 강력한 컨테이너

TMap<AProjectileBase*, FDamageInfo> DamageMap;

// 데이터 추가
DamageMap.Add(Projectile, DamageInfo);

// 데이터 검색
if (FDamageInfo* FoundInfo = DamageMap.Find(Projectile))
{
    FDamageInfo DamageInfo = FoundInfo->DamageInfo;
}

 

특징

  • 다수의 객체와 데이터를 체계적으로 매핑 가능.
  • 키를 기반으로 데이터를 빠르게 검색 가능.
  • 유지보수와 확장에 유리한 구조.
  • 단점: 메모리를 조금 더 사용하며, 관리 로직이 추가로 필요.

사용 시기

  • 여러 Projectile과 관련 데이터를 관리해야 할 때.
  • 데이터가 동적으로 추가되고 삭제되는 경우.
  • 유지보수와 확장성을 고려한 설계가 필요할 때.