Answers:
通常,您将要使用A *,除非您正在寻找重要不同的东西。
我需要解决一个类似的问题:在一个大型迷宫状的网格上寻找路径,不断变化的“成本”和障碍。
问题是,在塔防游戏中,需要为其求解路径的实体数通常比图中的节点数大得多。A * 不是最合适的算法,因为每次更改时您都需要重新解决它。好吧,如果您只需要找到一条路径,那是合适的,但是在我的情况下,我需要能够处理可能出现在不同位置且每个实体都有自己路径的实体。
在弗洛伊德-沃肖尔算法是更为合适的,但对于我来说,我写了一个自定义算法,每当一个节点发生变化时,重新计算成本,从所有邻居节点,然后如果邻居已经改变了它被调用递归地对待他们。
因此,在游戏开始时,我只是在所有“目标”节点上启动了该算法。然后,每当一个节点发生更改(例如,变得不可通过)时,我都会在该节点上启动它,并将更改传播到将受影响的所有节点,然后停止。因此,无需进行全局重新计算,并且该算法完全独立于需要寻路的实体数量。
我的算法基本上类似于(伪代码):
update_node method in Node class:
$old <- $my_score
find $neighbor node among all neighbors such that
$neighbor.score + distance_to($neighbor) is minimal
$my_score <- $neighbor.score + distance_to($neighbor)
$next_node <- $neighbor
if ($my_score != $old)
for each $neighbor
$neighbor.update_node()
初始分数取决于节点是目标还是某种障碍。
由于我在游戏中拥有的实体数量,我在TD上使用的路由算法比正常的A *路径落后。我没有从目标路由到坏人,而是从目标路由到了板上的每个空白方块。
这并不需要很长时间,您只需不断迭代电路板,直到找到您的“成本”,并且它为被阻塞的路由提供了很好的反馈(如果您正在执行这些操作)。与A *相比,使用Floyd算法是快速且缓存友好的,因为它不进行依赖数据的查找,它只是在流中加载数据并对其进行操作。
首先将您的面板设置为无限成本,然后将目标平方设置为零成本,然后在面板上进行迭代以检查相邻单元的成本是否小于当前成本加上差旅成本。旅行费用是您进行启发式分析的地方(在我的情况下,对角旅行的成本是无限的,但是穿过塔楼的成本很高,因此允许他们穿过塔楼进餐,但除非没有选择)
一旦获得了成本网格,就可以通过测试单元上最陡峭的成本梯度来快速构建一个“流”网格。这对于大量的坏人确实非常有效,因为他们中的任何一个都不必寻找路径,他们只是遵循虚拟路标。
另一个好处是,通过这种方式,您只需在每次调整障碍物时(或在我的游戏中,当小兵吞噬其中一个塔楼时)就运行此任务。并非每次都有小兵/暴民进入该领域(每秒成千上万的暴民和数十个暴民会令人头疼)。
寻路速度很快,并且在某种正常的塔防游戏大小的情况下,只要情况发生变化,您就可以毫无困难地运行完整的A *或Dijkstra传球。一毫秒之内,我们正在谈论一个完整的刷新。任何一种自适应寻路最终都会变得极其复杂。除非您要制作世界上最大的塔防网格,否则只需简单的方法即可。
A *寻路如何工作?可能是一个开始的好地方:-)
航路点寻路可能是td游戏的最佳选择,因为通常基于ai遵循直接路径的级别。基本上,您可以设置节点或航路点,然后将“ ai”点指向路标并走到它,一旦距该路标足够近,就可以到达下一个路标,面向它并朝它前进。
有人问过,您可以通过在玩家每次放置或卸下塔楼时重新计算路径来应对动态变化的环境,而您只是将该路径存储在内存中。环境不会在每一帧上都改变。
请注意,某些TD游戏具有设定的路径,并且不允许您在其上放置塔楼,因此它们可以通过简单的方法解决寻路:通过对路径进行硬编码而不是阻止路径:)
一个简单的解决方案是作弊。
事先设计地图,以确保没有死角。然后在每个路口,添加一个触发器,使角色选择路线(例如:始终向左转,始终向右转或随机)。