iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 26
1
Software Development

[Minecraft - 當個創世神] 從玩遊戲到設計遊戲系列 第 26

[Day26] 來玩玩實體AI吧 (上)

一隻狼正在向玩家祈求(Beg)
引用自Minecraft Wiki :

在麥塊世界中,所有的實體都會有自己的"小聰明" - 人工智慧(AI)。
當然,除了玩家,因為玩家是自以為聰明XD

回到正題,這些實體的AI目前在1.8版中有下面這些 (你可以從繼承net.minecraft.entity.ai.EntityAIBase這個類別去找到所有的列表):

  • EntityAIMate : 與另一個異性實體的互動行為AI
  • EntityAIBeg : 向玩家祈求的行為AI
  • EntityAISwimming : 游泳行為AI
  • EntityAIWander : 閒晃行為AI
  • ...太多列不完

因為AI的類型太多,我們在繼續實作自己的AI之前,需要先對Minecraft如何去執行AI的流程有些初步的理解。

基本架構

要使用AI的功能,定義我們自己實體類別的時候,需要去繼承EntityCreature這個類別,或者是其子類別。我們在[Day9]的自定義豬類別時,繼承的是EntityPig

EntityPig -> EntityAnimal -> EntityAgeable -> EntityCreature

在繼承之後,我們的類別內就會有兩個很重要的EntityAITasksAI列表可以使用:

  • tasks : 用來控制所有跟移動有相關的AI列表
  • targetTasks : 用來控制與實體目標有相關的AI列表

這兩個內建AI列表因為是可以互不相關同時發生,所以在使用時可以將你自定義的AI放到有相關的AI列表內去,這樣就可以專注在移動相關或是目標相關的AI行為上。

AI流程

整個AI的執行順序大概會是這樣:

  1. 從AI列表中尋找最高優先權的工作(我們有兩個列表,所以會各自去找最高優先權的)。
    • 在加入工作到AI列表中時,會使用addTask來加入:
      .addTask(0, new EntityAISwimming(this));
      
      其中第一個參數即為優先權,數字越低表示優先權越高;
      第二個參數是設定要加入列表的AI工作。
  2. 判斷這個工作是否有被其它工作遮蔽(Mask);若沒有才繼續下個動作。
    • 由於同一個AI列表內的工作大家都有可能同時間去執行,Minecraft設計了一個方法叫做

      setMutexBits()
      

      來控制兩兩工作之間是否可以同時間進行:即當前工作的執行是否不會被其他工作遮蔽。
      具體的作法需要對二進位數字有些概念,它的邏輯基本上就是

      當兩個工作的所有位元進行AND運算後,若為0才可以同時進行。

      例如:
      A工作的MutexBit值是3 -> 轉換成二進位就是011
      B工作的MutexBit值是1 -> 轉換成二進位就是001
      C工作的MutexBit值是4 -> 轉換成二進位就是100
      那麼,
      A不可以與B同時進行,因為A與B的AND位元運算完是"001";不是0
      A可以與C同時進行,因為A與C的AND位元運算完是"000";是0
      B可以與C同時進行,因為B與C的AND位元運算完是"000";是0

    • 以實際例子來說,EntityAISwimming的MutexBit是4,而EntityAIBeg的MutexBit是2,那麼這兩個在實際上是可以同時間發生的。

  3. 接著,會在該AI工作中執行shouldExecute()方法;只有該方法回傳為true才會繼續下個動作。
  4. 下一步,執行startExecute()方法。
  5. 後續在每一個遊戲內的時間,會去呼叫continueExecuting()方法;如果該方法回傳為true,就會一直在下一個時間執行,直到回傳為false
  6. 至此,一個AI工作完整流程就結束了。

到目前為止,我們也有使用過AI的功能來做一些事情;不過我們在[Day9]是希望把現有的AI都取消!

PigDoll.java

// 將豬的AI行為去除
EntityAIBase ai = new EntityAIBase() {
    @Override
    public boolean shouldExecute() {
        return true;
    }
};
ai.setMutexBits(0xFFFFFF);
pig.tasks.addTask(0, ai);

這裡的邏輯我想就比較容易理解了:

  • 我們實作shouldExecute方法,讓這個自定義AI是可以被執行的

  • 定義AI工作的MutexBit為0xFFFFFF,它代表的即為111111111111111111111111;用一個很多位元數字都是1來避免與其它AI工作AND運算為0。

    小技巧:其實這裡我們可以設定為setMutexBits(8)就可以了。想想是為什麼呢?

  • 最後,我們將此AI工作的優先權設定最高;因此在實際執行時,這個AI工作一定會先執行,並且沒有任何其它的工作可以與他同時執行,就達到我們的沒有AI效果。

這裡有很多概念我盡量都以比較簡單的方式去描述 (剩下比較實作面的細節會在明天說明);但因為概念已經簡單化了,所以如果要自己去動手試看看,這些觀念還是要盡可能了解比較好。


上一篇
[Day25] 人生是彩色的,麥塊也要是彩色的
下一篇
[Day27] 來玩玩實體AI吧 (下)
系列文
[Minecraft - 當個創世神] 從玩遊戲到設計遊戲30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言