AISystemPlugin
創(chuàng)建 Behavior Tree 和 Blackboard
創(chuàng)建行為樹(shù)和黑板:

在黑板中添加一個(gè)Object類型的Key:

將Base Class設(shè)置為Actor:

將行為樹(shù)的Move To函數(shù)中的BlackboardKey設(shè)置為剛剛設(shè)置的AttackTarget:

使用 AIController 運(yùn)行 Behavior Tree 并給 Blackboard 中的變量賦值
創(chuàng)建AIContorller C++類:

需要包含AIModule模塊:

創(chuàng)建AIController藍(lán)圖類:


為Enemy中的AI Controller Class賦值:

將行為樹(shù)和黑板鍵AttackTargetKeyName傳入:

運(yùn)行 Behavior Tree 并給 Blackboard 中的變量賦值

添加Nav Mesh Bounds Volume

按P鍵顯示:

Custom Task
創(chuàng)建Task類C++類:
注意:Task類是UBTTaskNode而不是UBTTask_BlueprintBase藍(lán)圖類型

在行為樹(shù)中添加自定義Task:


Task中的繼承函數(shù):

在BaseEnemy中創(chuàng)建Attack函數(shù)并創(chuàng)建AttackEnd委托:

方法一:在AttackMontage動(dòng)畫播放完成后調(diào)用委托:


在執(zhí)行Task函數(shù)中綁定委托并調(diào)用Attack函數(shù),然后返回InProgress
當(dāng)Attack函數(shù)調(diào)用委托時(shí),就會(huì)調(diào)用HandleAttackEnd函數(shù)來(lái)手動(dòng)結(jié)束任務(wù)
如果是異步執(zhí)行,必須要有AbortTask和OnTaskFinished函數(shù)來(lái)兜底,同步執(zhí)行(ExecuteTask 立即返回 Succeeded/Failed)可以不加

Custom AnimNotify
方法二:使用AnimNotify來(lái)結(jié)束Montage動(dòng)畫:
創(chuàng)建UAnimNotify C++類:


調(diào)用委托:

在Montage動(dòng)畫中添加AnimNotify:


Focus Target Task
用于在攻擊時(shí)Focus Target:
創(chuàng)建Task:

創(chuàng)建黑板鍵,用于在行為樹(shù)中賦值:

獲取黑板,黑板通過(guò)KeyName來(lái)讀取TargetActor,通過(guò)AIController設(shè)置Focus為目標(biāo)角色:

在行為樹(shù)中添加Task并給Attack Target key賦值:

使用Use Contorller Desired Rotation,取消Orient Rotation to Movement:

Clear Focus Task
用于在行走時(shí)清除Focus:




Spawn Weapon Task
創(chuàng)建Weapon類:



在Enemy中創(chuàng)建Spawn Weapon的函數(shù):


創(chuàng)建Task:




Decorator(修飾器)
創(chuàng)建修飾器,用于判斷Enemy是否裝備了武器:


添加修飾器并反轉(zhuǎn):

在Enemy中添加bool變量用于判斷:

當(dāng)Spawn武器后,bWeaponEquipped設(shè)置為true:

修飾器:


按路線巡邏
創(chuàng)建Actor類型用作Patrol Route:

添加更新PatroulRoute的函數(shù)和獲取當(dāng)前PointLocation的函數(shù):


創(chuàng)建藍(lán)圖類:


將藍(lán)圖拖到Map中:

創(chuàng)建Interface:

創(chuàng)建一個(gè)獲取PatrolRoute的純虛函數(shù):

在Enemy中實(shí)現(xiàn)這個(gè)純虛函數(shù):


創(chuàng)建按路線巡邏Task:


通過(guò)Actor來(lái)獲取Interface,從而獲取到對(duì)應(yīng)的PatrolRoute,通過(guò)PatrolRoute獲取到對(duì)應(yīng)的點(diǎn)位置,MoveTo到點(diǎn)位置,MoveTo完成后調(diào)用OnMoveCompleted函數(shù),在回調(diào)函數(shù)中更新PatrolRoute,若被打斷,則停止Move:

其中AbortTask中必須加上RemoveDynamic,否則中斷時(shí)會(huì)靜止不動(dòng):

設(shè)置Enemy的Patrol Route:

設(shè)置行為樹(shù):

設(shè)置移動(dòng)速度
創(chuàng)建Interface用于設(shè)置速度:

創(chuàng)建速度類型的Enum:

在Enemy中重寫純虛函數(shù):


創(chuàng)建Task:

在行為樹(shù)中賦值SpeedType:

使用接口調(diào)用SetMovementSpeed:

在行為樹(shù)中使用:

隨機(jī)巡邏
添加修飾器,判斷是否有路線:



如果沒(méi)有路線則進(jìn)行隨機(jī)巡邏:
在Build中添加NavigatonSystem模塊:

在Enemy中添加獲取隨機(jī)巡邏點(diǎn)的函數(shù)并設(shè)置巡邏范圍,以及MoveTo可接受范圍:

使用NavigationSystemV1來(lái)獲取可導(dǎo)航區(qū)域的隨機(jī)點(diǎn):

創(chuàng)建隨機(jī)巡邏的Task:


在Task中MoveToLocation,如果當(dāng)前的RandomLocation已經(jīng)處于AcceptRadius范圍內(nèi),則直接返回成功,否則會(huì)導(dǎo)致Enemy不返回任何值從而卡住:

其中AbortTask中必須加上RemoveDynamic,否則中斷時(shí)會(huì)靜止不動(dòng):

在行為樹(shù)中添加:

創(chuàng)建State

在黑板中添加Enum:

設(shè)置EnumeName與cpp中的Enum名稱一樣:

在Selector中添加BlackBoard的Decorator:

如果BlackBoard中的State==Attacking,則進(jìn)入:

如果BlackBoard中的State==Passive,則進(jìn)入:

添加ClearFocus:

添加AIStateKeyName并添加設(shè)置EnemyState的函數(shù):

初始化設(shè)置為Passive:

添加拔劍和收劍
在Enemy中:
創(chuàng)建動(dòng)畫結(jié)束事件的委托
創(chuàng)建PlayMontage函數(shù)
設(shè)置Sword綁定位置的DrawSword函數(shù):(SheatheSword同理)


創(chuàng)建DrawSword的Task:

在Task中調(diào)用Enemy來(lái)播放蒙太奇動(dòng)畫并綁定DrawSwordEnd委托:

創(chuàng)建DrawSword的AnimNotify:

調(diào)用Enemy的DrawSword用于切換Sword的綁定位置:

創(chuàng)建DrawSwordEnd的AnimNotify:

在DrawSwordEnd結(jié)束事件中調(diào)用在DrawSword Task中實(shí)現(xiàn)的委托OnDrawSwordEnd:

創(chuàng)建IsSwordDrawed的修飾器:

返回bSwordDrawed:

在Montage中添加DrawSword和DrawSwordEnd的AnimNotify:

取消Enable Root Motion,否則無(wú)法Focus Target:

在行為樹(shù)中添加DrawSword和SheatheSword:

添加AI Perception Component(AI感知系統(tǒng))和Team(隊(duì)伍系統(tǒng))
創(chuàng)建TeamType的枚舉類型,并添加轉(zhuǎn)換的輔助函數(shù):

創(chuàng)建TeamComponent,用于在Character中設(shè)置Team:

繼承IGenericTeamAgentInterface,并重寫GetGenericTeamId函數(shù),初始化TeamId為Player:

返回TeanId:

創(chuàng)建藍(lán)圖類:

在Character中添加TeamComponent:

在AIController中添加AIPerception并重寫Team類:

重寫Team函數(shù):

配置AIPerception:

在Character中臨時(shí)加入測(cè)試:

按下”鍵并按下小鍵盤4鍵:測(cè)試AIPerception

配置AIPerception
創(chuàng)建感知處理函數(shù)
創(chuàng)建AIPerception自帶的感知回調(diào)函數(shù)
創(chuàng)建興趣點(diǎn),用于Enemy調(diào)查興趣點(diǎn)
創(chuàng)建最大檢測(cè)距離和最大移動(dòng)距離,用于Enemy受到Damage時(shí),不會(huì)一直走到興趣點(diǎn),而是朝向興趣點(diǎn)移動(dòng):

綁定函數(shù):

通過(guò)SenseID來(lái)調(diào)用不同的感知回調(diào)函數(shù):

在感知狀態(tài)中設(shè)置對(duì)應(yīng)的EnemyState:


Investigate中設(shè)置興趣點(diǎn):

創(chuàng)建設(shè)置EnemyState的Task:



要想使用OnTargetPerceptionForgotten,必須在AIPerception中設(shè)置Age(最大記得的事件)不能為0,并且勾選Forget Stale Actors:

在黑板中創(chuàng)建PointOfInterest:

創(chuàng)建Investigate的行為樹(shù):

EQS
創(chuàng)建EQS:


在藍(lán)圖中創(chuàng)建用于測(cè)試EQS的Pawn:


將Pawn拖入世界中:

創(chuàng)建Context類用于將攻擊目標(biāo)設(shè)置為查詢系統(tǒng)的上下文數(shù)據(jù):

從EnemyAIController中存儲(chǔ)AttackTarget:



在EQS中設(shè)置Circle Center為AttackTarget,這樣就會(huì)圍繞角色生成一圈的球:
通過(guò)PathExist確保球體是Enemy可以到達(dá)的:
通過(guò)DIstance確保Enemy只會(huì)在左右最近的兩個(gè)球體中選擇:


創(chuàng)建一個(gè)新的Context用于Test:

獲取Player Start作為中心點(diǎn)用于測(cè)試:


在行為樹(shù)中添加Strafe并為Attack添加Cooldown:

完善Strafe的EQS
創(chuàng)建Decorator判斷是否處于目標(biāo)范圍內(nèi):

在Interface中創(chuàng)建獲取AttackRadius和DefendRadius的函數(shù):

在Enemy中初始化:

在Enemy中實(shí)現(xiàn)Interface:

判斷Enemy與AttackTarget的距離是否小于目標(biāo)值:


創(chuàng)建MoveToTargetRange的Task,將Acceptance Radius作為黑板參數(shù)傳遞:



在黑板中創(chuàng)建兩個(gè)Radius:

在Strafe中加上判斷是否處于防御范圍內(nèi),若不處于,則MoveToTargetRange到防御范圍:

添加FindCover的EQS
創(chuàng)建EQS:

添加Trace,確保在Target看不見(jiàn)的地方,并設(shè)置Item Height:

在行為樹(shù)中添加FindCover:

添加子類Enemy并添加SubBehaviorTree
創(chuàng)建BaseEnemy的子類,用于設(shè)置近戰(zhàn)Enemy和遠(yuǎn)程Enemy:


創(chuàng)建兩個(gè)樹(shù)用于作為子樹(shù):

將樹(shù)中的Investigate邏輯復(fù)制到子樹(shù)中:

添加一個(gè)FocusToDamageCauser,確保直接轉(zhuǎn)向DamageCauser:


將樹(shù)中的Patrol邏輯復(fù)制到子樹(shù)中:

在樹(shù)中使用Run Behavior來(lái)替代原有邏輯:

為近戰(zhàn)Enemy和遠(yuǎn)程Enemy分別創(chuàng)建行為樹(shù):

將BaseEnemy中的大部分邏輯刪除:

近戰(zhàn)Enemy:

在不同的Enemy中設(shè)置對(duì)應(yīng)的BehaviorTree,然后再傳遞為AIController:

設(shè)置遠(yuǎn)程敵人的BehaviorTree
創(chuàng)建開(kāi)火的Notify


通過(guò)射線檢測(cè)來(lái)ApplyDamage并ReportDamageEvent給AIPerception:

在Notify中調(diào)用Fire:

創(chuàng)建Decorator判斷Enemy是否能看見(jiàn)Target:


創(chuàng)建Health和Damage:


創(chuàng)建恢復(fù)Health的Task:


創(chuàng)建判斷是否Health低于閾值的函數(shù):


如果在Attack中,Health低于閾值,則執(zhí)行FindCover的EQS移動(dòng)到Cover并HealHealth:
如果Enemy看不見(jiàn)Target,則MoveToSeeTarget:

添加Sword
在Weapon中添加Box和Start,End:

創(chuàng)建Box的OnOverlap函數(shù),當(dāng)Overlap時(shí),通過(guò)Start和End的位置來(lái)BoxTrace判斷是否碰到Block Visibility Channel的物體:

設(shè)置Weapon的Owner:

設(shè)置Enemy的Mesh為WorldDynamic,從而與Capsule進(jìn)行區(qū)分,并將Visibility設(shè)置為Block,從而可以進(jìn)行BoxTrace:

在Enemy中創(chuàng)建EnableCollision和DisableCollision并清空IgnoreActors防止重復(fù)檢測(cè):

創(chuàng)建AnimNotifyState:

開(kāi)始時(shí)啟用Collision,結(jié)束時(shí)關(guān)閉:

在CanSeeTarget中也需要Ignore目標(biāo),不然會(huì)被Target的Visibility通道阻擋并返回,從而導(dǎo)致一直CanNotSeeTarget:

在AttackMontage中添加AnimNotifyState:

在劍中添加Box和Start,End:

添加Dead和HitReaction動(dòng)畫
添加Service,用于當(dāng)Enemy的Attack目標(biāo)死亡時(shí),將Enemy的State重新設(shè)置為Passive:



在Attack上添加Service:

在Enemy的TakeDamage中添加GetHit和Die的函數(shù):

GetHit通過(guò)角度來(lái)判斷受擊方向,HitReactMontage設(shè)置為可以與其他動(dòng)畫一起播放,如果在Attack,則不播放GetHitMontage:

Die不使用動(dòng)畫,使用模擬物理來(lái)達(dá)到布娃娃效果:

在Attack中設(shè)置是否被打斷,打斷則調(diào)用OnAttackEnd:

創(chuàng)建各個(gè)方向的GetHitAnimation,并創(chuàng)建一個(gè)新的Slot專門用于播放GetHitMontage:

在Anim中使用LayeredBlendPerBone來(lái)融合播放GetHitMontage:


浙公網(wǎng)安備 33010602011771號(hào)