[UE5] UGOSkillCastComponent 구조, 액터 컴포넌트와 인터페이스

seunghyun·2024년 4월 24일
0

ProjectGO

목록 보기
2/7

들어가며

액터 컴포넌트가 캐릭터에게 무언가를 시키도록 하고 싶다면? 또는 데이터를 전달하고 싶다면?

인터페이스를 사용해보자!

인터페이스를 사용하면 느슨한 결합(loose coupling)이 가능해진다.
컴포넌트가 구체적인 클래스 대신 인터페이스를 통해 상호작용함으로써, 어떤 클래스가 해당 인터페이스를 구현하고 있는지 알 필요 없이, 일관된 방식으로 기능을 호출할 수 있다.
또한 다형성을 지원하고, 코드의 재사용성과 유지보수성도 향상시킨다.


적용해보기

요구사항: SkillCastComponent (Actor Component) 가 캐릭터의 스킬을 재생시키도록 하고 싶다.

먼저 인터페이스를 만들어준다.

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "Skill/GOSkillCastComponent.h"
#include "GOPlaySkillAnimInterface.generated.h"

...

class GUARDIANSORDERS_API IGOPlaySkillAnimInterface
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
	virtual UGOSkillCastComponent* GetSkillCastComponent() = 0;
	virtual void PlaySkillAnim() = 0;
};

캐릭터 코드에서 인터페이스를 구현하도록 한다.

#include "Interface/GOPlaySkillAnimInterface.h"

...

UCLASS()
class GUARDIANSORDERS_API AGOCharacterBase : public ACharacter, public IGOAnimationAttackInterface, public IGOCharacterWidgetInterface, public IGOPlaySkillAnimInterface
{
	GENERATED_BODY()
    
    ...
// ======== IPlaySkillAnimInterface ========

	virtual UGOSkillCastComponent* GetSkillCastComponent()
	{
		return SkillCastComponent;
	}

	virtual void PlaySkillAnim()
	{
		UE_LOG(LogTemp, Warning, TEXT("[ACharacterBase::PlaySkillAnim] called. This function is inherited from GOPlaySkillAnimInterface. "));
	}
 
 ...
 
}

이제 컴포넌트의 코드이다.

void UGOSkillCastComponent::OnUpdateCast(float DeltaTime)
{
	if (CurrentSkill == nullptr || !bIsOnCasting)
	{
		return;
	}

	// 스킬 캐스팅 중 업데이트 로직
	CurrentSkill->UpdateCast(DeltaTime);

	if (AActor* Owner = GetOwner())
	{
		if (IGOPlaySkillAnimInterface* GOPlaySkillAnimInterface = Cast<IGOPlaySkillAnimInterface>(Owner))
		{
			GOPlaySkillAnimInterface->PlaySkillAnim();
		}
	}

	if (DeltaTime > CurrentSkill->GetCastingTime())
	{
		OnFinishCast();
	}
    
    ...
}

출력 결과는 잘 나온다.

[ACharacterBase::PlaySkillAnim] called. This function is inherited from GOPlaySkillAnimInterface. 

헤더가 안보인다

그러니까 UGOSkillCastComponent는 IGOPlaySkillAnimInterface의 헤더를 UGOSkillCastComponent.h 또는 UGOSkillCastComponent.cpp 어디에서도 포함하고 있지 않아도 정상 작동한다.

왜일까?

Unreal Engine에서는 자체 빌드 시스템인 Unreal Build Tool (UBT)을 사용하고, UBT는 헤더 파일의 종속성을 관리하는 과정에서 약간의 마법을 부린다 (?)

  • Precompiled Headers (PCHs): Unreal Engine은 프로젝트의 모든 파일에 대해 사전 컴파일된 헤더를 사용한다. 이 사전 컴파일된 헤더에는 자주 사용되는 Unreal Engine의 코어 헤더들이 포함되어 있고, 때로는 여러 인터페이스 파일들도 포함될 수 있다. 만약 IGOPlaySkillAnimInterface가 이 PCH에 포함되어 있다면, 명시적으로 포함하지 않아도 모든 컴파일 단위에서 사용할 수 있게 된다.

주의할 점

액터 컴포넌트는 액터한테만 붙어야 하는 녀석이고
캐릭터 컴포넌트는 캐릭터한테만 붙어야 하는 녀석이고
탱커 컴포넌트는 탱커한테만 붙어야 하는 녀석이다


소감 (?)

이렇게 인터페이스로 구현하는 구조가 마치 ASC랑 비슷한 구조와 비슷하다는 생각이 들었다. 헤더 의존성을 줄여주고, 태스크마다 만들어주는 면에서 든 생각이다.

그렇다면 보통 이렇게 뭔가 할 것이 있을 때마다
인터페이스를 사용하고 델리게이트를 사용하나? -> 맞다!

0개의 댓글

관련 채용 정보