我专注于寻路的任务,找到从一个地方走到另一个地方的路径。
然而,一个同样重要的问题是:一旦我有了一条路,我该如何移动呢?
最明显的答案是从位置 A 走直线移动到位置 B。
我们可能还希望以曲线的方式移动,或者具有多个移动种类。
但是这些路径中的部分位置,在微观视角来看,可能是偏离航线的。
再让我们提出一个更高级别的问题是:你想去哪里?
我们应当首先回答更高级别的问题,否则寻路会不好使。
常见的 AI 探索,间谍,攻击和建设,他们很有可能会自动寻找目标,自动寻路。
单位运动
我专注于寻路,这减少了从一个位置移动到另一个位置的问题,从一个空间移动到相邻空间的许多小问题。
您可以从一个位置直线移动到下一个位置,但也有其他选择。考虑此图中的四个移动路径:
红色路径是标准方法:从一个正方形的中心移动到下一个正方形的中心。
绿色路径稍好一些:在网格之间的边缘之间以直线移动,而不是在网格的中心。
您也可以尝试在网格的角和角之间直线移动。
蓝色路径使用样条曲线,深蓝色为低阶样条曲线,浅蓝色为高阶样条曲线。
网格的角和边之间的线将是最短的解决方案。
但是,样条曲线可以使您的单位看起来不那么机械,更“活跃”。
这是一个低开销的技巧,但不是一个伟大的技巧。有更好的方法来处理运动。
如果您的单位无法轻松转向,您可能需要在绘制运动路径时考虑到这一点。
Craig Reynolds 有一个很棒的关于转向的页面,其中有一篇关于转向和Java小程序的论文,展示了各种行为。
如果您有多个行走单元沿路径移动,您可能还需要研究一下群(Flocking,类鸟群 Boids)。
克雷格建议,不要将路径视为单位必须访问的地方列表,而是将路径视为 “指导原则,根据条件的要求,您可以根据该指南进行反应。”
如果您使用网格进行寻路、您的单位不受网格限制、且移动成本是均匀的,您可能希望通过直线从一个节点移动到远处前方的节点(当没有障碍物时)来拉直路径。
如果您正在使用导航网格,请查看漏斗算法。
行为标志或栈
您的单位可能有多个目标。
例如,你可能有一个像“间谍”这样大致的目标,但也有一个更直接的目标,比如“去敌人总部”。
此外,可能还有一些临时目标,比如“避开那个巡逻警卫”。
以下是目标的一些想法:
- 停止:留在当前位置
- 住宿:住在一个区域
- 逃离:搬到安全的地方
- 撤退:移动到安全区域,同时对抗敌方单位
- 探索:查找并了解知道少量信息的区域
- 漫步:漫无目的地四处走动
- 搜索:查找特定对象
- 间谍:靠近一个物体或单位以了解更多信息,而不会被人看到
- 巡逻:反复穿过一个区域以确保没有敌方单位通过它
- 防守:靠近某个物体或单位,以防敌方单位远离
- 守卫:靠近某个区域的入口,以防敌人单位出局
- 攻击:移动到某个对象或单位以捕获或摧毁它
- 环绕:与其他单位一起,试图围绕敌方单位或物体
- 远离:远离某个物体或任何其他单位
- 跟随:移动时靠近某个单元
- 组:寻求并形成单位组
- 工作:执行一些任务,如采矿,耕作或收集
对于每个单元,您可以有一个标志,指示它要执行的行为。
要拥有多个级别,请保留行为栈。
栈的顶部将是最直接的目标,栈的底部将是总体目标。
当你需要做一些新的事情,但后来想要回到你正在做的事情时,在栈上推送一个新的行为。
如果您需要做一些新事情但又不想回到旧行为,请清除栈。
完成某个目标后,从栈中弹出它并开始在栈上执行下一个行为。
等待移动
移动算法将不可避免地遇到在寻路过程中不存在的障碍。
一种易于实现的技术基于其他障碍物将首先移动的假设。
当障碍物是友好单位时,这尤其有用。
当障碍物挡住时,等待一段时间让它移动。
如果在该段时间后仍未移动,请重新计算其周围或目的地的路径。
如果提前检测到障碍物,您的单位可以简单地走得更慢,让其他单位有更多时间离开。
两个单元可能会相互碰撞,每个单元都会等待另一个单元继续运行。
在这种情况下,可以使用优先级方案:为每个单元分配唯一的编号,然后使编号较小的单元等待编号较高的单元。
如果两个单位都在等待,这将迫使其中一个单位继续进行。
当提前检测到障碍物时,较低编号的单位应在到达预期碰撞点之前减速。
协调运动
当单位试图穿过狭窄的走廊时,上述技术不起作用。
如果一个单元静止而另一个单元试图四处走动,则两个单元都不能使用该走廊。
一个单位将阻止它,而另一个单位将走很长的路径。
第二个单元应该可以与第一个单元通信,并要求它退出。
一旦走廊畅通,第二个单元就可以通过,然后第一个单元就可以通过。
除非您事先能够识别走廊,否则实施起来可能很复杂。
对于随机生成的地图,可能很难确定走廊的位置以及第一个单元需要后退的距离。