斯坦福UE4C++課程P46-P49AI、EQS再生邏輯
首先回顧任務3
為了能夠拓展Health Potion,我們可以寫一個PowerupActor基類,供生命藥水類繼承。
這個基類繼承自AActor和ISGameplayInterface,設置一個Mesh組件,具體邏輯在Interact_implementation函數(shù)實現(xiàn)。
然后我們要讓OnHealthChanged事件發(fā)生時的傷害顯示到視口中(使用Damage控件藍圖變量的Expose on Spawn)。
我們在Damage控件藍圖新建變量DamageDelta,勾選Expose on Spawn。此時創(chuàng)建Damage控件節(jié)點多出來DamageDelta變量可賦值,用角色類藍圖的OnHealthChanged(AttributeComp)事件的Delta連上DamageDelta即可。

在Damage控件藍圖給傷害文本綁定函數(shù),只需把DamageDelta作為返回值即可。

此時所受傷害值顯示在角色上。


然后是布置作業(yè)4

我們之后的工作會基于視頻內(nèi)容和作業(yè)內(nèi)容,所以需要保留在項目中。
我們需要給AI添加低生命值時前往遠離玩家位置,并緩慢回血功能(60秒一次)。
首先我們給AI添加掉血、死亡功能(具體方法參考前面給角色添加的同樣的功能,牽扯到Damage控件藍圖、動畫藍圖),復制作者github的Minion模型發(fā)現(xiàn)動畫藍圖中有為我們做好的一部分功能,直接用即可。
AI死亡邏輯簡單地在AI角色藍圖用:

接下來正式做作業(yè)4
依次添加Service、EQS、Task。
行為樹如下:

首先是檢查低血量的Service:
先在AIController類中給SelfActor黑板鍵賦值為GetPawn(),然后在檢查低血量Service類cpp文件中:(我們在Attribute類中新寫了若干函數(shù)GetHealth、GetHealthMax、SetHealthToMax以便于判斷血量、設置血量)
回到UE編輯器,新建EQS,讓AI前往遠離玩家、靠近自己的地點。

新建Task,ExecuteTask函數(shù)如下:
現(xiàn)在,除了60秒冷卻時間沒做之外,AI行為樹從根執(zhí)行,檢查到LowHealth時就會走到特定位置回滿血然后等待8秒,重新從根開始走行為樹(設置了Lower Priority觀察者中止)
60秒冷卻目前不熟悉行為樹節(jié)點,先跳了。

這一章我們用EQS生成AI、豐富AI的功能(死亡(stop behavior、'ragdoll' physics)、受擊邏輯(another 'sense'))
首先新建一個EQS,命名為Query_FindBotSpawn,從Root拖出一個Donut。后面我們將從Gamemode類中生成AI,這里先這樣。
新建一個QueryContext_BlueprintBase繼承藍圖類QueryContext_AllPlayers,重載Provide Actors Set(我們希望返回所有的玩家players)

Get All Actors Of Class遍歷關卡中所有Actor,把SCharacter放入數(shù)組中作為返回值,效率低,但此方法比較便利,況且我們的關卡簡單,沒有特別多Actor。
把Query_FindBotSpawn的Donut節(jié)點的center選為上面的QueryContext。

現(xiàn)在我們在場景中復制我們的角色,并新建一個EQSTestingPawn藍圖類,拖入場景,選擇其EQS為Query_FindBotSpawn?,F(xiàn)在可以看到每個角色周圍300-1000距離有3個8點環(huán)作為生成AI的位置:

我們可以微調(diào)生成位置,打開EQS,選中Donut節(jié)點,半徑選1000-3000,勾上Use Spiral Pattern:

現(xiàn)在一個角色的AI生成點可能離另外一個角色過于近,所以我們在EQS添加一個test,選擇在AllPlayers的至少1000距離之外生成:

現(xiàn)在,我們按P查看導航網(wǎng)格,發(fā)現(xiàn)白色墻下面也有導航網(wǎng)格,所以AI生成點也可能出現(xiàn)在里邊,導致AI生成時被卡在里面。
最理想的辦法,可以從左側拖進場景一個Nav Modifier Volume,覆蓋掉墻里面的導航網(wǎng)格:

此時如果AI生成點落在墻里面,我們讓它嘗試去最近的導航點。打開EQS,選擇Donut節(jié)點->Project Data->Trace Mode為Navigation。此時墻里的AI生成點只剩下墻外的了。
第二種方法代價較高,我們在EQS里添加PathFinding的test:

如果有一排火焰在AI前面,用這種方法可以讓AI刪掉經(jīng)過火焰的路徑。這里我們用這種方法也可以刪掉墻里的生成點;同時,可以避免第一種方法忘記刷掉墻里的導航網(wǎng)格。

接下來我們添加一個游戲模式類,游戲模式類是gameplay框架,包含游戲規(guī)則,指定了從哪個Pawn和Controller開始游戲,所以可以通過選擇不同GameMode來控制不同的角色集合。
新建C++類->選擇Game Mode Base,命名SGameModeBase。
tip:gamemode類沒有BeginPlay函數(shù),因為它負責調(diào)用世界中所有Actor的BeginPlay。所以用StartPlay()代替。
下面我們在Gamemode類寫AI生成邏輯。
.h
.cpp
編譯后,回到UE編輯器,創(chuàng)建SGameModeBase繼承的藍圖類GameModeBP,選擇Minion Class為MinionRangedBP,Spawn Bot Query為之前的生成AI出生點的EQS,保存。最后在World Settings中選擇Game Mode為GameModeBP(意思是針對當前關卡,選擇該游戲模式)。
現(xiàn)在運行游戲,除了開始游戲時的AI外,隔2秒生成的AI站在原地不動。我們只需進入MinionRangedBP,調(diào)整Auto Possess AI為放置在世界&&生成即可。

也可以在AI角色C++類構造函數(shù)設置該選項:
現(xiàn)在運行游戲,AI會不斷生成,沒有數(shù)量限制。我們添加上限,并添加CurveFloat,讓上限隨著時間的變化而變化。內(nèi)容瀏覽器新建CurveFloat,命名為DifficultyCurve,添加4點,0秒1個敵人,5秒2個,10秒5個,60秒10個,還可以調(diào)整函數(shù)曲線的離散性(防止四舍五入)。

我們在GamemodeC++類.h文件添加CurveFloat資產(chǎn):
在.cpp文件設置邏輯:
該節(jié)作者有個bug,因為沒有給AI添加Attribute組件而用了其中的isAlive()函數(shù),而我之前作業(yè)做好了,所以編譯、在藍圖分配資產(chǎn)后正常運行。現(xiàn)在隔2秒生成AI(不超過當前時間的上限):
