热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

游戏AI模块设计行为树

http:logit.meblog20131010game-ai-design游戏AI模块设计OCT10TH,2013|COMMENTS概述针对当前新的怪物AI需求,

http://logit.me/blog/2013/10/10/game-ai-design/



游戏AI模块设计

OCT 10TH, 2013 | COMMENTS

概述

针对当前新的怪物AI需求,简化怪物AI脚本编写,提高怪物AI运行效率,抽象出AI框架结构,增强框架的灵活性及扩展性,同时能够让设计人员快速的开发怪物AI。

需求

相对之前的怪物AI,当前新怪物AI相对比较简单,主要是由移动、攻击等基本行为组成的。

AI实现方式

游戏中怪物AI的现有设计方法主要有:

  1. 直接编码,或者给每个特定的怪物挂特定的脚本,当前我们游戏中很大一部分就是这样实现的;
  2. 有限状态机(FSM), 怪物在若干个状态中根据游戏世界中产生的特定事件产生特定的游戏行为,同时怪物进入新的状态;
  3. 行为树(Behavior Tree),怪物AI由若干个类型节点组成的树形结构,每个节点含有前置条件,当前置条件满足时执行该节点;

由于直接给每个怪物挂脚本的形式对于AI开发人员来说工作量繁琐,并且容易造成重复性劳动,下面主要阐述下有限状态机及行为树。

有限状态机

有限状态机(finite-state machine, 缩写: FSM)又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型,一个有限状态机可以用一个关系式描述:

State(S) x Event(E) -> Action(A), State(NS)

这些关系解析如下:如果我们处于状态S并且事件E发生了,那么我们需要执行动作A,并且状态转换为NS。

当前游戏中怪物AI很大部分是基于FSM实现的,例如一个巡逻小怪的AI可以表示为:

FSM

行为树

行为树(Behavior Tree, see),顾名思义,它是由若干个子节点组成的树形结构,如下图所示:

BehaviorTreeExample

其中叶子节点为行为节点,行为节点是游戏相关的,不同的游戏可以定义不同的行为节点,行为节点通常分为两种允许状态:

  1. 运行中(Running),该行为还在处理中;
  2. 完成(Finished),该行为处理完成;

其余节点是控制节点, 我们可以为行为树定义各种各样的控制节点(这也是行为树有意思的地方之一),一般来说,常用的控制节点有以下三种

  1. 选择(Selector), 选择其子节点的某一个执行;
  2. 序列(Sequence), 将其所有子节点依次执行, 也就是说当前一个返回”完成”状态后,再运行先一个子节点;
  3. 并行(Parallel), 将其所有子节点都运行一遍;

当AI决策时从树的根节点自顶向下(depth-first search),通过一些条件搜索这棵树,最终确定需要的行为(叶子节点),并执行相应动作。

行为树实现

Task = {update = function(args) end,on_enter = function(args) end,on_exit = function(args) end,
}
BehaviorNode = {nodes = {},status = 0,task = nil,tick = function(args)return task:update(args)end,
}
BehaviorTree = {object = nil,root = nil,tick = function(args)if root thenroot:tick(args)endend,
}

之前巡逻小怪AI用行为树可以表示为:

behavior_tree_2

如何选择子节点

如何从子节点中选择呢?选择的依据是什么呢?这里就要引入另一个概念,一般称之为前置条件或者前提(Precondition),每一个节点,不管是行为节点还是控制节点,都会包含一个前提的部分,如下所示:

-- lua code
local behavior_node = {precondition = function() return true end,action = function()-- do somethingend,
}

当自顶向下搜索行为树时,依次测试每个子节点的前提,如果满足则进入该子节点,以此继续选择下一个节点,最终返回某个行为节点,所以当前行为节点的前提可以表示为:

Precondition[CurrNode] = Precondition[CurrNode.Parent] and Precondition[CurrNode.Parent.Parent] and ... and Precondition[RootNode]

行为树就是通过行为节点,控制节点,以及每个节点上的前提,把整个AI的决策逻辑描述了出来,对于每次的Tick,可以用如下的流程来描述:

action = root.FindNextAction(input)
if action is not empty thenaction.Execute(request, input) --request是输出的请求
elseprint "no action is available"
end

与有限状态机比起来,行为树结构还是比较简单的,而且当从概念上来说,行为树还是比较简单的,但对AI程序员来说,却是充满了吸引力,它的一些特性,比如可视化的决策逻辑,可复用的控制节点,逻辑和实现的低耦合等,较之传统的状态机,都是可以大大帮助我们迅速而便捷的组织我们的行为决策。根据行为树的可视化的决策逻辑的特性可以开发出类似流程图绘制的编辑器,通过拖拽的方式定制怪物AI逻辑、编写各个节点的前提脚步及行为节点的游戏逻辑,同时能够导出lua脚本。

关于行为树更加详细的解释见这里

目前使用行为树的游戏

  1. Halo 3 & ODST
  2. League of Legends 参考幻灯片

AI模块设计

AI模块作为一个黑盒,依赖特定的输入进行决策再输出特定的请求,整体结构如下图所示:

AI Module

  • INPUT,AI输入数据,由游戏中产生的各种事件构成,主要有:
    1. 碰撞事件
    2. 技能事件
  • AI Module,由行为树组成的AI决策模块;
  • AI输出,AI决策结果,主要有:
    1. 移动: 请求移动模块移动到目标点
    2. 技能模块: 通过creature:use_skill(args)直接使用技能

Lua脚本集成

行为树每个节点的前提(Precondition),进入、退出、动作等是游戏相关性的,将这些与游戏逻辑紧密相关的部分使用lua脚本实现,每个行为树节点表示为:

follow_base = {precondition = function()-- check conditionend,behavior = function()-- do somethingend,on_enter = function()-- do somethingend,on_exit = function()-- do somethingend,
}

行为树编辑器

实现类似如下可视化AI行为树编辑器:

  1. From “Three Ways of Cultivating Game AI”BehaviorEditor1
  2. A plugin for Unity EditorBehaviorEditor2
  3. CryENGINE 3BehaviorEditor3





推荐阅读
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • Ubuntu安装常用软件详细步骤
    目录1.GoogleChrome浏览器2.搜狗拼音输入法3.Pycharm4.Clion5.其他软件1.GoogleChrome浏览器通过直接下载安装GoogleChro ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
author-avatar
mobiledu2502934191
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有