游戏开发中怪物AI实现方案总结

前言

        在游戏开发中实现怪物AI逻辑的主要技术有两种:1、状态机2、行为树。 他们两者的实现机制不一样,其中状态机是“事件”机制,行为树是“轮询”机制。在项目开发中可以根据具体情况合理的选择两者来处理AI编写问题。

         这篇文章分两个部分对游戏中的AI进行讲解,1、状态机,2、行为树。

概述

        开发游戏AI的目标之一就是要找到一个简单,可扩展的编辑逻辑的方案,从而加速游戏开发的迭代速度。在“行为系统图”中,行为系统(Behavior System)响应游戏中的各种信息,进行决策以挑选接下来将要执行的行动并且监控该行动的执行。


        知识模型(Knowledge Model)是对游戏世界中各种信息的抽象。

        在行为系统中,有限状态机(FSM,FiniteState Machine)最为经典,FSM模型的优势之一是简单。但是FSMs需要用转换(Transition)连接状态(State),因此,状态(State)失去了模块性(Modularity)。


        行为树,英文是Behavior Tree,简称BT,是由行为节点组成的树状结构:


        对于FSM,每个节点表示一个状态,而对于BT,每个节点表示一个行为。同样是由节点连接而成,BT有什么优势呢?

        在BT中,节点是有层次(Hierarchical)的,子节点由其父节点来控制。每个节点的执行都有一个结果(成功Success,失败Failure或运行Running),该节点的执行结果都由其父节点来管理,从而决定接下来做什么,父节点的类型决定了不同的控制类型。节点不需要维护向其他节点的转换,节点的模块性(Modularity)被大大增强了。实际上,在BT里,由于节点不再有转换,它们不再是状态(State),而是行为(Behavior)。



                                                第一种-有限状态机

1、有限状态机(FSM)的实现方式有三种

        1、面向过程的方式的if else

        2 、用枚举配合switch case语句。

        3、用多态与虚函数(也就是状态模式)

2、状态模式的经典定义:允许对象在当内部状态改变是改变其行为,就好像对象改变了自己的类一样。

3、状态模式的实现分为三个要点:

        1、为状态定义一个接口

        2、为每个状态定义一个类

        3、恰当地进行状态委托

4、通常来说,状态模式中状态对象的存放有两种实现存放思路:

        1、静态状态。初始化时把所有可能的状态都new好,状态切换时通过赋值改变当前的状态

        2、实例化状态。每次切换状态时动态new出新的状态。


关于FSM的具体案例如下:

        1、Unity的Mecanim动画系统就是通过状态模式来实现的


        2、下图是一个简单的战斗过程的状态机,如果用状态模式实现他的攻击逻辑就非常的方便,而且支持后期状态的扩展。

        总结:状态模式暂时没有找到好的开源框架,但是状态模式不仅仅在AI方面使用,在游戏的框架中也被广泛使用,比如:UI框架,游戏主逻辑状态框架等等。

                                                 第二种-行为树

什么是行为树

        如果了解过状态机,会知道在行为树之前,在实现AI用得比较多的技术是状态机,状态机理解起来是比较简单的,即一个状态过渡到另一个状态,通过判断将角色的状态改变即可,如果学习过Unity的Mecanim动画系统,会更加直观的理解。但是状态机在状态较多的情况下会使状态之间的切换变得异常繁琐,同时状态之间很难复用。在这种情况下,行为树被发明出来,行为树的优点如下:

        1、行为树提供大量的流程控制方法,使得状态之间的改变更加直观;

        2、整个游戏AI使用树型结构,方便查看与编辑;

        3、方便调试和代码编写;

        4、更好的封装性和模块性,让游戏逻辑更直观,开发者不会被那些复杂的连线绕晕。

        5、最重要的:行为树方便制作编辑器,可以交由策划人员使用;

行为树的基本概念:

        1、执行每个节点都会有一个结果(成功,失败或运行)

        2、子节点的执行结果由其父节点控制和管理

        3、返回运行结果的节点被视作处于运行状态,处于运行状态的节点将被持续执行一直到其返回结束(成功或失败)。在其结束前,其父节点不会把控制转移到后续节点。

行为树原理

        行为树是一种树形结构,所以其可以分成3种节点类型:


        1、红色的节点:根节点,没有父节点的节点;

        2、蓝色的节点:组合节点,有父节点和子节点的节点;

        3、白色的节点:叶节点,没有子节点的节点;

节点的返回

        每个节点都会有一个返回值,可能出现的返回值有3个,如下:

        1、运行中:表示当前节点还在运行中,下一次调用行为树时任然运行当前节点;

        2、失败:表示当前节点运行失败;

        3、成功:表示当前节点运行成功;


下面我们来细说一下这几个节点

根节点

        行为树的入口节点,可以是任意类型的节点;

组合节点

        行为树的组合节点是由下面几种类型来组成的:

1、选择节点/优先选择节点(Selector)

        该节点会从左到右的依次执行其子节点,只要子节点返回“失败”,就继续执行后面的节点,直到有一个节点返回“运行中”或“成功”时,会停止后续节点的运行,并且向父节点返回“运行中”或“成功”,如果所有子节点都返回“失败”则向父节点返回“失败”。

2、随机选择节点(Random Selector)

        之前的选择节点是有优先级顺序的,而随机选择节点的执行顺序是随机的。但每个节点只会执行一次,比如包含子节点:A、B、C、D、E;使用随机选择节点,执行顺序可能是:D、E、A、C、B或其他组合。其它规则同选择节点一致。

3、顺序节点(Sequence)

        该节点会从左到右的依次执行其子节点,只要子节点返回“成功”,就继续执行后面的节点,直到有一个节点返回“运行中”或“失败”时,会停止后续节点的运行,并且向父节点返回“运行中”或“失败”,如果所有子节点都返回“成功”则向父节点返回“成功”。

4、修饰节点(Decorator)

        修饰节点只包含一个子节点,用来以某种方式来改变这个子节点的行为。修饰节点的类型比较多,这里我们说一些比较常见的修饰节点:

1、Until Success和Until Failure

        循环执行子节点,直到返回“成功”或“失败”为止。

        比如Until Success在子节点返回“运行中”和“失败”时都会向父节点返回“运行中”,返回“成功”时向父节点返回“成功”。

        Until Failure在子节点返回“运行中”和“成功”时都会向父节点返回“运行中”,返回“失败”时向父节点返回“成功”。

2、Limit

        执行子节点一定次数后强制返回“失败”。当子节点运行指定次数后还没有返回“失败”则该节点向父节点返回失败。

3、Timer

        子节点不会立即执行,而会在指定的时间到达后才开始执行。

4、TimeLimit

        指定子节点的最长运行时间,如果子节点在指定时间到达后还在运行则强制返回“失败”。

5、Invert

        对子节点的返回结果取“非”,即子节点返回“成功”则该节点返回“失败”,子节点返回“失败”则该节点返回成功。      

5、并行节点(Parallel)

        不同于选择和顺序节点依次执行每个节点,并行节点是“同时”执行所有的节点,然后根据所有节点的返回值判断最终返回的结果。

        这里的“同时”会迷惑住不少人,实际上,行为树是运行在单一线程上的,并不会在并行节点上开多个线程来进行真正的同时执行,那么“同时”的含义是什么?

        我们知道选择或顺序节点会依次执行所有的子节点,当子节点返回“成功”或“失败”后就会停止后续节点的执行,而并行节点也会依次执行所有的子节点,无论子节点返回“成功”或“失败”都会继续运行后续节点,保证所有子节点都得到运行后在根据每个子节点的返回值来确定最终的返回结果。

        并行节点一般可以设定退出该节点的条件,比如:

        1、当全部节点都返回成功时退出;

        2、当某一个节点返回成功时退出;

        3、当全部节点都返回成功或失败时退出;

        4、当某一个节点返回成功或失败时退出;

        5、当全部节点都返回失败时退出;

        6、当某一个节点返回失败时退出;

叶节点

1、条件节点(Condition)

        条件节点可以理解为一个if判断语句,当条件的测试结果为true时向父节点传递success,结果为false时向父节点传递failure;

        该节点搭配一些组合节点可以完成各种判断跳转,比如搭配顺序节点,可以做出“是否看见敌人”->“向敌人开火”的AI;

2、行为节点(Action)

        行为节点用来完成具体的操作,比如,移动到目标点,执行开火等代码逻辑,多种情况下行为节点会返回running和success;行为节点也可能会使用多帧来完成;

子树的复用

        我们设计好的行为树可以在其他树中作为一颗子树来进行使用,最大可能的复用子树可以减少开发量。

总结:行为树的框架,网上有比较好的案例,如腾讯开源的behaviac。

        Github地址:https://github.com/Tencent/behaviac

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341

推荐阅读更多精彩内容

  • feisky云计算、虚拟化与Linux技术笔记posts - 1014, comments - 298, trac...
    不排版阅读 3,805评论 0 5
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,076评论 1 32
  • --- picknames.py --- 是注释行,Python是用#作为注释符的,每行注释的开始都要添加。Pyt...
    Noza_ea8f阅读 412评论 0 0
  • 话说不知是哪个朝代了,有一个县令他非常体恤百姓,经常微服私访。 一天,他扮成一个普通的商人带着一个仆役在城里考察老...
    醜与矁阅读 509评论 0 0
  • Y在电话里哭诉:我要回家了,我实在等不起。 Y出生在中国的北方城市,家境很好,是家中的独生女。她源于对“面朝大海、...
    立刻就很有阅读 186评论 0 0