看板 GameDesign 關於我們 聯絡資訊
網頁版 https://yekdniwue.blogspot.com/2020/08/GameplayAbilityTask.html 簡介 本篇介紹的是UE4引擎的Gameplay Ability System(GAS) 中的AbilityTask系列。 不知道什麼是GAS的話可以參考先前的文章 GameplayAbilities System介紹 (一) https://yekdniwue.blogspot.com/2018/08/gameplayabilities-sytem.html GameplayAbilities System介紹 (二) https://yekdniwue.blogspot.com/2018/09/gameplayabilities-system.html UE4 GameplayAbilitySystem - GameplayEffect & GameplayCue 如何設定參數 https://yekdniwue.blogspot.com/2019/06/GameplayEffectAndCue.html Gameplay AbilityTask介紹 AbilityTask建立了大量的範例,作為示範, 很多ASC內部的系統與其他系統的溝通都做在AbilityTask內。 而AbilityTask則是要在Gameplay Ability內串流程的時候使用, AbilityTask節點不會出現在一般的Blueprint(BP)內 所以當了解完如何使用ASC,如何創造一個GameplayAbility, 以及GameplayEffect後。 應該先試著了解GameplayTask,可以對ASC能夠做到的事情, 如何做事情有更深刻的了解。 以下是引擎提供的Tasks,這些都可以在 Engine\Plugins\Runtime\GameplayAbilities\ Source\GameplayAbilities\Private\Abilities\Tasks\ 裡面找到 RootMotion ApplyRootMotion_Base ApplyRootMotionConstantForce ApplyRootMotionJumpForce ApplyRootMotionMoveToActorForce ApplyRootMotionMoveToForce ApplyRootMotionRadialForce MoveToLocation NetworkSyncPoint PlayMontageAndWait Repeat SpawnActor StartAbilityState VisualizeTargeting Wait WaitAbilityActivate WaitAbilityCommit WaitDelay WaitGameplayEvent WaitGameplayTag WaitGameplayTagBase WaitMovementModeChange WaitOverlap WaitTargetData WaitVelocityChange WaitAttribute系列 WaitAttributeChange WaitAttributeChangeRatioThreshold WaitAttributeChangeThreshold WaitInput系列 WaitCancel WaitConfirm WaitConfirmCancel WaitInputPress WaitInputRelease WaitGameplayEffect系列 WaitGameplayEffectApplied WaitGameplayEffectApplied_Self WaitGameplayEffectApplied_Target WaitGameplayEffectBlockedImmunity WaitGameplayEffectRemoved WaitGameplayEffectStackChange 各細項說明 RootMotion 示範Ability如何透過RootMotionSource跟 Character的RootMotion系統連動。 經過實測PlayAnimMontageAndWait以及MoveToForce在 lag 200ms是有拉回現象的,但是JumpForce沒有。 在UE4.25似乎有更新,有對這部份的程式碼做修改,不過我還沒有機會做測試。 MoveToLocation 會改SetMovementMode為Custom,無視碰撞。 感覺是個示範用的Task,想不到實際用途。 NetworkSyncPoint 用來做server/client同步的節點,總共有三種 BothWait OnlyServer OnlyClient 訊息處理的來回都是使用RPC。 Client 的部分會多加上prediction window, 可以用來作client prediction。 例如client先上effect或是gameplay cue, server再apply effect。 如果要做上面說的Client prediction只有一種接法: OnlyServerWait OnSync後面接server與client都要 apply effect的程式碼(或是BP node)。 如下圖 [圖] 這樣接的話,執行順序會是這樣: Client透過Input先發動Ability Ability內執行WaitNetSync 因為Client不用等待,所以直接ApplyEffect (Client Prediction) 同時間Client也會送出RPC,並且把prediction key傳過去 Server也會知道Ability發動,然後執行WaitNetSync, 等Client的RPC過來。 當收到Client的RPC過來後,Server才會通過OnSync, 然後ApplyEffect,ApplyEffect後,Server也會給一個回應, 讓Client知道Server已套用這個Effect。 如果使用BothWait是不行的,因為這樣Client端OnSync後, 是等到Server執行完OnSync才會執行, 這時才上Effect不僅不是Prediction, Client還會多上一次Effect,然後再被回朔(因為Server已套用過)。 BothWait應該是要拿來處理其他事情的,不過我目前沒想到使用情境。 PlayMontageAndWait 應該是最常用的節點,讓角色做montage, 並且會負責處理server/client的同步, 嚴格來說是處理Authroity與SimulatedProxy的同步, Autonomous要自行決定時機呼叫PlayMontageAndWait。 Repeat 就是一個timer的loop,每隔一段時間做一次,做到設定的次數就結束。 SpawnActor 從TargetDataHandle內取出第一個TargetData。 從TargetData拿HitResult,或是EndPoint作為Spawn的座標。 如果都沒有,Spawn座標會是執行這個Task的OwnerActor所在位置。 StartAbilityState 讓Ability進入自定義的AbilityState。 有三種方式會進入OnStateEnded 1. Ability結束 2. 手動呼叫AGameplayAbility::EndAbilityState 3. 另一個StartAbilityState啟動並且勾選bEndCurrentState AGameplayAbility::CancelAbility被呼叫的時候會進OnStateInterrupted。 VisualizeTargeting Spawn target actor,並且呼叫TargetActor->StartTargeting。 在StartTargeting裡面會讓TargetActor知道可以Visualize TargetActor。 TargetActor會把視覺化的部份交給AGameplayAbilityWorldReticle做處理。 因為我的實驗環境沒有實作TargetActor相關的函式, 所以實際上我沒有測試效果是怎麼樣。 Wait系列 WaitAbilityActivate 偵測AbilityActivate的事件,並且取得Ability Reference 透過GameplayTag/Query/TagRequirements來決定事件的通知。 WaitAbilityCommit 偵測AbilityCommit的事件,並且取得Ability Reference WaitDelay Delay一段時間 WaitGameplayEvent 非常重要的Task,GAS系統與外部系統大多都是使用Event在溝通。 通常用法是等待多個事件,再根據不同的Tag決定事件要如何處理。 WaitGameplayTag 分為Add或是Remove。 核心是靠AbilitySystemComponent(ASC)->RegisterGameplayTagEvent RegisterGameplayTagEvent實際上對GameplayTagEventMap註冊事件 GameplayTagEventMap事件只有TagCount變為0或是從0變為其他值才會發送 如果想知道TagCount變動事件要在註冊的時候Type設為 EGameplayTagEventType::AnyCountChange 搜尋RegisterGameplayTagEvent可以看到範例。 WaitMovementModeChange 跟Chatacter->MovementModeChangedDelegate註冊事件 呼叫SetWaitingOnAvatar,跟Ability說有個Task註冊跟Avatar相關的事件。如果 AvatarActor有問題會直接結束執行這個Task的Ability。 WaitOverlap 對Avatar的PrimitiveComponent註冊OnComponentHit事件 事件發生後製作TargetData,並轉成Handle送出。 可能只能當作範例,直接使用不太好用。 1. 通常會知道要關注哪個Component。 2. 通常不會每個Hit都需要直接轉成Handle,有可能還要做一些過濾。 WaitTargetData 負責處理一整套作 SpawnTargetActor->ConfirmTarget->產生TargetData的流程, 也會負責處理網路同步(Client給Server) 註解有說明每次都會SpawnActor,所以效率不是很好, 也提到這個Task並沒有經過大量驗證, 但是可以用來學習Target同步的方法。 只要不是CustomMulti的ConfirmationType,都會直接EndTask, 並且殺掉SpawnedTargetActor。 (OnDestroy) 也就是說,當Confirm後,TargetActor就刪除了。除非是CustomMulti。 WaitVelocityChange 利用Tick檢查ActorInfo的速度是否大於參數Magnitude, 如果有就發送事件。 WaitAttribute系列 OptionalExternalOwner讓這個系列的Task可以偵測特定的角色, 不侷限於Task的擁有者。 WaitAttributeChange 偵測AttributeChange有變動的時候發送事件。 可以使用SrcTag來過濾 WaitAttributeChangeRatioThreshold 偵測兩個Attribute的比例改變的時候發送事件。 由ComparsionType決定什麼條件才會發送事件 WaitAttributeChangeThreshold 偵測Attribute的比例改變的時候發送事件。 由ComparsionType決定什麼條件才會發送事件。 WaitInput系列 WaitCancel 偵測GenericLocalCancelCallbacks事件, 玩家觸發InputAction:AbilityCancel的時候會收到。 WaitConfirm LocalPredict的Ability如果想知道Server已Confirm這個Ability的話, 透過這個事件可以知道。 Client::ActivateAbility->Client::WaitConfirm進入等待 Server::ActivateAbility->Client收到AbilityConfirm事件發送, Client才會通過WaitConfirm。 WaitConfirmCancel 跟WaitConfirm名字很像但意義差很大, 這邊指的是玩家已經進入Targeting, 結果在等待Confirm的階段取消的事件。 以實際上案例說明就是,玩家按了某個鍵會舉槍(進入Targeting), 要再按另一個鍵A才會開槍(Confirm)。 或是按另一個鍵B把槍放下(ConfirmCancel) 按下A就是進WaitConfirm。 按下B就是進WaitConfirmCancel。 WaitInputPress AbilitySystemComponent::AbilityLocalInputPressed 裡面做檢查 AbilitySystemComponent::BindAbilityActivationToInputComponent 裡面定義按鍵 按鍵定義都在FGameplayAbilityInputBinds GiveAbility的時候要定義Ability與inputID的關係 WaitInputRelease AbilitySystemComponent::AbilityLocalInputReleased 其餘關鍵與InputPress一樣。 WaitGameplayEffect系列 WaitGameplayEffectApplied_Self與Target Effect被Apply的時候會收到事件。 條件很多,除了可以用Source/Target的tag當過濾條件, 還可以用Query當過濾條件, 是不是要收到Periodic Effect事件也可以分開決定。 SourceFilter是比較少看到的過濾條件, 預設可以過濾掉不是自己,或只能是自己, 或是特定的actor等等的條件,也可以製作自定義的Filter。 WaitGameplayEffectBlockedImmunity 如果有Effect被Immunity的功能擋掉的話會收到通知。 WaitGameplayEffectRemoved Effect被移除的時候送通知,需要傳入EffectHandle。 WaitGameplayEffectStackChange Effect堆疊數量有變動的時候送通知,需要傳入EffectHandle。 常用的GameplayTasks與使用情境 這邊列出我們專案常用的Task組合, 需要注意的是我們專案沒有引入input與target, 所以這兩個部分相關的Task都沒有被列入。 PlayMontageAndWait WaitGameplayEvent 在我們的專案大量使用到 Ability觸發-> 播放動作-> 動作的某個時機發射子彈-> 傷害判定與計算,這樣的模式。 所以PlayMontageAndWait是我們的技能一定會呼叫的, 這部份算是簡單易懂。 不過動作的時機要如何回到Ability,就需要靠WaitGameplayEvent了。 首先要做一個AnimNotify, 開出GameplayTag為Editable參數, 然後將Tag作為參數呼叫SendGameplayEventToActor, 這樣發事件就結束了。如下圖 [圖] Example of send gameplay event in animation notify. 回到Ability的BP,我們需要的是註冊GameplayEvent, 所以利用WaitGameplayEvent作事件等待。 如此一來,只要Animation notify填的 gameplayTag與Ability等待事件的Tag有對上, 就能夠在這個Ability得到事件的通知。 在ActionRPG的範例裡面,他們直接延伸PlayMontageAndWait, 整合一事件通知與動作播放,名為PlayMontageAndWaitForEvent。 確實是很方便。如下圖的Event Tags。 [圖] 但是Ability並不一定只想收到動作的事件通知, 有可能會從其他系統的事件過來, 如此一來還是需要撰寫WaitGameplayEvent。 最後我們為了有統一的入口, 並沒有採取PlayMontageAndWaitForEvent的作法。 我們擴充的是ActionRPG中EffectContainerMap的概念, 對EffectContainerMap內將所有的Tag註冊事件, 然後統一在HandleGameplayEvent裡面處理。 這樣不管是外部事件,動畫事件, 幾乎只需要看Ability的EffectContainerMap欄位, 就能了解這個Ability的行為與效果。 如下圖: [圖] 假設一個ContainerMap裡面有兩筆資料 一個EventTag 是SpawnBullet 然後Effect是給傷害 一個EventTag 是ApplyBuff 然後Effect是回血 這樣企劃或程式只要打開這個ability看ContainerMap的部份, 就可以知道 "嗯...這應該是會發射一個子彈給對方傷害, 然後打中可能會回血,或是發射就回血的技能" 如果想要知道回血時機, 就是透過Tag搜尋功能去查ApplyBuff是在哪裡被用到就可以了。 結論 引擎雖然提供很多AbilityTask,但是我稍微看過一輪之後, 覺得AbilityTask比較像是一個教學範本。 學習者應該從裡面的程式碼知道AbilitySystem系統內如何溝通, 以及如何跟外部系統溝通,以及如何處理網路同步。 直接就使用內建的可能會遇到很多問題, 但是相信他們都把複雜的情況做出來了, 剩下的就是靠使用者繼承這些Task並完善他們。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 1.162.116.55 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/GameDesign/M.1597163947.A.96B.html
coolrobin: 想說有貼到FB社團怎麼沒貼到PTT www 08/12 00:40
yekdniw: 原訂是安排周三早上發文 本篇因特殊原因先發表 08/12 01:54
metallican: 推推 08/12 21:39