如何為敵方史萊姆建立人工智慧

**注意:**本教學的完成版專案檔案可在本文末尾找到。
簡介
在本教學中,我們將為一款平台遊戲打造一隻令人信服的敵方史萊姆的人工智慧(AI)。我們會介紹 hyperPad 中一些較進階的功能與行為,因此本教學假設你已具備 hyperPad 編輯器的基本知識。如果你想先熟悉如何從零開始製作遊戲,可以先參閱完整指南-建立平台遊戲教學。
為了讓史萊姆看起來「聰明」,它不能只是不斷來回移動,還應該對周遭環境有一定程度的感知。
聽起來很有趣!不過在開始之前,我們先來說明敵方史萊姆應該如何行動:
- 史萊姆不會走路,而是向左或向右跳躍移動。
- 史萊姆會朝玩家所在的方向跳躍。
- 如果玩家離得太遠,史萊姆就不會移動(待機)。
- 史萊姆碰到玩家時會扣除玩家的生命值。
- 玩家從史萊姆上方跳下來時,史萊姆就會被擊敗。
現在我們知道目標了,開始吧!
第 1 部分:設定專案
為了保持簡單,本教學會從頭建立新專案。建立一個新專案並將其設定為「側視圖」(Side View),其他設定則保持預設值即可。
建立新專案後,前往素材庫,在素材商店中取得 hyperPad 的「Platformer Starter Pack」(平台遊戲入門素材包)。(免費!)
現在我們有可用的素材了,接著放置一些地面方塊並建立你的遊戲世界。如果你目前不在素材庫中,請前往該處並依序點選「下載項目」和「Platformer Starter Pack」。
下圖中已放置一些地面方塊(「Grass World」資料夾),並設定了背景(「Backgrounds」資料夾)。
現在有了漂亮的場景,接著加入玩家和史萊姆物件。前往素材庫並開啟「Downloads」資料夾,再開啟「Platformer Starter Kit」資料夾(如果尚未開啟)。
我們會使用「Green Spaceman」作為玩家角色。點選綠色太空人的素材,就能查看它的所有動畫循環。預設情況下,我們希望玩家保持站立,因此點選「Stand」動畫並將它放到場景中。
素材庫的同一個資料夾中還有一個名為「Slime Pink」的動畫角色。它非常適合當作史萊姆敵人!點選史萊姆素材,選擇「Move」動畫,然後將史萊姆放到場景中,與玩家角色一同入場。
目前進展順利!現在已有玩家物件和史萊姆物件,可以開始使用了。不過,如果現在執行專案,我們還無法與遊戲互動。因此,我們需要建立一些邏輯,讓遊戲活起來。
第 2 部分:玩家控制
在讓史萊姆敵人活起來之前,我們先替綠色太空人設定玩家控制。
點選綠色太空人,將它的物理模式從「Wall」改為「Physical」,這樣玩家就能自由移動。接著點選「Behaviors」按鈕,開啟玩家角色的行為編輯器,為它加入控制功能。
在玩家角色的行為編輯器中,你應該會看到一個單獨的播放動畫行為。我們可以保留這個行為,再替它加上其他行為。
在互動區段中,任意放置一個搖桿控制行為,以及一個按鈕跳躍行為。加入這些行為後,玩家就可以接受控制了。不過,目前還缺少動畫。
點選「Joystick Controlled」行為,將「Joystick Left Animation」設定為 Green Spaceman 素材中的「Walk」動畫循環。「Joystick Right Animation」也設定成同樣的動畫。
現在玩家角色會走路了,但跳躍時仍然不會播放動畫。
點選「Jump with Button」行為,將「Falling Animation」和「Jumping Animation」都改成「Jump」動畫循環。
現在執行遊戲,就能四處移動和跳躍了!接下來,我們來製作史萊姆敵人。
第 3 部分:史萊姆移動
如本教學簡介所述,我們希望史萊姆朝玩家跳躍。要做到這一點,史萊姆必須知道玩家在遊戲世界中的位置。因此,我們應該替玩家角色加上標籤,這樣行為就能在任何場景中取得玩家角色。
點選玩家角色,並在屬性檢視畫面底部選擇「Tags」分頁。在標籤選單頂端的文字欄位中輸入「Player」,再點選旁邊的新增(+)按鈕。現在玩家角色已加上「Player」標籤。
和玩家角色一樣,點選史萊姆,將它的物理模式從「Wall」改為「Physics」。接著點選「Behaviors」按鈕,開啟史萊姆的行為編輯器。
在行為編輯器中,前往自訂行為區段,將「Timer」行為拖曳到編輯器中。
點選「Timer」行為,將間隔設定為 2 秒。
這就是史萊姆人工智慧邏輯的起點。
這裡的想法是,史萊姆每隔 2 秒就會「思考」下一步要做什麼,例如:要不要跳?如果要跳,該往哪個方向跳?
接著前往變換行為區段,放置一個取得位置行為。點選它,並在屬性檢視畫面底部點選「Tags」分頁,選取先前建立的「Player」標籤,將目標設定為玩家。現在將 Timer 連接到 Get Position 行為。
現在我們知道玩家在遊戲世界中的位置了!要判斷玩家在史萊姆的左邊還是右邊,我們也需要知道史萊姆自己的位置。
再將另一個 Get Position 行為拖曳到編輯器中。這個行為預設已將目標設為史萊姆,所以除了將它連接到邏輯分支之外,不需要再做其他設定。接著把取得玩家位置的 Get Position 行為連接到取得史萊姆位置的 Get Position 行為。
**選擇性:**為了更容易理解,我將 Get Position 行為重新命名,清楚標示它們追蹤的對象:「Get Position Player」和「Get Position Slime」。這不是必要步驟,但如果你也想更改行為名稱,可以點選行為,再點選屬性檢視畫面最上方的名稱。
目前的設定是:史萊姆每隔 2 秒就會取得玩家角色和自己的位置。取得這些資訊後,我們就能判斷史萊姆應該往左還是往右跳。
在邏輯分頁中,放置並連接一個 If 行為。在其屬性中,將第一個值設為第一個 Get Position(「Player」標籤)的 x 座標:把該行為的輸出值拖曳到 If 屬性的欄位中。第二個值則設為第二個 Get Position(史萊姆)的 x 座標。最後,將 If 行為的條件設為「小於」(Is Less Than)(<)。
**注意:**物件的 x 座標代表它在遊戲世界 x 軸上的位置(左、右)。
這代表什麼呢?If 行為會檢查玩家的 x 座標是否小於史萊姆的 x 座標。如果條件成立,就會執行下一個連接的行為。換句話說,如果玩家位於史萊姆更左邊的位置,行為就會繼續執行。
好了,我們已經設定好讓史萊姆向左跳的邏輯,現在就讓它照著做吧!
在物理行為區段中,放置一個施加力行為並將它連接到 If 行為。在其屬性中,將力設定為:x = -0.5、y = 1。接著將乘數設為較大的數值,200 就可以了。
現在的效果是:如果史萊姆發現玩家位於自己的左邊,就會向上跳(y = 1 × 200),並稍微往左移動(x = -0.5 × 200)。
試試看!執行遊戲並確認一切正常。只要玩家在史萊姆左邊,你應該會看到史萊姆每隔 2 秒往左跳一次。如果將玩家移到史萊姆右邊,它就會停止跳躍,直到你再次移到它左邊。
**注意:**如果史萊姆沒有移動,請檢查前面的步驟,確認沒有遺漏任何設定。確保行為連接正確,而且史萊姆的物理模式已設為「Physics」(可移動),而不是「Wall」(不可移動)。另外,我們很快就會修正史萊姆有時會翻倒或上下顛倒的問題。
目前進展很不錯!如果史萊姆如預期般跳動,我們就可以繼續完成它的移動行為,讓它也能向右跳。
回到史萊姆的行為編輯器,複製 If 行為。將新的 If 行為拖到原本 If 行為的右側並與之吸附連接,這樣它就會變成「Else If」行為。
也複製 Apply Force 行為,並將複本連接到新的 Else If 行為。
在 Else If 的屬性中,將條件從「小於」(Is Less Than)(<)改為「大於」(Is Greater Than)(>)。這會產生與第一個 If 相反的效果。如果第一個 If 條件不成立,就會改為檢查 Else If 是否成立。也就是說,如果玩家不在史萊姆左邊,就會檢查玩家是否在史萊姆右邊,並改為執行連接到 Else If 的行為。
現在應該會看到類似下方的行為分支:
在第二個 Apply Force(位於 Else-If 下方)中,將力的 x 值從 x = -0.5 改為 x = 0.5。現在史萊姆就會改為向右跳。
執行專案再試一次!現在你應該會看到史萊姆朝玩家所在的方向跳了。太好了!
你可能在測試遊戲時注意到,若玩家撞到史萊姆,它有時會側倒或上下顛倒。我們希望史萊姆保持直立,因此快速修正這個問題。
回到史萊姆的行為編輯器,前往 Transform 行為區段,將鎖定旋轉行為拖曳到編輯器中。不需要把它連接到其他行為;我們希望它在史萊姆建立時就鎖定旋轉,因此保留原狀即可。完成後再試玩一次,這次史萊姆就不容易被撞倒了。
你可能也注意到史萊姆的動畫播放速度太快。如果是這樣,請點選史萊姆行為編輯器中的 Play Animation 行為,並將每秒影格數調低。每秒 6 格看起來相當不錯。
很好!現在史萊姆不但移動得很自然,外觀也很棒。大致上,史萊姆的移動邏輯已經完成。
不過,我們還希望史萊姆只在玩家附近時才跳躍。這樣一來,如果遊戲世界很大,遠處的史萊姆就不會立刻朝玩家跳來並發動攻擊。下一部分中,我們會加入另一個條件:如果玩家離得太遠,就阻止跳躍邏輯執行。
第 4 部分:史萊姆待機
這一部分會加入史萊姆的待機行為,也就是當玩家距離太遠時不移動。
要做到這一點,我們需要找出測量史萊姆與玩家之間距離的方法。剛好有行為可以做到這件事!開始吧。
開啟史萊姆的行為編輯器,從 Logic 區段拖曳一個計算距離行為。在它的屬性中,第一個物件已經設為史萊姆。第二個物件則前往「Tabs」選單並選取「Player」標籤。
執行這個行為時,它會計算史萊姆到玩家的距離(公尺)。利用這項資訊,我們可以檢查距離是否超過特定數值,判斷玩家是否離得太遠。
從 Logic 區段再放置一個 If 行為,並將它連接到 Calculate Distance 行為下方。在 If 行為的屬性中,將第一個值設為 Calculate Distance 的輸出值。條件設為「小於」(Is Less Than),第二個值設為 15。
現在我們可以透過檢查史萊姆和玩家之間的距離是否小於 15 公尺,來判斷玩家是否離得太遠。如果條件不成立,表示玩家距離太遠,If 行為就不會執行下一個行為。
現在新條件已準備就緒,請將前一部分中的 Get Position(史萊姆)和舊的 If 行為取消連接,並騰出空間放置新條件。若要取消連接行為,請點住兩個行為之間的連線。
加入新的距離條件後,將 Get Position(史萊姆)連接到 Calculate Distance 行為,再將新的 If 行為連接到舊的 If 行為。完成後應該會如下圖所示:
現在看起來有點複雜,不過概念其實很簡單。在檢查史萊姆該往哪個方向跳之前,我們會先檢查史萊姆和玩家之間的距離是否小於 15 公尺。
如果玩家離史萊姆不到 15 公尺,邏輯就會繼續執行,照常檢查應該往哪個方向跳。如果玩家距離超過 15 公尺,流程就會停止,直到史萊姆下一次「思考」(2 秒後)才會重新檢查。
試玩看看!如果你靠近史萊姆,它應該就會開始朝你跳來;如果你走得太遠,它則會停止移動,直到你再次靠近。
現在史萊姆看起來越來越有威脅性了,但還缺少傷害玩家的能力。在本教學的下一部分,我們會為玩家加入生命值列,並設定扣除玩家生命值的邏輯。
第 5 部分:攻擊玩家
如簡介所述,我們會讓史萊姆碰到玩家時造成傷害,以此實作史萊姆的攻擊。要開始設定史萊姆的攻擊方式,我們首先要替玩家加入生命值。
在主編輯器中,選取 Scene UI 圖層,再使用特殊物件按鈕建立新物件。點選「Health Bar」為玩家建立生命值列。
由於生命值列放在 Scene UI 圖層上,即使我們擴大遊戲世界並讓畫面跟隨玩家移動,它仍會停留在畫面上的同一位置。
你可以將它放在畫面上任何適合的位置。我把它放在畫面底部附近的中央。
找到適合放置生命值列的位置後,就可以開始設定扣除生命值的功能。回到史萊姆所在的 Main 圖層,再次開啟它的行為編輯器。
在史萊姆的行為中找個空白處,從 Object 區段拖曳一個碰撞行為。在它的屬性中,將第二個物件設為「Player」標籤。
在 Custom 行為區段中,拖曳一個廣播訊息行為,並將它連接到 Collided 行為下方。在 Broadcast Message 行為的屬性中,將 Event Key 設為「player hit」,值設為 -10。
**請記住:**Event Key 區分大小寫!為了簡化說明,本教學會使用小寫字母作為 Event Key。你也可以使用大寫字母,但要記住哪些字母有大寫,後續才不會弄錯。
現在我們可以偵測玩家何時應該扣除生命值。玩家與史萊姆碰撞時,遊戲會廣播一則 Event Key 為「player hit」、值為 -10 的訊息。我們會利用 -10 告訴生命值列「增加」-10 點生命值;由於這是負值,因此會扣除 10 點生命值。
我們還需要將這套邏輯加入生命值列,現在就來設定。離開史萊姆的行為編輯器,在主編輯器中點選 Scene UI 圖層,再點選生命值列,然後開啟生命值列的行為編輯器。
在生命值列的行為編輯器中,從 Custom 區段拖曳一個接收訊息行為。在它的屬性中,將 Event Key 設為「player hit」。(請記住,這會區分大小寫!)
這個行為會監聽玩家碰到史萊姆時送出的「player hit」訊息。只要它偵測到遊戲中任何地方廣播了「player hit」訊息,就會執行。
接著在UI行為區段中加入一個增加生命值行為,並將它連接到 Receive Message 行為下方。
在 Add to Health Bar 的屬性中,將 Receive Message 的輸出值拖曳到「Value to add」欄位。這個值就是稍早在史萊姆的 Broadcast Message 行為中設定的 -10。這樣一來,如果我們希望其他敵人造成不同程度的傷害,只要更改廣播訊息中的數值,生命值列就會使用新的數值!
確認「Event On Full」已關閉,而「Event On Empty」已開啟。這表示生命值列降到零時,就會執行下一個行為。
在場景行為區段中,拖曳一個載入覆蓋畫面行為,並將它連接到 Add to Health Bar 行為。
在 Load Overlay 設定中,將選取的覆蓋畫面改成「Game Over」。建立新專案時,系統會自動為你建立這個覆蓋畫面。
執行遊戲試試看!現在每次碰到史萊姆,生命值列都會減少;生命值歸零時,遊戲就結束了。
太好了!現在我們可以傷害玩家,也可以讓玩家輸掉遊戲了。
不過,感覺還是有點不太對勁。除了生命值列減少之外,玩家被擊中時沒有得到太多回饋。
我們可以讓玩家和史萊姆彼此彈開,讓玩家明確感受到碰撞,同時避免玩家因為快速連續碰撞史萊姆而受到過多傷害。
前往史萊姆的行為編輯器(可能需要先選取 Main 圖層),從 Physics 區段拖曳一個推開物件行為。將它連接到前面建立的 Broadcast Message 行為下方,再開啟它的屬性。
在屬性中,開啟 Tags 分頁並選取「Player」標籤,將第二個物件改成玩家。將 Force 設為 200、Object A Multiplier 設為 0.25,並將 Object B Multiplier 設為 1。
現在玩家和史萊姆碰撞時,玩家會以 200 的力(1 × 200)被推離史萊姆,而史萊姆則會以 50 的力(0.25 × 200)被推離玩家。
遊戲現在玩起來感覺好多了!不過,史萊姆仍然無敵,玩家還沒有辦法打敗它。下一部分中,我們會加入玩家反擊的方式。
第 6 部分:擊敗史萊姆
要讓玩家從史萊姆上方跳下來攻擊它,我們得改變碰撞處理方式,讓史萊姆在造成傷害時忽略玩家的底部(玩家的腳)。
開啟史萊姆的行為編輯器,點選前一部分建立的 Collided 行為。關閉「On Bottom」選項,這樣史萊姆與玩家碰撞箱底部碰撞時就會忽略該碰撞。
現在玩家從史萊姆上方跳下來時,史萊姆就不會傷害玩家。接著我們要在這種情況下執行不同的邏輯。
選取 Collided 事件後,複製它,並在新複製的 Collided 行為中反轉所有選項,讓「On Bottom」成為唯一啟用的事件。
這會成為玩家從史萊姆上方跳下來時的觸發點。
接著從 Object 行為區段拖曳一個摧毀物件行為並將它連接起來。預設情況下,它應該已設定為摧毀史萊姆物件。
現在執行遊戲時,從史萊姆上方跳下來就能摧毀它。不過,和先前被史萊姆擊中時一樣,這樣的效果不太有滿足感。
就像上一部分一樣,再加入一個 Propel Object。複製先前玩家受傷邏輯中的 Propel Object 行為,並將它連接到 Destroy Object 行為下方。新 Propel Object 的屬性可以沿用原本的設定。
現在執行遊戲,從史萊姆上方跳下來時就會有令人滿意的彈跳效果。
結論與練習
大致上就是這樣!我們已經完成簡介中列出的所有目標:
- 史萊姆不會走路,而是向左或向右跳躍移動。完成!
- 史萊姆會朝玩家所在的方向跳躍。完成!
- 如果玩家離得太遠,史萊姆就不會移動(待機)。完成!
- 史萊姆碰到玩家時會扣除玩家的生命值。完成!
- 玩家從史萊姆上方跳下來時,史萊姆就會被擊敗。完成!
如果你一路做到這裡,現在應該已經充分了解如何讓敵人變得更有智慧,並自行思考與做出決策。做得好!
不過,還有很多可以嘗試的地方。試著自行完成以下練習:
- 玩家從史萊姆上方跳下來時,播放史萊姆的「hit/dead」動畫。
- 史萊姆攻擊玩家時,播放玩家的「hit」動畫。
- 讓史萊姆每次跳躍的距離帶有一些隨機變化。
本教學的完成版專案檔案可在此下載:下載教學專案

