지난번에, Attribute와 GameplayTag에 대해서는 어느정도 알아보았다. Attribute는 캐릭터의 특정 속성의 구체적인 수치를 의미하는 것이고, GameplayTag는 플레이어의 현재 상태를 의미하는 것이다.
Attribute와 GameplayTag를 활용하여 컨텐츠를 만들려면 원하는 시기에 Attribute와 GameplayTag의 값을 변경해주는 기능이 필요할 것이다.
그 과정에서 중요한 역할을 하는 클래스가 GameplayEffect라고 한다. 이번 게시글에선 GameplayEffect에 대해 알아보고자 한다.
GameplayEffect
먼저, 공식문서의 설명을 보자.
그렇다고 한다. GameplayEffect는 GAS에서 Attribute를 변경하는 방식이라고 한다. 하지만, 아예 처음 접하는 사람의 입장에선 다소 설명이 부족하다고 느껴지는 부분이 있다.
그래서, 예제 프로젝트 깃허브의 설명도 참조해보았다.
위의 글은 예제 프로젝트를 제공해준 깃허브의 GameplayEffect에 대한 설명이다.
아래는 번역이다.
GameplayEffect (GE)는 본인 혹은 다른 개체의 Attribute와 GameplayTags를 변경하기 위한 통로이다. GE는 기절, 이동속도 증가와 같이 오래 유지되는 디버프/버프 상태를 적용하기도 하고, Damage, Healing과 같이 Atrribute를 즉시 변경해주기도 한다. UGameplayEffect 클래스는 하나의 GameplayEffect를 정의하는 데이터 전용 클래스를 의미한다. 추가적인 로직을 GameplayEffect에 추가해서는 안된다. 일반적으로 디자이너들이 UgameplayEffect를 상속받은 블루프린트 클래스를 많이 만들게 될 것이다.
GameplayEffects 는 Modifier와 Execution을 통해 Attribute를 변경한다. (GameplayEffectExecutionCalculation).
GameplayEffects는 Instanct, Duration, Infinite의 3가지 타입을 가지고 있다.
추가적으로 GameplayEffects는 GameplayCues를 더하거나 실행할 수 있다. Instant 타입의 GameplayEffect는 GameplayCue, GameplayTags 를 실행하는 반면, Duration이나 Infinite타입의 GameplayEffect는 GameplayCue, GameplayTags를 더하거나 제거할 수 있다.
아래는 GameplayEffect의 세가지 타입에 대한 부가적인 설명이다.
Instant타입은 GameplayCueEvent를 실행하고, Duration과 Infinite는 GameplayCueEvent를 제거하거나 더해준다고 한다.
GameplayCue는 나중에 좀 더 자세히 다뤄보아야 겠지만, 간단하게 알고 넘어가자면 특정 상황에서 발생하는 사운드나 이펙트와 관련된 것이라고 한다.
Instant는 Attribute의 BaseValue를 즉시 영구적으로 변경할 때 사용된다고 한다.
단, GameplayTags는 한 프레임에서 조차 적용되지 않는다고 한다.
Duration은 Attribute의 CurrentValue를 일시적으로 변경하거나, GameplayEffect가 만료되거나, 수동적인 제거 등의 이유로 GameplayTags가 제거될 때 사용된다고 한다. GameplayEffect의 지속시간은 UGameplayEffect클래스에서 지정할 수 있다고 한다.
Infinite는 Attribute의 CurrentValue를 일시적으로 변경하거나, GameplayEffect가 제거되어 GameplayTag를 제거하기 위해 사용한다고 한다. 이 경우엔 UGameplayEffect가 만료되는 일이 없기 때문에, ASC나 ablility에 의해 수동적으로 제거해야만 한다고 한다.
정리하자면, Instant는 Attribute를 한 번 바꾸고 더 이상 후속처리를 할 필요가 없을 때 사용한다는 것 같다.
예를 들어, 플레이어가 레벨업을 해서 최대 체력이 증가했다면, 이 수치는 감소될 일이 없기 때문에 Instant로 값을 한 번 바꾼 뒤 GameplayEffect를 소멸시키는 것 같다.
Duration은 특정 기간동안 적용되는 상태에 대해 사용하는 것 같다. 예를 들어, Buff스킬을 사용하면 일반적으로 지속시간이 존재한다. 3분이라고 가정한다면, 버프 스킬을 사용하고 3분동안은 CurrentValue가 변경되어 있다가 지속시간이 끝나는 3분 뒤에 CurrentValue를 다시 BaseValue로 변경해주어야 한다. 그렇기 때문에, GameplayEffect는 3분동안 살아있다가 마지막에 CurrentValue를 BaseValue로 변경해준 뒤에 소멸하는 듯 하다.
Infinite는 반대로, 특정 상태가 언제 소멸되는지 예측할 수 없을 때 사용하는 것 같다. 예를 들어, 플레이어가 안개로 가득한 맵에 입장했다고 가정해보자. 해당 맵 안에서는 이동속도가 10%가 감소하고 플레이어의 시야 범위가 좁아진다고 했을 때, 플레이어가 이 맵을 탈출하게 되면 다시 이동속도와 시야 범위를 기존의 값으로 돌려놓아야 한다. 하지만, 플레이어가 정확히 몇 분, 몇 초가 걸려서 이 맵을 탈출할 지 정확히 예측할 수 없기 때문에, GameplayEffect는 계속 살아있다가 플레이어가 맵을 탈출하는 시기에 수동적으로 제거해주어야 하는 듯 하다.
블루프린트 클래스를 한 번 훑어보자.
예제 프로젝트를 보면, 이렇게 3개의 GameplayEffect 블루프린트 클래스가 있다.
세 클래스 모두 Infinite이며, 플레이어의 체력, 마나, 스태미너의 자연치유에 관한 GameplayEffect이며 플레이어가 죽을 때 까지 계속 자연치유를 하기 때문에 Infinite로 되어있는 듯 하다.
내부를 보자.
먼저, Duration Policy를 보면 Infinite로 되어있다.
여기서 Instant, Duration, Infinite를 설정할 수 있다.
밑에 있는 Period를 확장해보면 이렇게 3개의 옵션이 나온다.
Period는 해당 GameplayEffect를 몇 초 주기로 적용할 것인가에 관한 옵션이다.
실제로, Period 수치를 변경하며 치유 주기를 확인해보니 3을 입력하면 3초 주기로 Hp가 회복되는 것을 보았다.
밑의 두 옵션에 대해서 정확히 이해하지는 못했지만, 에디터의 코멘트를 번역해보면 이와 같다.
Execute Periodic Effect on Application : True일 경우, 매 주기마다 어플리케이션에서 Effect가 실행된다.
false일 경우, 첫 번째 주기가 끝날 때 까지 실행되지 않는다.
아마, 이 효과가 적용된 프레임에 바로 효과를 적용할 것인지, 아니면 한 번의 주기를 건너 뛴 다음 주기부터 효과를 적용할 건지에 대한 옵션인 것 같다.
Periodic Inhition Policy : 주기적인 GameplayEffect가 더이상 억제되지 않을 때, 어떻게 반응할 것인가?
1) Never Reset : 마지 억제가 발생하지 않았던 것처럼 주기적인 타이밍은 계속된다.
2) Reset Period : 주기를 리셋한다. 다음 실행은 억제가 사라진 이후로부터 한 번의 주기가 끝난 이후에 발생된다.
3) Execute And Reset :즉시 실행하고, 주기를 초기화한다.
이 것은 외부에서 설정한 어떤 원인으로 인해, GameplayEffect의 효과가 일시적으로 억제되다가 해당 원인이 사라지면서 다시 GameplayEffect의 효과가 적용될 때 어떻게 반응할건지를 고르는 것 같다.
예를 들어, HP 리젠 주기가 3초라고 해보자.
2.6초가 지난 후, HP리젠을 억제하는 디버프가 들어왔고, 다시 이 디버프가 사라졌다고 해보자.
만약, Never Reset을 선택했다면, 디버프가 사라지고 0.4초 뒤에 HP가 리젠된다.Reset Period를 선택했다면, 디버프가 사라지고 3초 뒤에 HP가 리젠된다.Execute And Reset을 선택했다면, 디버프가 사라지는 순간 HP가 리젠되고, 그 이후로 3초의 주기마다 HP가 동일하게 리젠된다.
GameplayEffect가 적용되는 주기를 디테일하게 조절하는 옵션인 듯 하다.
밑에는 GameplayEffect 카테고리가 있다.
이 카테고리에는 Componenty와 Modifiers, Executions가 있다.
Components를 확장해보면 아래와 같은 옵션들이 나온다.
첫 번째에 있는 컴포넌트에는 여러가지 목록이 존재한다. 목록을 설정함에 따라 GameplayEffect의 적용 조건을 다양하 세팅할 수 있는 듯 하다.
현재 설정되어 있는 것은 GameplayTag를 기반으로 이 GameplayEffect의 효과가 적용되어야 하는가, 적용되지 말아야 하는가, 삭제되어야 하는가 등을 제어하는 컴포넌트인 듯 하다.
이 컴포넌트의 아래 옵션들을 보면, 여러가지가 있는데, 이 중에서 현재 프로젝트의 HealthRegen에는 Ongoing Tag Requirements 만 설정되어 있다.
아마, State.Dead 태그가 없어야지만, 이 GameplayEffect가 적용된다는 의미인 듯 하다.
다음은 Modifer카테고리를 확장해보자.
이렇게 옵션이 나온다.
Attribute는 이 GameplayEffect가 어떠한 Attribute의 값을 변경할 것인지를 선택하는 것 같다.
Modifer Op는 Add, Devide, Multiply, Override, Invalid가 있는데, 더할지 곱할지 나눌지 덮어씌울지 등을 선택하는 것 같다. Invalid는 뭘까.. 설정을 바꿔서 실행해봤더니 크래시가 발생했다. 해당 Attribute가 변경되지 못하도록 막는 옵션인 걸로 추측된다.
아래에 있는 Modifier Magnitude 도 확장해보았다.
Coefficient는 계수이다. Attribute에 적용되는 수치에 Coefficient를 곱해서 최종적으로 적용되는 듯하다.
Attribute to Capture는 어떤 Attribute를 기반으로 이 Attribute의 값을 변경할 것인가를 선택하는 것 같다. 여기선 HealthRegenRate가 선택되어 있다.
그 외에도 여러가지 옵션들이 있는데, 이건 좀 더 만져보면서 테스트해보아야 할 듯 하다..
여기까지 GameplayEffect에 대해 알아보았다.
개념들을 파헤치다 보니 어떤 방식으로 GAS에서 상호작용이 발생하는지 대충은 감이 잡히는 것 같다.
'언리얼 엔진 > GAS' 카테고리의 다른 글
언리얼 엔진 - GAS ( Game Ability System ) [ 5 ] (0) | 2024.04.21 |
---|---|
언리얼 엔진 - GAS ( Game Ability System ) [ 3 ] (0) | 2024.04.16 |
언리얼 엔진 - GAS ( Game Ability System ) [ 2 ] (0) | 2024.04.16 |
언리얼 엔진 - GAS ( Game Ability System ) [ 1 ] (0) | 2024.04.14 |