原文:Unreal Engine 4 Tutorial: Artificial Intelligence
做者:Tommy Tran
譯者:Shuchang Liuhtml
在本篇教程中,你將學習如何使用行爲樹和AI感知來建立一個能四處走動,攻擊敵人的簡單AI。web
在視頻遊戲中,人工智能(AI)一般指的是擁有自主決策行爲的非玩家角色。AI能夠是看到玩家而後進行攻擊的簡單角色,也能夠是即時策略(RTS)遊戲裏的強大對手。app
在Unreal引擎裏,咱們能夠經過行爲樹建立AI。行爲樹是一個決定AI作哪一種行爲的實時決策系統。好比,若是AI有戰鬥和逃跑兩種行爲。你能夠建立行爲樹,讓AI在高於50%血量時進行戰鬥,低於50%血量時逃跑。dom
在本篇教程中,你將學習到:編輯器
注意:本篇教程只是Unreal Engine 4系列教程的其中一篇:ide
下載示例項目並解壓。進入項目文件夾,雙擊MuffinWar.uproject打開項目。svg
按下Play運行遊戲,在圍欄內點擊左鍵生成蘑菇小人。學習
在本例中,咱們將建立一個能四處走動的AI,當其餘蘑菇小人進入AI的視野時,AI會追逐對方並進行攻擊。動畫
要建立一個AI角色,咱們須要三個元素:ui
如今咱們已經有了身體,接着要搞來靈魂和大腦。首先,咱們要建立控制器做爲靈魂。
控制器是一個能控制角色單位的非物理Actor。這裏所說的「控制」,具體指的是什麼意思呢?
對於玩家而言,控制指的是能經過按鍵操控角色單位。控制器獲取玩家輸入,並將輸入直接傳給角色。固然,控制器也能夠獲取輸入進行處理,而後再告訴角色單位作哪一個行爲。
對於AI來講,角色單位就是由控制器或「大腦」(取決於實現方式)來通知其作什麼行爲的。
爲了用AI控制蘑菇小人,咱們須要建立一類特殊的控制器——AI控制器。
打開Characters\Muffin\AI目錄並建立Blueprint Class,選中AIController做爲父類並命名爲AIC_Muffin。
接着,咱們須要讓蘑菇小人使用這個AI控制器,打開Characters\Muffin\Blueprints並雙擊打開BP_Muffin。
默認狀況下,Details面板會顯示藍圖的默認設置,若是沒有顯示,就點擊Toolbar的Class Defaults。
在Details面板找到Pawn設置,將AI Controller Class設爲AIC_Muffin,這樣當蘑菇小人生成時,就會對應生成一個AI控制器實例。
因爲咱們要動態生成蘑菇小人,Auto Possess AI要設成Spawned。這樣當蘑菇小人生成時,AIC_Muffin就會自動控制BP_Muffin。
點擊Compile並關閉BP_Muffin。
如今,咱們要來建立決策蘑菇小人行爲的邏輯,就要用上行爲樹。
打開Characters\Muffin\AI目錄,並選擇Add New\Artificial Intelligence\Behavior Tree,將其命名爲BT_Muffin並打開。
行爲樹編輯器包含3個新面板:
像藍圖同樣,行爲樹也是由節點構成的。行爲樹有4類節點,前兩種分別是任務(tasks)和組合(composites)節點。
顧名思義,任務節點負責完成具體任務,能夠是表現一套連招這樣的複雜任務,也能夠是原地等待這樣的簡單任務。
要完成多個任務,咱們就要用上組合節點。一個行爲樹由許多分支(行爲)組成。每一個分支的根節點,都是一個組合節點。不一樣類型的組合節點,執行其子節點的方式也各不相同。
好比,咱們有一組以下序列的行爲:
要按順序執行每一個行爲,咱們就要用上Sequence組合節點,由於Sequence節點可以從左至右的執行子節點,圖表看起來是這樣的:
注意:從組合節點衍生出來的節點能夠稱爲子樹(subtree)。一般來講,這些節點就統稱爲一個行爲。好比,Sequence,Move To Enemy,Rotate Towards Enemy和Attack就統稱爲「攻擊敵人」行爲。
若是Sequence的任意節點執行失敗,整個Sequence節點就會中止執行。
好比,若是角色沒法移動到敵人身邊,Move To Enemy節點就執行失敗了,這樣Rotate Towards Enemy和Attack節點也就沒法繼續執行了。反之,若是角色成功移動到敵人邊上,就能執行隨後兩個節點。
後續咱們還會學習Selector組合節點,不過如今先讓咱們用Sequence節點實現角色隨機移動到某個位置並原地停留。
首先,建立Sequence節點並與Root節點相連。
接着,咱們須要讓角色移動起來,建立MoveTo節點與Sequence節點相連,這個節點能夠驅動角色移動到特定位置或Actor。
隨後,建立Wait節點與Sequence節點相連,確保將其放置在MoveTo節點右邊,放置順序很是重要,由於子節點是按照從左到右的順序執行的。
注意:你能夠經過每一個節點右上角的數字確認其執行順序。數字越小執行順序越高。
恭喜你,你剛剛建立了你的第一個行爲!它將會驅動角色移動到指定位置並原地停留數秒。
爲了讓角色移動,咱們還須要指定要移動的位置。因爲MoveTo節點只接受由黑板提供的數值,咱們要先建立一個黑板。
黑板是一個單純用來存放變量(鍵值)的資源。咱們能夠將其理解爲AI的內存。
雖然黑板不是必須使用的,但它確實爲咱們讀取,存取數據提供了極大便利,這麼說的緣由是不少行爲樹節點只接受黑板鍵值做爲參數輸入。
要建立一個黑板,咱們在Content Browser選擇新建Add New\Artificial Intelligence\Blackboard,將其命名爲BB_Muffin並打開。
黑板編輯器由2個面板組成:
如今,咱們要建立一個鍵值用於存放目標位置。
因爲是3D空間裏的一個位置點,咱們須要用Vector來進行存儲。點擊New Key並選擇Vector,將其命名爲TargetLocation。
接着,咱們須要隨機生成一個位置並將其存在黑板裏,咱們就須要用到第三種類型的行爲樹節點:服務(service)節點。
服務節點相似於任務節點,用於完成一些事情。然而,不一樣於操控角色作特定行爲,服務節點用於執行檢查或更新黑板操做。
服務並非獨立節點,而是依附於任務節點或者組合節點。這樣使得行爲樹更加簡潔易於組織,不會橫生太多節點。若是咱們用任務節點來實現,效果以下圖所示:
若是用服務節點來實現,則以下圖所示:
如今,讓咱們來建立一個生成隨機位置的服務吧。
回到BT_Muffin並點擊New Service。
這樣就會新建一個服務並自動打開,咱們回到Content Browser將其重命名爲BTService_SetRandomLocation。
服務應當且僅當在角色準備移動時才執行,所以咱們要將它附着在MoveTo節點上。
打開BT_Muffin,右鍵點擊MoveTo節點,從彈出菜單選擇Add Service\BTService Set Random Location。
如今,當MoveTo激活執行時,BTService_SetRandomLocation也會跟着激活執行。
接着,咱們須要隨機生成目標點位置。
打開BTService_SetRandomLocation。
爲了監聽獲知服務什麼時候觸發執行,咱們建立Event Receive Activation AI節點,這個節點會在服務父類(所附着的節點)激活時觸發執行。
注意:另外一個事件Event Receive Activation也有着相同的觸發時機,二者區別在於Event Receive Activation AI事件額外提供了Controlled Pawn參數。
爲了生成隨機位置,添加以下高亮節點,確保將Radius設置爲500。
這樣就能返回獲得該角色500單位半徑內的一個隨機可達目標點。
注意:GetRandomPointInNavigableRadius節點使用了導航數據(稱之爲NavMesh)來判斷一個點是否可達。在本例中,我已提早建立好了NavMesh。你能夠經過在Viewport選中Show\Navigation觀察NavMesh。
![]()
若是你想建立本身的NavMesh,請建立 Nav Mesh Bounds Volume,縮放其大小爲理想可達區域。
接下來,咱們須要將位置數據存儲到黑板裏。有兩種方式指定要存放的鍵值:
這裏咱們使用第二種方法。建立類型爲Blackboard Key Selector的變量。將其命名爲BlackboardKey並啓用Instance Editable,這樣行爲樹裏的服務就會出現對應變量。
隨後,建立以下高亮節點:
小結:
點擊Compile並關閉BTService_SetRandomLocation。
接着,咱們須要讓行爲樹來使用這個黑板值。
打開BT_Muffin並確保沒有選中任何東西。在Details面板的Behavior Tree設置處,將Blackboard Asset設爲BB_Muffin。
而後MoveTo和BTService_SetRandomLocation就會自動使用黑板的第一個鍵值,在本例中,就是TargetLocation。
最後,咱們須要讓AI控制器來運行行爲樹。
打開AIC_Muffin並鏈接Run Behavior Tree節點與Event BeginPlay節點,將BTAsset設爲BT_Muffin。
這樣當AIC_Controller生成時就會執行BT_Muffin。
點擊Compile並返回主編輯器,按下Play運行遊戲,生成一些蘑菇小人,觀察它們四處走動吧。
雖然設置很繁瑣,咱們仍是搞定了!接着,咱們要進一步設置AI控制器,讓它能夠在必定範圍內感知敵人所在。要實現這點,就要使用AI感知(AI Perception)。
AI感知是一個能夠添加給Actor的組件,經過它,咱們能夠給AI添加感官能力(如視覺和聽覺)。
打開AIC_Muffin並添加AIPerception。
接着,咱們要添加一個感官,因爲咱們想要蘑菇小人可以感知到其餘小人靠近,咱們給它加上視覺感官。
選中AIPerception並在Details面板的AI Perception設置處,給Senses Config添加新元素。
將元素0設置爲AI Sight config並展開它。
對於視覺有3個主要設置:
默認狀況下,AI感知只檢測敵人(被指定爲不一樣隊伍(team)的Actor)。然而,Actor默認是沒有設置隊伍的,若是Actor沒有隊伍,AI感知就會將其認爲中立(neutral)角色。
截至目前,尚未方法能經過藍圖設置Actor的隊伍,退而求其次,咱們展開Detection by Affiliation設置,啓用Detect Neutrals。
點擊Compile並回到主編輯器。按下Play運行遊戲來生成蘑菇。按下 ‘ 鍵能夠顯示AI調試信息,按下小鍵盤的數字鍵4能夠可視化AI感知組件。當蘑菇小人進入視野時,就會顯示綠色球體。
接着,咱們要讓蘑菇小人往敵人的方向走去。要實現這點,行爲樹就要了解敵人的信息,咱們經過在黑板存儲敵人的引用來完成這件事。
打開BB_Muffin並添加類型爲Object的鍵值,將其命名爲Enemy。
如今,咱們還不能在MoveTo節點使用Enemy,由於其鍵值類型爲Object,但MoveTo只接受Vector或Actor類型的鍵值。
爲了解決這點,咱們選中Enemy並展開Key Type,將Base Class設置爲Actor。這樣行爲樹就能將Enemy識別爲Actor了。
關閉BB_Muffin,如今,咱們要建立一個行爲讓AI向敵人走去。
打開BT_Muffin並斷開Sequence和Root鏈接。咱們能夠經過按住Alt鍵點擊連線來作到,並將移動子樹移到一邊。
接着,建立以下高亮節點,並將Blackboard Key設置爲Enemy:
這樣角色就會朝Enemy走去。有時候,角色不會恰好面對着它的目標,因此咱們還須要用上Rotate to face BB entry節點。
如今,咱們須要在AI感知檢測到其餘蘑菇時,將其設置爲Enemy的值。
打開AIC_Muffin並選中AIPerception組件,添加Perception Updated事件。
只要感官發生更新,這個事件就會觸發執行。在本例中,當AI得到或丟失了某物體的視野,這個事件就會執行,並提供了其當前所能感知到的Actor列表。
添加以下高亮節點,並確保將Make Literal Name節點設置爲Enemy。
這樣就能夠判斷AI目前有沒有敵人對象,若是沒有,咱們就要給它設置一個敵人,所以添加以下節點:
小結:
點擊Compile並關閉AIC_Muffin,按下Play運行遊戲並生成兩個蘑菇小人,其中一個生成暴露在另外一個面前,後者就會自動向前者走過去。
接着,你要建立一個自定義任務,讓蘑菇小人能夠表演攻擊行爲。
咱們能夠直接在Content Browser建立任務,而無須經過行爲樹編輯器。建立新的Blueprint Class類,並將BTTask_BlueprintBase做爲其父類。
將新建類命名爲BTTask_Attack並打開,添加Event Receive Execute AI節點,這個節點會在行爲樹激活BTTask_Attack時觸發執行。
首先,你須要讓蘑菇執行攻擊行爲。BP_Muffin包含一個IsAttacking變量,當變量設置爲true時,蘑菇會執行一次攻擊,所以咱們添加以下高亮節點:
若是這個任務節點在這裏就結束了,那行爲樹執行就會卡在這個節點上,由於行爲樹並不知道該節點已執行完畢了,因此咱們要在節點鏈末端添加Finish Execute節點。
接着,啓用Success,因爲咱們用的是Sequence,這樣就能讓BTTask_Attack的後續節點得以執行。
如今圖表看起來應該是這樣的:
小結:
點擊Compile並關閉BTTask_Attack。
如今,咱們須要將BTTask_Attack節點添加到行爲樹中。
打開BT_Muffin,隨後,將BTTask_Attack節點添加到Sequence節點後面。
接着,將Wait節點添加到Sequence節點後面,並將Wait Time設置爲2。確保蘑菇小人不會攻擊個不停。
回到主編輯器點擊Play運行遊戲,像上次同樣生成兩個蘑菇小人。蘑菇小人會朝着敵人走去。隨後,它會嘗試攻擊,而後休息兩秒。當它發現另外一個敵人時,又會重複以上行爲。
在最後一部分,咱們要將攻擊和移動兩顆子樹合併在一塊兒。
爲了合併子樹,咱們要用上Selector組合節點。相似於Sequence節點,它也是按從左向右的順序執行的。然而,Selector節點會在子節點返回成功而非失敗時中止執行。利用這個特性,就能夠確保行爲樹每次只執行一顆子樹。
打開BT_Muffin並在Root節點下建立Selector節點。隨後,以下圖鏈接兩個子樹:
這樣同一時間只有一顆子樹會獲得執行,下面是每顆子樹的執行狀況:
攻擊: Selector節點會首先運行第一顆子樹,若是全部任務都成功了,Sequence節點也會返回執行成功。Selector節點得知執行成功,就會中止執行後面的節點,這樣就不會再執行移動節點。
移動: Selector節點會嘗試運行前面的攻擊子樹,若是Enemy尚未值,MoveTo節點就會執行失敗,Sequence節點也就一樣失敗。因爲第一個子樹失敗了,Selector節點就會執行後續這顆移動子樹。
回到主編輯器,按下Play運行遊戲,生成一些蘑菇小人試試看吧!
「等等,爲何圖中這個蘑菇小人沒有立刻攻擊另外一隻呢?」
在傳統的行爲樹設計裏,行爲樹每幀都會從根節點開始執行,意味着每幀更新,它都會嘗試執行第一顆攻擊子樹,而後再執行第二顆移動子樹,這也意味着當Enemy值發生變化時,行爲樹就會立刻切換執行另外一顆子樹。
然而,Unreal的行爲樹並非這樣設計執行的。在Unreal裏,行爲樹會繼續執行上一幀選中的那顆子樹。圖中因爲AI感知沒有立刻感知到另外一隻蘑菇小人的存在,行爲樹開始執行移動子樹,因而行爲樹就只能乖乖等待移動子樹執行完畢,才能從新評估肯定執行攻擊子樹。
爲了解決這個問題,咱們須要用上最後一種類型節點:裝飾(decorators)節點。
相似於服務節點,裝飾節點也依附於任務或組合節點。一般而言,裝飾節點用於作前置檢查。若是檢查結果爲true,裝飾節點就返回true,反之亦然。經過裝飾節點,就能控制其依附節點是否可以執行。
裝飾節點也有能力停止子樹的運行,這意味着咱們能實現一旦Enemy有設值,就當即停止移動子樹。這樣蘑菇小人就能在發現敵人的第一時間攻擊敵人。
要實現停止功能,咱們可使用Blackboard裝飾節點,這個節點只是簡單地檢查某個黑板鍵值是否有值。打開BT_Muffin,並在攻擊子樹的Sequence節點點擊右鍵,從彈出菜單選中Add Decorator\Blackboard,這樣Sequence節點就會添加上Blackboard節點。
接着,選中Blackboard裝飾節點,並在Details面板將Blackboard Key設爲Enemy。
這樣能夠判斷Enemy是否有值,若是沒有值,節點返回失敗,從而致使Sequence失敗,從而讓移動子樹獲得執行。
爲了停止移動子樹,咱們須要用上Observer Aborts設置。
Observer Aborts可以實現所選中的黑板鍵值發生變化時,停止執行子樹,這裏分爲兩種類型的停止:
咱們將Observer Aborts設爲Both,同時啓用兩種類型的停止。
如今,當AI已經沒有敵人目標時,能夠立刻從攻擊子樹切換運行移動子樹。一樣的,當AI檢測到敵人目標時,又能從移動子樹切換運行攻擊子樹。
如下是完整的行爲樹圖表:
攻擊子樹小結:
移動子樹小結:
關閉BT_Muffin並按下Play運行遊戲,生成一些蘑菇小人進行一場你死我活的決鬥吧!
你能夠在這裏下載完整項目。
如你所見,製做簡單AI還算一件不難的事。若是你想建立一個更加高級的AI,請查閱場景查詢系統,這個系統容許AI收集場景數據並做出相應的反饋。
若是你還想繼續學習引擎其餘內容,點擊下篇教程,將教你如何製做一個簡單的第一人稱射擊遊戲。