관리 메뉴

Mini

[UE5] 속성행에 GE태그 연결, 속성추가시 AS코드만 수정 // 함수포인터 사용방법 본문

UE5/Attribute Menu

[UE5] 속성행에 GE태그 연결, 속성추가시 AS코드만 수정 // 함수포인터 사용방법

Mini_96 2024. 6. 8. 21:22

* 각 속생행은 각각의 태그를 가져야함

부모에 변수추가
각 행 이름 변경
각행에 태그를 set해주는 함수 구현 하면됨
구현부 : 모든 속성에 대해 태그를 set 해준다 (노가다)

 

이제 우리는 this.AttributeTag에 설정해준 태그를 얻을수 있다

 

* TextButtonRowButton 리팩토링

들어온 info.tag == 나의태그가 일치할때만, set Text 해주도록 변경
결과
버튼Row의 부모인 TextRow에도 복붙함

 

* 모든속성을 방송하기

1. //아래코드에서 모든 속성에 대해 노가다 -> wtf

void UAttributeMenuWidgetController::BroadcastInitialValues()
{
    UAuraAttributeSet* AS = CastChecked<UAuraAttributeSet>(AttributeSet); //부모인 위젯컨트롤러가 갖고있음

    check(AttributeInfo) //DA가 set되었는지 확인
    FAuraAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(FAuraGameplayTags::Get().Attributes_Primary_Strength); //일치태그 정보를 리턴
    Info.AttributeValue=AS->GetStrength(); //속성정보 set 완료, value는 직접넣기로 설계함
    AttributeInfoDelegate.Broadcast(Info); //set완료후 방송해야함

    
}

 

2. for loop로 돌리는게 좋겠다.

* 설계

1.

AS에 Getter 가 있음

AS에서 FGameplayAttribute를 리턴해주는 델리게이트 생성

DECLARE_DELEGATE_RetVal(FGameplayAttribute, FAttributeSignature);

태그-속성을 매치해주는 Map 만듬

TMap<FGameplayTag,FAttributeSignature> TagsToAttributes;

생성자에서 맵에 추가

모든 태그에 대해

UAuraAttributeSet::UAuraAttributeSet()
{
    const FAuraGameplayTags& GameplayTags = FAuraGameplayTags::Get(); //모든태그들 가져오기

    FAttributeSignature StrengthDelegate;
    StrengthDelegate.BindStatic(UAuraAttributeSet::GetStrengthAttribute); //델리게이트에 실제속성넣기(바인딩)
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength,StrengthDelegate); //맵에추가<태그,속성>

    FAttributeSignature IntDelegate;
    IntDelegate.BindStatic(GetIntelligenceAttribute); //델리게이트에 실제속성넣기(바인딩)
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength,IntDelegate); //맵에추가<태그,속성>
}

 

2.

델리게이트내부의 FGameplayAttribute에 접근하려면 Signature.Execute()로 포장을 벗겨야함
//GameplayAttribute의 껍질을까서 실제 값에 접근하려면 Attr.getNumeric을 사용

리팩토링 완성

void UAttributeMenuWidgetController::BroadcastInitialValues()
{
    UAuraAttributeSet* AS = CastChecked<UAuraAttributeSet>(AttributeSet); //부모인 위젯컨트롤러가 갖고있음

    check(AttributeInfo) //DA가 set되었는지 확인

    //기존
    // FAuraAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(FAuraGameplayTags::Get().Attributes_Primary_Strength); //일치태그 정보를 리턴
    // Info.AttributeValue=AS->GetStrength(); //속성정보 set 완료, value는 직접넣기로 설계함
    // AttributeInfoDelegate.Broadcast(Info); //set완료후 방송해야함

    //리팩토링
    for(auto& Pair : AS->TagsToAttributes) //AS의 <태그,속성:델리게이트> 맵 순회
    {
       FAuraAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key) //태그에 맞는 속성 찾기
       FGameplayAttribute Attr = Pair.Value.Execute(); //델리게이트내부의 FGameplayAttribute에 접근하려면 Signature.Execute()로 포장을 벗겨야함
       Info.AttributeValue=Attr.GetNumericValue(AS); //GameplayAttribute의 껍질을까서 실제 값에 접근
       //(Attr이 스태틱 함수에서 반환되기떄문에 -> 이속성이 연괸딘 AS가 누구인지 알려줘야함)

       AttributeInfoDelegate.Broadcast(Info);
    }
    
}

결과

 

3. 문제 : 델리게이트 사용은 복잡, 코드가 늘어남

해결 : 함수포인터 사용

//FGameplayAttribute를 반환하는 함수포인터

TBaseStaticDelegateInstance<FGameplayAttribute(), FDefaultDelegateUserPolicy>::FFuncPtr FunctionPointer; 

 

TMap<FGameplayTag,FAttributeSignature> TagsToAttributes; //기존


//함수포인터
TMap<FGameplayTag,TBaseStaticDelegateInstance<FGameplayAttribute(), FDefaultDelegateUserPolicy>::FFuncPtr> TagsToAttributes2;
FunctionPointer = GetStrengthAttribute; //바로 FGameplayAttribute 속성을 넣을수있다

 

- 기존코드

FunctionPointer = GetStrengthAttribute;
FAttributeSignature StrengthDelegate;
StrengthDelegate.BindStatic(UAuraAttributeSet::GetStrengthAttribute); //델리게이트에 실제속성넣기(바인딩)
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength,StrengthDelegate); //맵에추가<태그,속성>
//리팩토링, 위젯메뉴컨트롤러
for(auto& Pair : AS->TagsToAttributes) //AS의 <태그,속성:델리게이트> 맵 순회
{
    FAuraAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key); //태그에 맞는 속성 찾기
    FGameplayAttribute Attr = Pair.Value.Execute(); //델리게이트내부의 FGameplayAttribute에 접근하려면 Signature.Execute()로 포장을 벗겨야함
    Info.AttributeValue=Attr.GetNumericValue(AS); //GameplayAttribute의 껍질을까서 실제 값에 접근
    //(Attr이 스태틱 함수에서 반환되기떄문에 -> 이속성이 연괸딘 AS가 누구인지 알려줘야함)

    AttributeInfoDelegate.Broadcast(Info);
}

 

- 함수포인터 코드

:바인딩하는 부분이 없어도 된다!

: 바로 <태그, 속성>을 맵에 Add하면된다.

최종적으로 line3와 같이  줄일수있다.

FunctionPointer = GetStrengthAttribute;
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength,FunctionPointer); //맵에추가<태그,속성>

//단축코드
TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength,GetStrengthAttribute); //맵에추가<태그,속성>
//리팩토링
for(auto& Pair : AS->TagsToAttributes) //AS의 <태그,속성:델리게이트> 맵 순회
{
    FAuraAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key); //태그에 맞는 속성 찾기
    FGameplayAttribute Attr = Pair.Value(); //FGameplayAttribute에 접근
    Info.AttributeValue=Attr.GetNumericValue(AS); //GameplayAttribute의 껍질을까서 실제 값에 접근
    //(Attr이 스태틱 함수에서 반환되기떄문에 -> 이속성이 연괸딘 AS가 누구인지 알려줘야함)

    AttributeInfoDelegate.Broadcast(Info);
}

결과

 

* 리팩토링 함수포인터

1. typedef로 줄일수있음

typedef TBaseStaticDelegateInstance<FGameplayAttribute(), FDefaultDelegateUserPolicy>::FFuncPtr FAttributeFuncPtr;
TMap<FGameplayTag,FAttributeFuncPtr> TagsToAttributes;

문제 : FGameAttribute 타입으로 제한됨

해결 : 템플릿

 

2. 템플릿

FGameplayAttribute를 T로 대체함

template<class T>
using TAttributeFuncPtr = typename TBaseStaticDelegateInstance<T, FDefaultDelegateUserPolicy>::FFuncPtr

선언시, 무슨타입인지 FuncPtr<반환타입(매개변수)>을 써주면됨

TMap<FGameplayTag,TAttributeFuncPtr<FGameplayAttribute()>> TagsToAttributes;

+ : FGameAttribute타입뿐아니라, 모든타입에 사용가능한 함수포인터임

 

3. 사용예시

Ptr<float반환 (매개변수들)>

 

* 맵에 모든 <태그, 속성> 추가 노가다

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);
}

결과

 

* 결과

속성추가시, AS코드만 수정하면된다!

메뉴위젯 컨트롤러의 코드는 손댈필요 없음! (map을 단순히 순회하는 loop임)

 

* 정리

FGameplayAttribute 반환하는 함수포인터를 맵에 전달
반환X, 입력0개인 함수포인터로 지정
위젯컨트롤러에서 태그에 해당하는 속성을찾고, 값을넣고, 정보들을 방송함 / 위젯에서 수신하고 정보표시