* 주의 *

1. 해당 작업은 StandAlone에서만 테스트되었습니다.

2. 해당 작업은 임시 연동을 위해 작업되었으며, 타 환경 (네트워크 환경 등)에서는 정상 작동을 보장하지 않습니다.

3. 필요시, 코드를 적당히 수정해서 사용해주세요!

 

 

(아마 기억이 맞다면) 언리얼 5.3에 들어오면서 큰 변화가 몇가지 생겼다.

그중에 프로그래머 입장에서 유의미하게 볼것이 바로 EnhancedInput의 정식 사용 시작 및 AbilitySystem의 공식 플러그인 화 일것이다.

 

근데 웃긴게, 이 두가지가 하나는 정식기능, 다른 하나는 플러그인이라서 그런가 공식적으로 지원하는 연동 코드가 없다.....

 

물론, 진짜 하나도 없진 않다. 대신, LyraStarterGame에 포함되어있을뿐...

 

LyraStarterGame에서는 해당 기능을 HeroComponent라는 연동 컴포넌트와, EnhancedInput을 위한 LyraInputComponent를 만들어서 사용하는데, 해당 컴포넌트 및 Lyra 식 사용에 대한 분석은 다음에 하기로 하고, 우선은 조금 빠른 사용법을 익혀보도록 하자.

 

 

* 해당 코드의 일부는 EpicGames에서 제공하는 Lyra Starter Game에서 발췌했습니다.


우선, 이전 글을 참고하여 AbilitySystemComponent를 정상적으로 사용할 수 있는 상태를 기준으로 한다.

 

https://locketgoma.tistory.com/80

 

짧막 팁 : AbilitySystem 관련 헤더를 불러오지 못할때

대충 이런 상황이다. AbilitySystemComponent 및 기타 관련 헤더를 사용해야하는데 못불러오는경우... 해당 문제는 모듈이 빠져있는 상황으로, 프로젝트 명칭으로 된 폴더에 있는 "(ProjectName).Build.cs"

locketgoma.tistory.com

 

 

두가지를 연동하려면 우선, InputAction과 GameplayTag를 연동시켜둔 데이터파일이 필요하다.

해당 파일 타입을 Lyra에서는 "FLyraInputAction" 라는 struct를 사용하는 ULyraInputConfig라는 DataAsset를 만들어 사용한다.

 

일단, 해당 방법을 그대로 사용하자.

 

UDataAsset를 상속받는 신규 클래스를 만들고, 해당 파일에

 

USTRUCT(BlueprintType)
struct FInputAction		//이름은 적당히 바꿔서 쓰면 됩니다.
{
	GENERATED_BODY()

public:

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	TObjectPtr<const UInputAction> InputAction = nullptr;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Meta = (Categories = "InputTag"))
	FGameplayTag InputTag;
};

해당 구조체를 추가, uproperty로 추가해주면 된다.

Lyra에서는 (EditDefaultsOnly, BlueprintReadOnly) 조건으로 사용중이나, 적당히 필요한대로 쓰시면 될것같다.

 

 

 

그 다음부터는 선택지가 갈리는데, EnhancedInputComponent 및 PanwComponent를 상속받아서 Lyra와 같이 InputComponent + HeroComponent를 만들어서 사용하거나, 간략하게 AbilitySystemComponent를 상속하여 구현해주는 방법 등이 있다.

 

여기서는 AbilitySystemComponent 을 상속하여 추가 함수를 만들어주는 방식으로 구현하고자 한다.

 

Lyra 방식은... 공부도 하실겸 Lyra 코드를 열어보시는걸 추천드립니다.

 

 

 

첫번째. UAbilitySystemComponent를 상속받은 컴포넌트를 추가한다.

두번째. 위에서 만든 DataAsset Class를 헤더에 추가한다.
(단순히 전방선언으로 사용하면 구조체의 사이즈를 알 수 없어 오류가 발생한다)

세번째. 다음과 같이 (혹은 적당히 수정하여) 헤더를 작성한다.

UCLASS()
class PROJECTCLOUD_API UCLAbilitySystemComponent : public UAbilitySystemComponent
{
	GENERATED_BODY()

public:
	//인풋 액션을 세팅하는 함수 (return bool인 이유는 오류 검출 용도)
	bool BindInputActions(const UCLAbilityInputConfig* InputConfig, UEnhancedInputComponent* EnhancedInputComponent);
	
	//인풋 액션을 호출하는 바인딩 함수
	void TryActiveAbilityFromInputAction(const FInputActionInstance& Value);

private:
	//인풋 액션 리스트
	TMap<TObjectPtr<const UInputAction>, FGameplayTag> InputactionList;
};

네번째. cpp 파일에 필요한 헤더들을 추가한다.
EnhancedInput관련, GameplayTag 관련 헤더를 추가해주면 된다.

다섯번째. 바인딩 코드 작성.

bool UCLAbilitySystemComponent::BindInputActions(const UCLAbilityInputConfig* InputConfig, UEnhancedInputComponent* EnhancedInputComponent)
{
	if (!ensure(EnhancedInputComponent))
	{
		UE_LOG(LogTemp, Error, TEXT("UCLAbilitySystemComponent :: EnhancedInputComponent is Null."));
		return false;
	}

	for (const FCLInputAction Action : InputConfig->AbilityInputActions)
	{
		InputactionList.Add(Action.InputAction, Action.InputTag);

		EnhancedInputComponent->BindAction(Action.InputAction, ETriggerEvent::Triggered, this, &UCLAbilitySystemComponent::TryActiveAbilityFromInputAction);
	}
	return true;
}

 

Input으로 받은 DataAsset에서 리스트를 가져와서 EnhancedInput에 바인드하고, 로직 검사를 위해 ASC에 추가한 Map에 등록해주는 로직이다.

 

여섯번째. 바인드 될 호출함수 작성

void UCLAbilitySystemComponent::TryActiveAbilityFromInputAction(const FInputActionInstance& Value)
{
	//1. 이벤트로 들어온 InputAction과 매치되는 Tag가 있는지 검사
	FGameplayTag* InputTag = InputactionList.Find(Value.GetSourceAction());
	
    //2. 매치되는 Tag가 있다면
	if (InputTag != nullptr)
	{
    	//3. Pay로드 작성 후
		FGameplayEventData TempPayload;
		TempPayload.EventTag = *InputTag;
		TempPayload.Instigator = GetOwner();
        
        //4. ASC에 포함된 HandleGameplaytEvent를 호출한다.
        HandleGameplayEvent(TempPayload.EventTag, &TempPayload);
	}
}

Payload값은 임의로 수정해도 된다. (단, EventTag 제외)

 

 

다음과 같이 작성하면 함수 준비는 끝났다.

 

이를 어떻게 사용하느냐...

 

사실 생각보다 별거 없다. EnhancedInput과 ASC를 사용하고자 한다면, 아마 여러가지 검색을 하면서 Player Pawn에다가 연동하는 작업도 수행했을것이다.

아니었다구요? 그렇다면..

 

	UEnhancedInputComponent* EnhancedInputComponent = GetComponentByClass<UEnhancedInputComponent>();

	if (ACLPlayerState * PS = Cast<ACLPlayerState>(GetPlayerState()))
	{
		PS->GetAbilitySystemComponent()->InitAbilityActorInfo(PS, this);
		PS->SetAbilitiesFromActionSet(AbilitySet);
		PS->GetAbilitySystemComponent()->BindInputActions(InputConfig, EnhancedInputComponent);
	}

다음과 같은 로직을 Player Pawn의 Beginplay 등의 Init 단계에서 호출하도록 추가해주면 된다.

 

당연한 얘기겠지만, 이미 EnhancedInput을 Player Pawn에 등록했어야 하고,
해당 로직의 경우에는 PlayerState에 ASC를 등록해서 사용했기에, 해당 과정도 거친 상태여야 한다.

(스텐드 얼론이어서 Pawn에 직접 ASC를 붙여서 사용한다면, 코드를 적당히 수정하면 된다.)

 

다음과 같이 등록하고, Player Pawn에 "InputConfig"  변수를 추가해주면 끝.

 

정상적으로 잘 따라왔다면,

 다음과 같은 InputConfig를 만들 수 있고,

해당 InputConfig를 추가할 수 있는 공간이 Player Pawn에 추가된다.

 

이제 자유롭게 InputAction과 InputTag를 부착하면, Player의 ASC에 부착된 GameplayAbility 중 Trigger Event로 호출되는 Ability를 사용할 수 있게 된다.

 

 


ASC 사용법은 저 말고도 다른 분들이 잘 설명해준 문서들이 많으니 참고 바랍니다...
EnhancedInput과 ASC 연동하는 방법은 어디에도 없길래 Lyra 코드 분석해가면서 간략화해서 만들어봤어요

 

틀린 내용에 대한 지적은 언제나 받습니다.

+ Recent posts