参考书籍 Unity3D 人工智能编程精粹 Unity3D 人工智能编程
游戏 AI 的架构模型
运动层: AI 的具体行为, 比如移动
决策层: 决定 AI 下一时间步该做什么
战略层: 从集体层面对个体 AI 进行控制
除此之外, 还要结合动画系统, 物理引擎, 感知系统等, 共同组成人工智能
个体 AI
Seek 是最常见的 AI 行为, 最简单的实现是给 AI 添加一个修正力使之向目标移动
Flee 和 Seek 相反, 通常我们都要设置一个 Distance 范围判断结束行为用 Vector3.sqrMagnitude 向量平方长度, 计算会更快
Arrival 到达目标减速至停止, 可设置一个 StopDistance, 距离大于停止距离时给一个 Force 移向目标
Pursuit 追逐会预测 Target 的未来位置, 比如预测 t 时间内 Target 不会转向, AI 将计算未来位置朝之移动另外还可以用点乘计算夹角, 判断双方是不是面对面
Evade 逃避与 Pursuit 反向
Wander 随机徘徊设置一个圆周半径, 每帧给 Target 附加随机位移, 比 AI 只按照预设好的路线移动更加真实
FollowPath 路径跟随设置 radius 路点半经, 让 AI 在路径间切换更加真实
CollisionAvoidance 避开障碍向前射线检测障碍物的包围圈, 产生一个排斥力
集体 AI
组行为
分离: 避免局部拥挤
队列: 朝向附近同伴的平均朝向
聚集: 向附近同伴的平均位置移动
Radar 检测附近的 AI 角色(数学 / Trigger)
Separation 分离搜索领域内的其他邻居, 计算两者间的向量并单位化, 得到排斥力方向, 排斥力大小与距离成反比
Alignment 队列将 AI 的朝向纠正为和邻居一致, 平均朝向减去当前朝向就是操控朝向
Cohesion 聚集
集体 AI 往往需要一个集体状态机, 负责判断团队整体状态和动作
各个角色则需要完成动作的多层状态机设置, 比如这层行动路线, 下层具体行为, 下层角度速度细节
AI Director 导演系统控制整局游戏流程
更多实例暂略
A * 寻路
A* (A-Star)算法是一种静态路网中求解最短路最有效的直接搜索方法, 也是许多其他问题的常用启发式算法注意是最有效的直接搜索算法, 之后涌现了很多预处理算法(如 ALT,CH,HL 等等), 在线查询效率是 A * 算法的数千甚至上万倍
欧几里得 / 欧拉距离: 多维空间两点间的距离, 即直线距离
曼哈顿距离: 估计到目标格子之间的水平和垂直方格的数量和, 即不走斜路
地图, 目标估计, 代价, 节点
导航图: 将地图用图表示
1 基于单元的导航图
将地图划分为多边形单元组成的规则网格易于动态更新, 但时间空间消耗都大
2 创建可见点导航图
先手工放置一些路径点, 然后若路径点之间可视, 就能以边连接可以设置一些特殊点, 适合简单的寻路
3 创建导航网格 NavMesh
将可行走区域划分为凸多边形可以是多种多边形的组合, 让网格划分更加合理
采用视线确定方法, 向前跳到视线最远途经点, 对路径进行后处理, 得到更平滑的路径
效率高, 空间小
以基于单元的导航图为例, 执行 A * 算法
g(n): 起始节点到当前节点 n 的代价
h(n): 当前节点 n 到目标节点的估计代价
f(n)=g(n)+h(n) 从初始状态经由状态 n 到目标状态的代价估计
open 表: 待考察的结点的优先级队列, 代价从低到高(可以不排序, 只找最小值)
closed 表: 已考查的结点列表
第一步: 取起始结点, 将其 8 个邻接点加入 Open, 并将各邻接点的父节点设置为起始节点, 起始点加入 Close
第二步: 计算 open 表中结点的代价 f=g+h, 计算规则是:
g: 取父节点 g 值, 根据 n 点和父节点的连接方式计算如果是直角连接 g++, 对角连接 g+=1.414
h: 采用欧几里得距离 / 曼哈顿距离[不考虑障碍物]
根据 f 大小来确定 open 表中下一个要被检查的节点
第三步: 取 f 最小结点, 检查 8 个邻接点, 障碍物点无视
计算各邻接点通过当前结点得到的新 g 值, 计算规则同上
新结点加入 open 表
已经在 open 表的, 若新 g 值比原值大, 不需更新若小于原值, 则更新 g,f, 父节点, 而不用更新 h
已经在 closed 表的, 按上图文字处理
第四步: 对于具有相等的最小代价值 f 的结点, 可任选一个计算
循环直到终点
其他
1. 对于已经计算的 (存在于 open 或 closed 表中) 节点, 无需再次计算, 因为选择那些节点只会绕远
2. 障碍物节点加入 closed 表, 对于被 open 或 closed 表包围的节点, 也加入 closed 表中
和 Dijkstra 算法的区别:
Dijkstra 是 BFS, 不会去预估到终点的距离, 因此在有多个权值相等的路径时会搜索很多不必要的结点而且没有考虑障碍物
A * 是按照启发函数, 向着目标搜很适合寻路
Dijkstra 会求出所有点的最短路径, 得到理论上的最优解, 而 A * 则只会找需要计算的点结果是 A * 更快, 但是不一定是最优解
Unity 寻路
AI 使用 NavMeshAgent 组件
如果要配合物理引擎使用, 则 AI 需要有 kinematic 的刚体, 表示刚体由 nav 控制
和 Animator 配合使用的话, 最好不要用 root motion
将地面勾选 Navigation Static, 再打开 Navigation 视图, 点击 bake 即可看到蓝色可达区域
Navigation Area 可以设置 object 为不同 Area, 会用不同颜色表示
可以在 NavMeshAgent 中修改其可以行走的 Area
Off Mesh Link 添加跳跃点(手动路径)
默认的 NaveMesh Agent 组件上面是勾选了 Auto Traverse Off Mesh Link(自动通过 OffMeshLink)选项的这样的意思是人物只要到了 OffMeshLink 的开始点, 就会自动的移动到 OffMeshLink 的结束点
Navmesh Obstacle
enable 时不可通行, false 时可通行此情况下物体不会暂停
寻路还有很多用法, 这里就暂不详述了
AI 感知事件
AI 往往要感知视觉听觉等信息来决策下一步的行为, 其中又包括位置信息, 对象属性信息, 自身信息等
1 轮询(主动查询信息)
轮询类似编程中的 switch-case, 是 AI 周期性地查询所需要的信息, 轮询非常常见, 容易维护, 但有效信息率低, 花费性能较多
轮询中心(没有必要每个 AI 都进行一遍查询, 而是集中处理需要查询的信息)
2 事件驱动(被动得知信息)
事件是一种高效的消息传递机制, 由事件分发者主动通知每个感兴趣的 AI, 这样就使 AI 准时获得有效信息
可以做一个中心检测系统(事件管理器), 记录每个 AI 感兴趣的事件, 并通知他们, 还方便了调试
3Trigger 触发器
触发器其实和事件比较接近, 相比之下, 触发器是事件的本源, 比如监听声音的声音触发器, 检测观察物的视觉触发器, 等待时间的时间触发器等等
Trigger 常用一个半径计算检测的范围,
Sensor 感知器则定义了枚举类型和变量, 保存了事件管理器
视觉感知: 圆锥形探测
听觉感知: 衰减范围而感知器也有对应的感知阈值
触觉感知: 碰撞器
记忆感知: 记忆 List+Time 留存时间
FSM 有限状态机
finite-state machine 是表示有限个状态 以及在这些状态之间的 转移和动作等行为的数学模型
最简单的用 enum+switch 即可实现
在 Unity 中, 我们可以用 Animator 或其他 FSM 框架实现可视化状态机
但是对于一些复杂的 AI, 用 FSM 图十分繁琐, 效率低且容易出错, 对一般的 AI 来说, FSM 就足够了
BehaviorTree 行为树
行为树是由行为节点组成的树状结构
对于 FSM, 每个节点表示一个状态, 而对于 BT, 每个节点表示一个行为
行为树层次清晰, 易于模块化, 封装性好, 可重用, 是一种效果理想的 AI 编辑器
在 BT 中, 节点是有层次 (Hierarchical) 的, 子节点由其父节点来控制
每个节点的执行都有一个结果(成功 Success, 失败 Failure 或运行 Running), 该节点的执行结果都由其父节点来管理, 从而决定接下来做什么, 父节点的类型决定了不同的控制类型
常见结点: Sequence,Selector,Parallel,Decorators
AI 实例
AI 包括设计和实现两部分
AI 设计
首先要根据需求, 设计关卡中合适的 AI, 是个体还是集体, 有什么特点, 可行性, 并制作相应的资源
AI 的基本逻辑: 感知 - 行动 - 反应 - 学习
AI 的基本能力
AI 的基本属性
设计逻辑流程图 / 状态图
设计 AI 使用技能, 就好比调用一个结点
2D 横版 AI
个体行动: 待更新
集体战术: 夹击, 车轮, 埋伏
3D 平面 AI
常见的技能行为有: 追寻, 连击, 远程攻击, 固定线路攻击, 绕路, 反向攻击, 跳起等等
关于 Unity-AI 的更多技术, 我将另外写篇博文
来源: http://www.bubuko.com/infodetail-2502223.html