最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

TomLooman_ActionRoguelike_第十一章自定義任務(wù)和EQS的AI

2023-08-18 15:14 作者:別叫我小紅  | 我要投稿

該專欄用于保存對(duì)TomLooman的ActionRoguelike項(xiàng)目的學(xué)習(xí)筆記,學(xué)習(xí)過(guò)程中的思考與記錄不一定準(zhǔn)確。


教程參考:https://github.com/tomlooman/ActionRoguelike

基于UE5.0的項(xiàng)目實(shí)現(xiàn):https://github.com/CarolBaggins2023/TomLooman_ActionRogueLike_Tutorial.git

自定義任務(wù)和EQS的中級(jí)AI:用于遠(yuǎn)程攻擊的自定義C++行為樹(shù)任務(wù),環(huán)境查詢,感應(yīng)組件,改進(jìn)機(jī)器人動(dòng)畫(huà)

?

我們之前在行為樹(shù)中插入了MoveTo和Wait這兩個(gè)自帶的節(jié)點(diǎn),除了自帶節(jié)點(diǎn)外,我們還可以自定義行為樹(shù)節(jié)點(diǎn),并插入行為樹(shù)。

?

像MoveTo和Wait這樣表示具體行為的節(jié)點(diǎn)稱為Task節(jié)點(diǎn),我們?cè)谔砑庸?jié)點(diǎn)時(shí)Task那一欄下面可以找到它們。

?

我們可以自定義遠(yuǎn)程攻擊的任務(wù)節(jié)點(diǎn),先創(chuàng)建BTTaskNode的C++類。


在BTTaskNode基類中,這里用到了成員函數(shù)virtual EBTNodeResult::Type ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory);

,該函數(shù)表示開(kāi)始該節(jié)點(diǎn)代表的任務(wù)。

我們?cè)谧远x的行為樹(shù)任務(wù)節(jié)點(diǎn)類中覆蓋它。我們要進(jìn)行遠(yuǎn)程攻擊,這里的邏輯是,遠(yuǎn)程攻擊其實(shí)就是Spawn子彈類實(shí)例(參考角色的遠(yuǎn)程攻擊),而Spawn時(shí)需要Spawn的Location和Rotation,Location來(lái)自機(jī)器人,Rotation來(lái)自機(jī)器人和目標(biāo)(這里就是玩家)的Location的差值。所以我們要在任務(wù)節(jié)點(diǎn)類的成員函數(shù)中訪問(wèn)機(jī)器人和玩家。因?yàn)镋xecuteTask的參數(shù)中有使用該節(jié)點(diǎn)的行為樹(shù),可以從該行為樹(shù)入手,那么就類似于之前的Service節(jié)點(diǎn)(行為樹(shù)作為TickNode函數(shù)參數(shù)),(1)通過(guò)行為樹(shù)訪問(wèn)使用行為樹(shù)的AI控制器,再通過(guò)AI控制器訪問(wèn)被控制的機(jī)器人,(2)通過(guò)行為樹(shù)訪問(wèn)行為樹(shù)使用的黑板,通過(guò)黑板得到TargetActor(到這里為止,TargetActor是在AIController的BeginPlay中被定義的)。

ExecuteTask函數(shù)返回行為樹(shù)節(jié)點(diǎn)的運(yùn)行結(jié)果,包括Succeeded, Failed or InProgress,這里我們將在C++類中定義了,但是在藍(lán)圖中沒(méi)有賦值資產(chǎn)的情況作為Failed。


因?yàn)閷?shí)現(xiàn)中用到了子彈類型,所以我們也要將子彈類型作為類的成員變量,并在編輯器中進(jìn)行賦值。


?

在創(chuàng)建自定義的任務(wù)節(jié)點(diǎn)后,我們可以在行為樹(shù)中執(zhí)行它。我們想實(shí)現(xiàn)這樣一個(gè)效果,當(dāng)玩家在機(jī)器人射程內(nèi)時(shí),機(jī)器人攻擊三次,然后進(jìn)入一段時(shí)間的冷卻,我們先實(shí)現(xiàn)了下面的行為樹(shù)分支,

其中的Cooldown節(jié)點(diǎn)控制它的子樹(shù)的執(zhí)行間隔,Loop節(jié)點(diǎn)控制它子樹(shù)的循環(huán)執(zhí)行次數(shù)。但是這里Wait和RangedAttack只執(zhí)行了一次,因?yàn)镃ooldown節(jié)點(diǎn)認(rèn)為一次循環(huán)就算是一次執(zhí)行,所以執(zhí)行一次Wait和RangedAttack馬上進(jìn)入冷卻。因此,我們不能把Cooldown節(jié)點(diǎn)和Loop節(jié)點(diǎn)放在一起。而是要采用下面的結(jié)構(gòu),

這里的第一個(gè)節(jié)點(diǎn)時(shí)Sequence或Selector都可以,因?yàn)橹笫菃畏种也蛔雠袛?。這樣的結(jié)構(gòu)能夠?qū)崿F(xiàn)我們的目標(biāo)。

另外,這里的黑板節(jié)點(diǎn)要設(shè)置對(duì)低優(yōu)先級(jí)的監(jiān)聽(tīng)中斷,也就是一旦玩家進(jìn)入機(jī)器人射程,就執(zhí)行攻擊,而不是等Wait5s或者尋找玩家的分支執(zhí)行完成。也可以同時(shí)設(shè)置對(duì)自身的監(jiān)聽(tīng)中斷,這樣一來(lái),當(dāng)機(jī)器人在攻擊時(shí),如果玩家走出攻擊范圍,則機(jī)器人停止攻擊。

?

我們可以讓我們的機(jī)器人時(shí)刻面朝玩家,這可以通過(guò)行為樹(shù)中的Focus服務(wù)實(shí)現(xiàn),也就是說(shuō)Focus也類似于每個(gè)一段時(shí)間執(zhí)行一次的函數(shù)。

?

?

現(xiàn)在我們的機(jī)器人的行動(dòng)路徑都是筆直地朝玩家走來(lái),這是比較恐怖的。所以我們想對(duì)此進(jìn)行修改,讓機(jī)器人先在一定范圍內(nèi)運(yùn)動(dòng),當(dāng)靠近玩家后再執(zhí)行上面定義的攻擊任務(wù)。我們通過(guò)UE的Environment Query System(EQS)實(shí)現(xiàn)這個(gè)功能。

EQS可以對(duì)場(chǎng)景中的信息(比如位置)進(jìn)行打分,根據(jù)打分結(jié)果對(duì)信息進(jìn)行篩選,然后選擇合適的信息給AI機(jī)器人使用。例如在這里,我們可以通過(guò)EQS對(duì)環(huán)境中的一些位置進(jìn)行打分,打分的依據(jù)是該位置與玩家的距離,然后篩選掉距離玩家太遠(yuǎn)的一些位置,最后將距離玩家最近的位置或者隨機(jī)一個(gè)比較近的位置作為行為樹(shù)中MoveTo節(jié)點(diǎn)的目標(biāo)。

?

我們可以在Artificial Intelligence里新建Environment Query,

環(huán)境查詢的結(jié)構(gòu)和行為樹(shù)有點(diǎn)像,我們可以從根節(jié)點(diǎn)引出Generator節(jié)點(diǎn),Generator節(jié)點(diǎn)的作用是在環(huán)境中生成一些表示位置的點(diǎn)或者Actor,來(lái)供后續(xù)打分和篩選,這里我們選擇了Points: Donut,來(lái)生成圓弧分布的點(diǎn)。

在DonutGenerator中,我們可以選擇點(diǎn)所在圓弧的內(nèi)外半徑、方向、角度等。

接著我們可以在Generator中添加一些Test用來(lái)對(duì)Generator產(chǎn)生的點(diǎn)進(jìn)行篩選,這里我們先講Distance。

DistanceTest根據(jù)生成點(diǎn)與指定對(duì)象的距離,對(duì)生成點(diǎn)進(jìn)行篩選。這里的指定對(duì)象可以是使用該EQS的對(duì)象(我們之后會(huì)將它作為行為樹(shù)的節(jié)點(diǎn),那么就是使用帶有這個(gè)EQS的行為樹(shù)的機(jī)器人),也可以是我們自定義的環(huán)境查詢背景(后面講)。

這里的Test Purpose項(xiàng)包括篩選、打分、打分并篩選,單純打分不會(huì)篩去生成的點(diǎn)。篩選可以根據(jù)距離的上下限等,打分可以設(shè)置參數(shù)。

?

創(chuàng)建完環(huán)境查詢后,我們可以在行為樹(shù)中添加執(zhí)行環(huán)境查詢的節(jié)點(diǎn),

我們用剛剛創(chuàng)建的環(huán)境查詢對(duì)EQS節(jié)點(diǎn)進(jìn)行賦值。這里的RunMode指在通過(guò)篩選的節(jié)點(diǎn)中選擇哪一個(gè),可以選分?jǐn)?shù)最高的,或者分?jǐn)?shù)前5%之類的。這里的BlackboardKey很關(guān)鍵,它是EQS與任務(wù)直接關(guān)聯(lián)的一個(gè)參數(shù),決定了EQS最終選擇的點(diǎn)(或者Actor)要賦值給行為樹(shù)的黑板中的哪個(gè)參數(shù)。

因?yàn)檫@里我們?cè)贓QS中生成的是點(diǎn)(FVector),所以我們將其賦給MoveToLocation,并在MoveTo節(jié)點(diǎn)中使用。

此外我們希望,當(dāng)玩家在機(jī)器人攻擊范圍內(nèi),但機(jī)器人的攻擊處于冷卻時(shí),機(jī)器人會(huì)隨意地走動(dòng),所以我們刪除了MoveToSequence上的黑板節(jié)點(diǎn),這樣即使WithinAttackRange為true,也會(huì)執(zhí)行下面的MoveTo任務(wù)。

?

在上面的實(shí)現(xiàn)中,我們?cè)贓QS中以機(jī)器人為中心生成了一些點(diǎn)作為機(jī)器人運(yùn)動(dòng)的目標(biāo),并根據(jù)這些點(diǎn)與機(jī)器人的距離進(jìn)行篩選。但是我們其實(shí)應(yīng)該在玩家周圍生成這些點(diǎn),這樣才能讓機(jī)器人靠近玩家。但是DonutPoints的Center參數(shù)選項(xiàng)中并沒(méi)有玩家,所以我們要自定義一個(gè)Environment Query Context(環(huán)境查詢背景)。

我們通過(guò)創(chuàng)建藍(lán)圖的方式自定義一個(gè)環(huán)境查詢背景,

我們可以在其中覆蓋一些函數(shù),根據(jù)我們想要這個(gè)環(huán)境查詢返回什么來(lái)決定(位置或者是Actor)。因?yàn)檫@里我們想要得到對(duì)玩家的查詢結(jié)果,而不僅是對(duì)玩家位置的查詢結(jié)果,所以覆蓋ProvideSingleActor。

藍(lán)圖中的邏輯和機(jī)器人遠(yuǎn)程攻擊中訪問(wèn)玩家的邏輯相同,都是通過(guò)AIController獲得行為樹(shù)的黑板,再獲取黑板中的TargetActor變量。

然后我們就可以在EQS中使用這個(gè)ContextQueryContext了,我們將它作為DonutPoints的中心,以及修改圓弧方向。

?

現(xiàn)在我們已經(jīng)實(shí)現(xiàn)了在玩家周圍生成一些點(diǎn),機(jī)器人向這些點(diǎn)移動(dòng),如果玩家進(jìn)入攻擊范圍則執(zhí)行攻擊任務(wù)。但我們不希望機(jī)器人與目標(biāo)點(diǎn)之間有障礙物,比如一堵墻,此時(shí)我們可以使用TraceTest節(jié)點(diǎn)。

Trace節(jié)點(diǎn)類似于我們之間制作物體交互功能時(shí)使用的LineTrace,可以檢測(cè)從某個(gè)環(huán)境查詢背景出發(fā)(或到某個(gè)環(huán)境查詢背景截止)的射線途中是否與其他物體發(fā)生碰撞。當(dāng)Filter中的Bool Match為true時(shí),則有碰撞的點(diǎn)被保留,否則無(wú)碰撞的點(diǎn)被保留。

?


到目前為止,機(jī)器人會(huì)嘗試逐漸靠近玩家,但是這個(gè)玩家是我們?cè)贏IController的Beginplay中通過(guò)UGameplayStatics::GetPlayerPawn(this, 0)實(shí)現(xiàn)的。我們希望機(jī)器人能去靠近自己“看見(jiàn)”的玩家。為了讓機(jī)器人擁有“視覺(jué)”,我們可以使用PawnSensing組件。(還有一種方法是用AIPerception,相比之下PawnSensing雖然比較老,但是比較容易)

我們將PawnSensing組件作為AICharacter的成員變量。UPawnSensingComponent中聲明了一個(gè)單參數(shù)委托,監(jiān)聽(tīng)擁有該組件的對(duì)象是否看見(jiàn)其他Pawn,并在觸發(fā)后進(jìn)行廣播。所以我們的AICharacter中需要有一個(gè)成員函數(shù)與該委托綁定,并在該成員函數(shù)中完成對(duì)行為樹(shù)的黑板中TargetActor變量的賦值。

以下是該成員函數(shù)的實(shí)現(xiàn),并且我們?cè)赑ostInitializeComponents中完成函數(shù)與委托的綁定(比在構(gòu)造函數(shù)中綁定更安全)。

因?yàn)樵贏ICharacter中完成了對(duì)TargetActor的賦值,所以AIController中基于UGameplayStatics::GetPlayerPawn(this, 0)的賦值就可以取消了。

?

在機(jī)器人的藍(lán)圖中,我們可以對(duì)PawnSensing組件的參數(shù),比如視野大小等,進(jìn)行調(diào)整。

?

但是此時(shí)出現(xiàn)了一個(gè)問(wèn)題,就是我們只有在第一看見(jiàn)玩家后,機(jī)器人的TargetActor才有值。在此之前,因?yàn)樾袨闃?shù)黑板的TargetActor為空,那么我們自定義的環(huán)境查詢背景返回空值,行為樹(shù)中的EQS無(wú)法運(yùn)行,黑板中的MoveToLocation就沒(méi)有值,MoveTo任務(wù)就無(wú)法運(yùn)行,最終機(jī)器人也就不會(huì)運(yùn)動(dòng)。

所以,當(dāng)黑板的TargetActor為空時(shí),我們?cè)谧远x的環(huán)境查詢背景中要直接給TargetActor一個(gè)值,如下

?

?

另外是一些角色動(dòng)畫(huà)的內(nèi)容。在移動(dòng)組件中,我們可以選擇UseControllerDesiredRotation來(lái)讓角色的轉(zhuǎn)向不那么突兀,而是有一定過(guò)度,更加自然。在選擇UseControllerDesiredRotation的同時(shí),我們要取消UseControllerRotationYaw。這兩者是沖突的,因?yàn)樗鼈兌伎刂平巧腞otation,同樣沖突的還要加上前面玩家角色控制中提到的GetCharacterMovement()->bOrientRotationToMovement。


TomLooman_ActionRoguelike_第十一章自定義任務(wù)和EQS的AI的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
蓝田县| 柳江县| 涟源市| 武平县| 谢通门县| 衢州市| 天峻县| 广东省| 体育| 泌阳县| 鄂伦春自治旗| 新源县| 丁青县| 内乡县| 阿拉善左旗| 天水市| 睢宁县| 巩留县| 庄浪县| 井研县| 蒙自县| 海安县| 镶黄旗| 加查县| 昌都县| 赫章县| 镇康县| 珠海市| 阜平县| 茌平县| 乌拉特中旗| 长子县| 安顺市| 息烽县| 巫溪县| 长阳| 武汉市| 横山县| 米林县| 延边| 图木舒克市|