斯坦福UE4C++課程P63-P65游戲能力系統(tǒng)GAS
GAS(Game Ability System),在課程里我們稱之為Action Component/Action System,也是為了避免把所有代碼寫到SCharacter而使用的東西。
虛幻引擎的針對abilities、buffs、attributes的框架(和Gameplay框架完全分開,所以和GameMode、PlayerStates、playercontroller這些類無關(guān))
強大的RPG游戲功能集、適配廣泛的游戲類型(對包含少量actions/abilities的小型游戲可能有些不必要)
陡峭的學(xué)習(xí)曲線,沒有大量的文檔
作者給出了一些GAS的學(xué)習(xí)資源,主要是官方文檔、github.com/tranek/GASDocumentation(比官方文檔詳細)。
下面我們準(zhǔn)備創(chuàng)建我們自己的'Action System',比直接在角色類寫代碼擁有更多的靈活性(針對abilities、buffs)。之前我們創(chuàng)建的Attribute組件類其實就是一個類似于GAS的類。
GAS代碼分離:
避免單個類包含所有的關(guān)于ability、VFX的代碼
一種用途的類更易維護(e.g. Action_MagicProjectile, Action_Sprint)
更好的協(xié)作,尤其是針對藍圖(版本控制中無法合并二進制的資產(chǎn))
其他好處:
gameplay時,可提供Abilities、Buffs(e.g. level-ups、gear upgrades、damage-over-time effects)
避免通過“硬鏈接”一次把整個游戲加載到內(nèi)存(GAS更多是通過軟鏈接)
可通過GameplayTags管理大量的state和labels,而不是booleans或者enums(e.g. 'DamageType.Melee.Slashing','Action.IsSprinting','Pawn.Mage','Pawn.Warrior')
不僅僅Player能用Abilities,世界中的actors也能用Actions

這一章我們要做
SActionComponent.h(ActorComponent)
SAction.h(UObject)
首個Action:Sprinting沖刺
重構(gòu)Projectile abilities(扔魔法球、Dash球、黑洞),從SCharacter.h移到Action
SActionComponent.h
SActionComponent.cpp
SAction.h,UCLASS里加Blueprintable是為了能夠被藍圖繼承
SAction.cpp(后面可以在藍圖重寫這兩個函數(shù))
另外,在SCharacter添加Action組件,以及我們要添加的沖刺函數(shù):
在構(gòu)造函數(shù)實例化ActionComp
綁定輸入Action:(按住左shift沖刺,松開停止沖刺)
SprintStart、SprintStop函數(shù):
現(xiàn)在編譯,我們在藍圖里實現(xiàn)沖刺能力Sprint ability。
由于我們給SAction類加了Blueprintable,所以可以在內(nèi)容瀏覽器創(chuàng)建藍圖時看到它。我們創(chuàng)建藍圖Action_Sprint,繼承SAction,并添加一些沖刺的邏輯。后面我們寫projectile ability邏輯仍在C++里實現(xiàn)。
現(xiàn)在打開藍圖,我們在右側(cè)可以看到類默認值有Action Name,填上Sprint;左側(cè)可以點擊重寫StartAction、StopAction函數(shù),彈出兩個節(jié)點。
我們可以右鍵點擊該兩個節(jié)點,選擇調(diào)用父類(在C++里有一句UE_LOG的函數(shù)),表示打印該Action名字在日志里。

另外,我們需要在project settings->Input添加action,名為Sprint,鍵為左Shift。
最后我們在角色類藍圖添加該Action:

表示將實例化的Action Sprint藍圖類添加到ActionComp中。
現(xiàn)在按住左shift加速,松開回到正常速度。
這種添加角色ability的方法,僅僅在角色類藍圖添加了Action,沒有硬編碼的程序,所有具體的ability邏輯都在Action_Sprint藍圖實現(xiàn)。

下面我們在C++中把三種Projectile邏輯(魔法球、Dash球、黑洞)轉(zhuǎn)換為Action。
新建C++類,繼承自SAction ,命名為SAction_ProjectileAttack。SAction_ProjectileAttack是三種projectile繼承的基類(把Dash、黑洞也看成Attack罷了)。
在此類中,我們需要重構(gòu)projectile的基本功能(從角色手中發(fā)出、向十字準(zhǔn)星發(fā)出、各種component),只需要從SCharacter搬過來。
SAction_ProjectileAttack.h
SAction_ProjectileAttack.cpp,從SCharacter照搬的代碼需要改動一點。
其中獲取相機組件位置的語句可以用InstigatorCharacter->GetPawnViewLocation()代替
SCharacter的PrimaryAttack函數(shù)改為:
編譯,回到內(nèi)容瀏覽器,新建繼承自SAction_Projectile的新魔法球攻擊藍圖類Action_MagicProjectile,在右側(cè)details按之前的魔法球設(shè)定選擇資產(chǎn),ActionName選為"PrimaryAttack"。最后一步,我們需要給角色分配該ability,在角色類藍圖AddAction即可。

現(xiàn)在成功移植魔法球攻擊能力。
接下來可以移植Dash、黑洞能力。
只需要在SCharacter改寫B(tài)lackholeAttack、Dash函數(shù):
然后duplicate新魔法球攻擊藍圖,命名為Action_Dash、Action_Blackhole,按原來的設(shè)定分配資產(chǎn);
但現(xiàn)在有一個問題,需要在角色類藍圖一個一個添加ability,我們可以在ActionComponent創(chuàng)建一個array來添加ability(之前在ActionComponent添加的Actions是組件中所有可能存在的能力TArray<USAction*>,而這次我們創(chuàng)建的是我們要讓角色使用的能力TArray<TSubclassOf<USAction>>),要讓角色用該能力就放進去,不要就從中移除。
這樣一來,只需最后在角色類藍圖右側(cè)Default Actions(我們在ActionComponent新加的array的名字)添加四個abilities藍圖類(魔法球、Dash、黑洞、Sprint沖刺)即可。無需beginplay->addactions->addactions->addactions->......了。

此外,把C++中老代碼全部刪除。
下一章我們學(xué)習(xí)GameplayTag。其作用,比如我們希望角色沖刺時不能發(fā)射魔法球,發(fā)射魔法球時也不能沖刺?,F(xiàn)在我們發(fā)射魔法球動畫播放時仍可以發(fā)射第二個魔法球,只要我們手速夠快,每幀都能發(fā)射一個魔法球出去,所以可以限制攻擊時不能再次攻擊。
我們同時按鼠標(biāo)左鍵(魔法球)、Q(Dash)、R(黑洞),它們可以同時發(fā)射,因為我們并沒有限制它們。