ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [UE5] 게임플레이 이펙트의 활용
    UE5 2025. 1. 7. 15:32

    게임플레이 이펙트

    • 줄여서 GE(Gameplay Effect)로 불림
    • GAS는 게임에 영향을 주는 객체를 별도로 분리해서 관리함
    • 게임에 영향을 준다는 것은 대부분 게임 데이터를 변경한다는 것을 의미함
    • 따라서 대부분 게임플레이 이펙트와 어트리뷰트는 함께 동작하도록 구성되어 있음
    • GAS 시스템에서 가장 많은 기능을 제공하는 클래스
    • 세 가지 타입 존재
      • Instant : 어트리뷰트에 즉각적으로 적용되는 게임플레이 이펙트. 한 프레임에 실행됨
      • Duration : 지정한 시간 동안 동작하는 게임플레이 이펙트
      • Infinite : 명시적으로 종료하지 않으면 계속 동작하는 게임플레이 이펙트

     

    게임플레이 이펙트 모디파이어(Modifier)

    • GE에서 어트리뷰트의 변경 방법을 지정한 설정을 모디파이어라고 함
    • 모디파이어의 사용 방법
      • 적용할 어트리뷰트의 지정
      • 적용 방식의 설정 : 더하기, 곱하기, 나누기, 더어쓰기
    • 모디파이어의 계산 방법
      • ScalableFloat : 실수 (데이터 테이블과 연동 가능)
      • AttributeBased : 특정 어트리뷰트에 기반
      • CustomCalculationClass : 계산을 담당하는 전용 클래스의 활용
      • SetByCaller : 데이터 태그를 활용한 데이터 전달
    • 모디파이어 없이 자체 계산 로직을 만드는 것도 가능 ( GameplayEffectExecutionCalculation )
    • C++로 설정하기에는 문법이 복잡해서 블루프린트로 제작하는 것을 권장

    게임플레이 이펙트 모디파이어 설정창

     

    메타(Meta) 어트리뷰트

    • 어트리뷰트의 설정을 위해 사전에 미리 설정하는 임시 어트리뷰트
    • 예) 체력을 바로 깎지 않고, 데미지를 통해 체력을 감소하도록 설정
      • 체력은 일반 어트리뷰트, 데미지는 메타 어트리뷰트
    • 데미지를 사용하는 경우 기획 추가에 유연한 대처가 가능
      • 무적 기능의 추가 (데미지를 0으로 처리)
      • 실드 기능의 추가 (실드 값을 토대로 실드 값만큼 데미지를 감소)
      • 콤보 진행시 공격력 보정 기능 추가 (콤보 증가시 데미지를 보정하도록 구현)
    • 메타 어트리뷰트는 적용 후 바로 0으로 값을 초기화하도록 설정
    • 메타 어트리뷰트는 리플리케이션에서 제외시키는 것이 일반적
    void UABCharacterAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
    {
    	Super::PostGameplayEffectExecute(Data);
    
    	float MinimumHealth = 0.0f;
    
    	if (Data.EvaluatedData.Attribute == GetHealthAttribute())
    	{
    		ABGAS_LOG(LogABGAS, Warning, TEXT("Direct Health Access : %f"), GetHealth());
    		SetHealth(FMath::Clamp(GetHealth(), MinimumHealth, GetMaxHealth()));
    	}
    	else if (Data.EvaluatedData.Attribute == GetDamageAttribute())
    	{
    		ABGAS_LOG(LogABGAS, Log, TEXT("Damage : %f"), GetDamage());
    		SetHealth(FMath::Clamp(GetHealth() - GetDamage(), MinimumHealth, GetMaxHealth()));
    		SetDamage(0.0f);
    	}
    
    	if ((GetHealth() <= 0.0f) && !bOutOfHealth)
    	{
    		Data.Target.AddLooseGameplayTag(ABTAG_CHARACTER_ISDEAD);
    		OnOutOfHealth.Broadcast();
    	}
    
    	bOutOfHealth = (GetHealth() <= 0.0f);
    }

     

    레벨과 커브 테이블

    레벨에 따른 커브 테이블

    • 게임플레이 이펙트에는 추가적으로 레벨 정보를 지정할 수 있음
    • 게임플레이 이펙트에 저장된 레벨 정보를 사용해 데이터 테이블에서 특정 값을 가져올 수 있음
    • ScalableFloat 모디파이어 타입에서 이를 사용하는 것이 가능
    • 이를 활용해 다양한 기능을 구현하는 것이 가능
      • 콤보 추가시 증가하는 요율을 반영해 최종 데미지를 계산
      • 현재 캐릭터 레벨에 따른 초기 스탯 적용
    • 커브테이블은 언리얼 에디터를 통해 쉽게 제작 가능

     

    게임플레이 이펙트의 생성 과정

    • 게임플레이 이펙트 컨텍스트와 게임플레이 이펙트 스펙을 통해 생성할 수 있음
    • 게임플레이 이펙트 컨텍스트 : GE에서 계산에 필요한 데이터를 담은 객체
      • 가해자 (Instigator), 가해수단 (Causer), 판정정보 (HitResult) 등
    • 게임플레이 이펙트 스펙 : GE에 관련된 정보를 담고 있는 객체
      • 레벨, 모디파이어 및 각종 태그에 대한 정보
      • 게임플레이 이펙트 컨텍스트 핸들
    • ASC는 각 데이터를 핸들 객체를 통해 간접적으로 관리함
    • 따라서 이펙트 컨텍스트 핸들을 만든 후, 이펙트 스펙 핸들을 생성하는 순서로 진행되어야 함
    • 아래의 과정을 거치면 어빌리티 시스템 컴포넌트가 별도의 GA를 발동시키지 않고 스스로 Gameplay Effect를 발동시켜 자신의 스탯을 변동 시킴
    // 게임플레이 이펙트 컨텍스트 핸들에 소스 오브젝트에 대한 정보만 넣어서 구성
    FGameplayEffectContextHandle EffectContextHandle = ASC->MakeEffectContext();
    EffectContextHandle.AddSourceObject(this);
    
    // 게임플레이 스펙 핸들에 레벨, 스택, 이펙트 컨텍스트 핸들을 넣어서 생성
    FGameplayEffectSpecHandle EffectSpecHandle = ASC->MakeOutgoingSpec(InitStatEffect, Level, EffectContextHandle);
    if (EffectSpecHandle.IsValid())
    {
        ASC->BP_ApplyGameplayEffectSpecToSelf(EffectSpecHandle);
    }
    • 언리얼 엔진 5.5 버전부터는 스스로에게 게임플레이 이펙트를 적용시키는 블루프린트 함수를 제공 (ApplyGameplayEffectToSelf)

     

    기간형 게임플레이 이펙트

    기간형 게임플레이 이펙트 적용(Has Duration)

    • 인스턴트 타입이 아닌 게임플레이 이펙트
      • Duration : 지정한 시간 동안 동작하는 게임플레이 이펙트
      • Infinite : 명시적으로 종료하지 않으면 계속 동작하는 게임플레이 이펙트
    • 인스턴트 타입은 한 프레임에 종료되기 때문에, 상태를 가질 수 없음
    • 기간형 게임플레이 이펙트는 유효 기간동안 태그와 같은 상태를 가질 수 있음

    • 기간형 게임플레이 이펙트는 중첩(Stack)이 가능하도록 설정이 가능함
    • 모디파이어를 설정하지 않아도 다양하게 활용 가능함
    • 인스턴트는 Base값을 변경하지만 기간형은 Current값을 변경하고 원래대로 돌려놓음
    bool UABCharacterAttributeSet::PreGameplayEffectExecute(FGameplayEffectModCallbackData& Data)
    {
    	if (!Super::PreGameplayEffectExecute(Data))
    	{
    		return false;
    	}
    
    	if (Data.EvaluatedData.Attribute == GetDamageAttribute())
    	{
    		if (Data.EvaluatedData.Magnitude > 0.0f)
    		{
    			if (Data.Target.HasMatchingGameplayTag(ABTAG_CHARACTER_INVINCIBLE))
    			{
    				Data.EvaluatedData.Magnitude = 0.0f;
    				return false;
    			}
    		}
    	}
    	return true;
    }

     

Designed by Tistory.