0. 개요
이전 포스트에서 속성 메뉴에 속성 이름과 값을 전달하도록 설정했다.
이제 태그를 확인하여 속성 메뉴의 각 행에 속성을 하나 씩 매칭하도록 설정한다.
(지금은 모든 행에 Strength의 이름과 값만 표시되도록 설정되어 있다)
1. 사전 준비
(1) 게임플레이 태그를 변수로 추가 - TextValueRow 위젯 블루프린트
속성 메뉴의 각 행에 대해 태그를 확인하고 부여하기 위해 게임플레이 태그를 변수로 추가한다.
(2) 각 행에 대해 속성 이름 부여 - AttributeMenu 위젯 블루프린트
각 행의 속성 이름을 작성하고 모두 선택하여 변수 여부(Is Variable)를 체크한다.
(3) Set Attribute Tags 블루프린트 함수 생성 및 연결
새로 변수로 추가한 Attribute Tag와 전달받은 Info 구조체의 게임플레이 태그를 비교하기 전에, 메뉴의 각 행에 속성을 할당한다.
해당 함수를 생성하고 노드를 연결한다.
2. 속성 매핑
이제 속성 세트 내의 모든 속성의 값을 가져오도록 하기 위해, 각 속성을 태그와 매핑(Map으로 키-값 쌍을 만들어)하여 맵 컨테이너로 관리한다.
(1) 속성 델리게이트 선언 - AuraAttributeSet
속성 세트 상단에 아래와 같이 델리게이트를 선언한다.
DECLARE_DELEGATE_RetVal(FGameplayAttribute, FAttributeSignature);
FAttributeSignature 델리게이트는 FGameplayAttribute를 반환한다.
(2) 맵 컨테이너 선언
TMap<FGameplayTag, FAttributeSignature> TagsToAttributes;
이제 태그와 델리게이트를 키-값 쌍으로 저장하는 맵을 선언한다.
(3) 델리게이트 바인딩 및 키-값 쌍 추가
UAuraAttributeSet::UAuraAttributeSet()
{
const FAuraGameplayTags& GameplayTags = FAuraGameplayTags::Get();
auto StrengthTag = GameplayTags.Attributes_Primary_Strength;
FAttributeSignature StrengthDelegate;
StrengthDelegate.BindStatic(GetStrengthAttribute);
TagsToAttributes.Add(StrengthTag, StrengthDelegate);
auto IntelligenceTag = GameplayTags.Attributes_Primary_Intelligence;
FAttributeSignature IntelligenceDelegate;
StrengthDelegate.BindStatic(GetIntelligenceAttribute);
TagsToAttributes.Add(IntelligenceTag, IntelligenceDelegate);
}
태그와 속성을 매치시켜 맵에 저장한다.
델리게이트에 Static 함수를 바인딩하여 델리게이트 호출 시 속성을 Get 하게 한다.
3. 델리게이트 인스턴스, 함수 포인터 - TBaseStaticDelegateInstance
위와 같이 매번 속성마다 델리게이트 인스턴스를 생성하고 함수를 바인딩 하는 것은 비효율적이다.
델리게이트 인스턴스를 멤버 변수로 하나를 만들어 함수 포인터를 교체하는 방법을 사용한다.
(1) 함수 포인터(Function Pointer)
함수 포인터는 함수를 변수처럼 저장하여 사용할 수 있도록 도와주는 문법이다.
언리얼에서 델리게이트 인스턴스는 함수 포인터를 내부에 저장할 수 있도록 되어있다.
여기에서는 인스턴스의 함수 포인터에 직접 접근하여 값을 바꾸는 방법을 사용한다.
(2) 정적 델리게이트 인스턴스 선언
TBaseStaticDelegateInstance<FGameplayAttribute(), FDefaultDelegateUserPolicy>::FFuncPtr FunctionPointer;
속성을 타입으로 반환하며, 0개의 인수를 전달하는 인스턴스에 접근해 함수 포인터를 멤버 변수로 저장한다.
(3) 맵 컨테이너 변경
TMap<FGameplayTag, TBaseStaticDelegateInstance<FGameplayAttribute(), FDefaultDelegateUserPolicy>::FFuncPtr> TagsToAttributes;
태그-속성 쌍 맵을 태그-함수 포인터 쌍으로 변경한다.
(4) 델리게이트-바인딩 제거
UAuraAttributeSet::UAuraAttributeSet()
{
const FAuraGameplayTags& GameplayTags = FAuraGameplayTags::Get();
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength, GetStrengthAttribute);
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Intelligence, GetIntelligenceAttribute);
}
기존에 델리게이트를 생성하고 정적 함수를 바인딩하는 구문을 위와 같이 변경할 수 있다.
(5) 속성 메뉴 위젯 컨트롤러 수정
void UAttributeMenuWidgetController::BroadcastInitialValues()
{
UAuraAttributeSet* AS = CastChecked<UAuraAttributeSet>(AttributeSet);
check(AttributeInfo);
for (auto& Pair : AS->TagsToAttributes)
{
// 키를 이용하여 캐릭터의 속성 정보를 꺼내기
FAuraAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key);
Info.AttributeValue = Pair.Value().GetNumericValue(AS);
// 속성 정보 브로드캐스트
AttributeInfoDelegate.Broadcast(Info);
}
}
4. 함수 포인터 수정하기 - AuraAttributeSet
(1) 함수 포인터 문법
이제 직접 속성의 값을 Get하는 함수에 값으로써(키-값 쌍에서) 접근할 수 있다.
함수 포인터를 얻기 위해서는 괄호를 명시해야 한다.
TMap<FGameplayTag, TBaseStaticDelegateInstance<FGameplayAttribute(), FDefaultDelegateUserPolicy>::FFuncPtr> TagsToAttributes;
해당 구문을 아래로 축약하여 사용할 수 있다.
TMap<FGameplayTag, FGameplayAttribute(*)()> TagsToAttribute;
(2) typedef 문법
아래와 같이 typedef 문법을 사용하여 짧게 변형할 수 있다.
typedef TBaseStaticDelegateInstance<FGameplayAttribute(), FDefaultDelegateUserPolicy>::FFuncPtr FAttributeFuncPtr;
UCLASS()
class AURA_API UAuraAttributeSet : public UAttributeSet
{
//~~~~~~~
TMap<FGameplayTag, FAttributeFuncPtr> TagsToAttributes;
(3) template 문법
해당 템플릿 포인터를 일반화 할 수 있다.
template<class T>
using TStaticFuncPtr = typename TBaseStaticDelegateInstance<T, FDefaultDelegateUserPolicy>::FFuncPtr;
TMap<FGameplayTag, TStaticFuncPtr<FGameplayAttribute()>> TagsToAttributes;
TStaticFuncPtr 포인터는 GameplayAttribute 함수에 0개의 인수를 전달하여 호출하는 함수 포인터가 된다.
5. 결과
함수 포인터를 일반화하고, 속성 메뉴 위젯 컨트롤러의 코드가 맵을 순회하도록 하게 함으로써 앞으로 주요 속성을 추가하더라도 속성 메뉴 위젯 컨트롤러를 수정하지 않아도 된다.
(아래와 같이 새로운 속성을 추가한 속성 메뉴 클래스만 수정하면 된다)
UAuraAttributeSet::UAuraAttributeSet()
{
const FAuraGameplayTags& GameplayTags = FAuraGameplayTags::Get();
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength, GetStrengthAttribute);
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Intelligence, GetIntelligenceAttribute);
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Resilience, GetResilienceAttribute);
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Vigor, GetVigorAttribute);
}
- 순서 정리
속성 메뉴 위젯 블루프린트에서 최초 속성 값을 표기하는 순서는 아래와 같다.
1. 속성 세트에서 태그와 속성 함수 포인터를 맵 컨테이너의 키-값 쌍으로 매핑
- 각 속성 함수 포인터는 속성 값의 Getter 함수(Accessor ; 접근자에 의해 생성된)이며 괄호가 없다.
2. 속성 메뉴 위젯 컨트롤러에서 맵을 순회하고 태그에 따라 AttributeInfo 구조체를 생성
3. 속성 정보 구조체에 함수 포인터의 값을 저장하고 브로드캐스트
4. 위젯이 정보 구조체를 전달받아 값으로 표시
'UE 5 스터디 > Gameplay Ability System(GAS)' 카테고리의 다른 글
8-1. 게임플레이 어빌리티(Gameplay Ability) (0) | 2024.10.31 |
---|---|
7-11. 속성 메뉴 UI - (7) 속성 값 변화 델리게이트, 2차 속성 매핑 (0) | 2024.10.23 |
7-9. 속성 메뉴 UI - (5) 속성 값 전달하기 (0) | 2024.10.04 |
7-8. 블루프린트 함수 라이브러리 - (2) 속성 메뉴 위젯 컨트롤러 (0) | 2024.09.27 |
7-6. Native 게임플레이 태그, Native 태그 블루프린트로 전달하기 (0) | 2024.09.19 |