[UE5] CSV, JSON 파일로부터 GameplayAttribute 설정

kkado·2024년 9월 11일
0

UE5

목록 보기
61/63
post-thumbnail

Gameplay Attribute를 설정하는 데 사용할 수 있는 Curve Table을 CSV(Comma-Seperated Value) 또는 Json 파일로 Ex/Improt하여 사용하면 편리하다.

CSV/JSON

Export

먼저 Content Drawer에서 Miscellaneous -> Curve Table을 클릭해서 커브테이블을 생성한 후, 우클릭 -> Export as CSV/JSON 을 클릭해서 간단히 export 할 수 있다.

Import

만들어진 CSV/JSON 파일을 이용해서 커브 테이블을 만들고 싶다면 커브 테이블을 연 후 'Reimport' 버튼을 클릭해서 쉽게 연동할 수 있다.

Gameplay Effect(GE) 생성

이제 어트리뷰트들을 적용하는 GameplayEffect를 만든다.
Modifier Magnitude에서 Use Curve Table 을 선택해서 커브를 어트리뷰트 모디파이어와 연결한다.

Character Class별 Data Asset 생성

확장성을 고려해서 캐릭터 종류별 Enum Class를 만들고, 각각의 클래스가 어떤 GE를 사용하는지에 대한 정보를 하나의 Data Asset으로 만들어서 관리한다.

먼저 캐릭터 클래스 Enum을 정의해 주고,

// 캐릭터 타입을 정의
UENUM(BlueprintType)
enum class ECharacterClass : uint8
{
	Elementalist,
	Warrior,
	Ranger
};

사용할 데이터 구조체를 만든다.

USTRUCT(BlueprintType)
struct FCharacterClassDefaultInfo
{
	GENERATED_BODY()

	UPROPERTY(EditDefaultsOnly, Category = "Class Defaults")
	TSubclassOf<UGameplayEffect> PrimaryAttributes;
};

이를 가지고 CharacterClassFCharacterClassDefaultInfo의 맵을 가지는 Data Asset 클래스를 만든다.

UCLASS()
class AURA_API UCharacterClassInfo : public UDataAsset
{
	GENERATED_BODY()

public:
	UPROPERTY(EditDefaultsOnly, Category = "Character Class Defaults")
	TMap<ECharacterClass, FCharacterClassDefaultInfo> CharacterClassInformation;
    
	FCharacterClassDefaultInfo GetClassDefaultInfo(ECharacterClass CharacterClass);
};

이후에는 에디터에서 GE와 클래스를 서로 연결.

GameplayEffect 적용

이제 마지막으로 GameplayEffect를 적용하는 것만 남았다.

그 전에 한가지 생각해야 할 것은 방금 만들었던 CharacterClass를 저장하는 위치이다.
게임의 전체적인 정책을 중앙에서 관리하는 game mode가 좋은 장소가 될 수 있을 것이며 여기에 CharacterClassInfo TObjectPtr을 생성하기로 한다.

AbilitySystemLibrary에다 함수를 정의하기로 하고, 상위 Character 클래스의 InitializeDefaultAttribute 함수를 가상 함수로 만들어 몬스터클래스에서 오버라이드한다.

void UAuraAbilitySystemLibrary::InitializeDefaultAttributes(const UObject* WorldContextObject, ECharacterClass CharacterClass, float Level, UAbilitySystemComponent* ASC)
{
	if (AAuraGameModeBase* AuraGameMode = Cast<AAuraGameModeBase>(UGameplayStatics::GetGameMode(WorldContextObject)))
	{
		AActor* AvatarActor = ASC->GetAvatarActor();
		check(AuraGameMode->CharacterClassInfo);
		const FCharacterClassDefaultInfo ClassDefaultInfo = AuraGameMode->CharacterClassInfo->GetClassDefaultInfo(CharacterClass);

		// Set Primary Attribute
		FGameplayEffectContextHandle PrimaryAttributesContextHandle = ASC->MakeEffectContext();
		PrimaryAttributesContextHandle.AddSourceObject(AvatarActor);
		const FGameplayEffectSpecHandle PrimaryAttributesSpecHandle = ASC->MakeOutgoingSpec(ClassDefaultInfo.PrimaryAttributes, Level, PrimaryAttributesContextHandle);
		ASC->ApplyGameplayEffectSpecToSelf(*PrimaryAttributesSpecHandle.Data.Get());
    }
}

ASC에서 ApplyGameplayEffect를 수행할 수 있고 여기서 필요한 건 GameplayEffectSpec. GameplayEffectSpecMakeOutgoingSpec로부터 얻은 SpecHandle에서 .Data.Get() 을 통해 얻을 수 있다.

그리고 MakeOutgoingSpec의 파라미터로써 필요한 FGameplayEffectContextHandleMakeEffectContext() 를 통해 얻을 수 있으며 여기서 AddSourceObject 를 설정해서 이 effect의 출처를 명시한다.

(개인적으로는 이런 식으로 거슬러 거슬러 올라가는 방식이 좋은 것 같다)


그 결과, 디버깅해 보았을 때 Ranger 타입으로 설정된 Goblin_SlingShot 몬스터에서 ClassDefaultInfo가 GE_PrimaryAttributes_Ranger로 잘 매핑되어 적용되고 있음을 확인할 수 있다.

profile
베이비 게임 개발자

0개의 댓글