MC1.12.2的AI系统简述
MC提供了一套比较灵活的AI系统,但目前主要用于动物、村民和怪物。如果玩家可以自定义一种生物,以及它的AI,想必是个不错的补充。
在《理想境》里,“另我离影”召唤出的分身具有三种行为模式:跟随、攻击、守护。不过,这三个行为模式并不是各对应一个AI。它们对应了三种不同的AI组合。
在MC 1.12.2里,AI系统分为两类:行为AI(EntityAIBase)和索敌AI(EntityAITarget extends EntityAIBase),它们归属两个不同的AI列表。
每个AI列表里有若干任务,每一个都有优先级,同一列表里,优先级序号越小的越优先执行。不同队列之间没有优先级比较可言。
举例来说,“寻找附近的玩家作为目标”是索敌AI,我把它扔进索敌列表,优先级序号设为3;“冲锋并近战攻击”是行为AI,我把它扔进行为列表,优先级序号设为2。这两者组合在一起,就能制作一个看到玩家就扑过来的敌人。少了索敌的部分,或者少了攻击的部分,都会导致该生物对玩家无动于衷。虽然“会攻击玩家”在认知上只是一件事,但是它在mod实现里实际上是拆成两半做的。
看到这里,我群里某个总喜欢挑战我极限的群友就该问了:
假如把索敌AI扔进行为列表,把行为AI扔进索敌列表会怎样?
我看到这个问题会非常生气:你听听,这是碳基生物能干出来的事吗?
要回答这个问题,要从MC AI的本质上说起。AI对象主要包括这么几个东西:启动条件、继续条件、互斥锁状态、执行时的update代码。无论是索敌AI,还是行为AI,本质上都是这些内容。所以,光从语法来看,这样做是允许的。
但是,由于我们一般默认没有人这样做,所以也就不会预料到这样会出什么问题。举例来说,我们的索敌行为列表里1号位是“寻找附近玩家”的索敌AI,2号位是“移动并近战攻击”,那么索敌AI找到了目标之后,很可能就不执行后面的2号位AI了,导致找得到敌人,却还是不去攻击。即使不去考虑和其他mod的联动,光是整理出一个不会有问题的列表就不容易。请不要给自己找麻烦……除非不这样做更麻烦。
然后又有人要问了,
如果两个AI在同一个列表,且优先级相同会怎样?
我只能说,少干这种给自己找麻烦的事。设计的时候就避免这种优先级相同。把谁先谁后规定得清清楚楚,不好吗?你的时间是浪费在给自己找麻烦上的?
我想做一个能自定义AI的机器人(或使魔)mod,那么这里涉及到三种选择:
1,根据玩家理解设计操作,写一套复杂的逻辑把它转化为MC AI的双列表体系;
2,根据MC AI双列表体系设计操作,让玩家去理解这东西;
3,完全否定双列表体系,自己另起炉灶。
方案1做起来非常麻烦,当玩家想实现某个操作的时候,你可能需要去按顺序组合四五个AI才能实现这个效果。而且,当玩家改变生物的行为模式时,你还要精确地去除原本的AI,确保它们不残留下来干扰你。
方案2玩家理解起来非常麻烦,或者说门槛比较高。实际上,很多MC玩家对游戏的理解是远不如mod作者的。这个差距大到什么程度呢?达到很多人宁可付费下载一个死亡不掉落mod或者防爆mod,也不去自己打mc原版就有的指令——尽管那个mod实际上就是在执行指令。网易版这种mod的巨大下载量证明了这一点。如果我希望自己的mod有更多人玩的明白,那势必就不要这样干。“让这个怪物攻击玩家”,在逻辑上只是一件事,那也就不要让玩家分别正确执行两个操作才能实现。
方案3呢,做起来也简单,玩家理解起来也简单,但兼容性差。如果有哪个mod基于双列表体系修改AI,那么它和我的互动结果,只有实际试试才知道了。
可能有人要问,MC为啥要搞双列表体系呢?这不是自找麻烦吗?其实也不然。我们看一个比较好的生物作为例子吧:僵尸。实际上,骷髅更好,但是也更难理解,我们先从僵尸开始入手。



有人可能会说了,这mojang是不是有病,为什么把行为列表的3和4空出来了,是为了让不同生物类型的同种任务序号对齐吗?并不是。如果你去看骷髅的,你会发现骷髅里EntityAIWanderAvoidWater是5,但是在僵尸里是7。再比如,游泳在骷髅里是1,但是在僵尸里是0。那么,是为了给EntityZombie的子类留空间吗?也不是。子类一共有仨,Husk、PigZombie和ZombieVillager,都没有指定3和4。我只能假设这是以前有3和4,后来随着版本更新给删掉了,又懒得整理后面的编号而造成的历史残留。
虽然多数索敌列表里内容的工作都是去指定实体的attackTarget(攻击目标),但这不意味着它们不能干别的, 也不意味着其他地方不能去修改目标。索敌AI可以影响寻路的目的地,做什么都行,代码里写什么就是什么。其他地方也可以手动指定attackTarget,这使得我们可以制作一个具有嘲讽效果的道具,而不必直接和AI列表打交道。
这就是AI的本质:两套列表里的若干项目,控制实体的若干内容。这里我们没有深入讨论寻路的部分,那个比较麻烦,且多数情况下不需要修改——除非你想做的东西不是在地上走来走去,而是蹦来蹦去,或者飞来飞去。一旦改了,还会和某些AI类不兼容,所以我们先pass。
如果我们在实体运行的好好的时候,突然把其中一条AI从列表里去掉, 或者把一条AI加入列表,会怎么样?
这个问题很合理,事实上MC自己就经常这么干。最典型的例子就是骷髅。

点此查看骷髅失去弓的效果。
骷髅会经常调用(主要是每次在主手物品修改时)setCombatTask。
这个接口的效果是,首先把近战和远程攻击都从行为列表里去掉(但不销毁),然后判断主手物品。如果主手是弓,那就把远程攻击行为给挂回列表;如果不是,那就把近战攻击行为给挂回去。显然,即使是手里从钻石换成铁锭,这个接口也要调用一次,然后把AI拆了又挂回去。只有两种模式的时候,已经这么墨迹,如果你要在多个模式间来回切换,不事先规划好肯定是不行的。
最后再提两点关键的东西:
玩家、船、盔甲架等不具有AI系统。这些东西是给EntityLiving用的。
AI不会持久化并存盘。如果你退出游戏后再进入游戏,那么实体并不会记得退出前它获得了什么AI,只会正常调用构造函数。你需要手动恢复它的各项AI状态。或者说,对于可变AI的生物,自己写一套AI状态存档系统。