iPhone寻路实施

时间:2010-08-09 21:05:51

标签: iphone multithreading a-star

我正在尝试为iPhone创建一个Pacman AI,而不是Ghost AI,而是Pacman本人。我正在使用A *进行寻路,我有一个非常简单的应用程序启动和运行,它计算游戏板上两块瓷砖之间的最短路径,避开墙壁。

因此,运行1函数来计算2点之间的路径很容易。一旦函数到达goalNode,我就可以通过每个tile'parentNode'属性向后遍历路径并创建所需的动画。但在实际游戏中,状态不断变化,因此路径和动画也必须如此。我是游戏编程的新手,所以我不确定实现它的最佳方法。

我是否应该创建一个在后台运行的NSOperation,并根据游戏的当前状态不断计算goalNode及其最佳路径?该线程还必须在某些点通知主线程并提供信息。问题是什么?

我应该在什么时候通知主线程?

我应该通过主线程通知哪些数据?

......还是我一起离开了?

非常感谢任何指导。

3 个答案:

答案 0 :(得分:1)

对于pacman AI,我建议您使用泛洪填充算法来计算网格上每个图块的最短路径和总距离。这是一个比A *简单得多的算法,实际上比A *具有更好的最坏情况,这意味着如果你能够在每一帧都买得起A *,那么你可以买得起洪水。

为了更详细地解释性能比较,想象一下A *中的最坏情况:由于死角,你最终必须在到达最终目的地之前探索网格上的每个图块。如果你在电路板上有很多死角,这个理论案例是可能的,但在大多数现实世界的pacman板上都不太可能。洪水填充的最坏情况与最佳情况相同,您只需访问地图上的每个瓷砖一次。不同之处在于迭代步骤对于泛洪填充比对A *迭代(没有启发式,没有节点堆等)更简单,因此使用泛洪填充访问每个节点比使用A *更快。

实施非常简单。如果您将网格想象为图形,每个图块都是一个节点,并且相邻图块之间没有墙的每条边作为图形中的边缘,您只需对图形进行广度优先遍历,跟踪您来自哪个节点你从那里探索过多少个节点。您在访问节点时将其标记为已访问,并且从不访问节点两次。

这里有一些伪代码可以帮助您入门:

openlist = [ start_node ]
do
    node = openlist.remove_first()
    for each edge in node.edges
        child = node.follow_edge(edge)
        if not child.has_been_visited
            child.has_been_visited = true
            child.cost = node.cost + 1
            child.previous = node
            openlist.add(child)
while openlist is not empty

要弄清楚如何让pacman移动到某个地方,你可以从你想要的节点开始,然后按照.previous指针一直回到开头,然后反转列表。

关于这一点的好处是,您可以定期查询到达地图上任何图块的成本。例如,您可以遍历每个电源芯块并计算哪一个最接近,以及如何到达那里。

你甚至可以使用它来让鬼魂知道当他们处于“攻击”模式时最快回到pacman的方式!

您可能还会考虑来自每个鬼魂的洪水填充,在每个瓦片中存储距离最近的鬼魂有多远。您可以限制探索的最大距离,如果它们大于某个最大成本(8个方格?),则不会将节点添加到打开列表中。然后,如果您之后DID执行A *,则可以根据鬼魂的接近程度来估算每个图块的成本。但是这比你在问题中提出的要求有所提高。

它应该足够快,你可以在每一帧内联它,或者如果你愿意多线程。为了简单起见,我建议你只是在主游戏模拟线程(注意,而不是UI线程)中进行,因为当完成所有操作时它确实应该非常快。

一个性能提示:您可以简单地使用一个搜索计数器来增加每个帧,而不是通过并清除每帧的“has_been_visited”标记。像这样:

openlist = [ start_node ]
do
    node = openlist.remove_first()
    for each edge in node.edges
        child = node.follow_edge(edge)
        if child.last_search_visit != FRAME_NUMBER
            child.last_search_visit = FRAME_NUMBER
            child.cost = node.cost + 1
            child.previous = node
            openlist.add(child)
while openlist is not empty

然后你只需每帧增加FRAME_NUMBER。

祝你好运!

答案 1 :(得分:0)

略有不相关,但你见过ASIPathFinder framework吗?如果您有更高级的寻路需求,可能会有所帮助。

答案 2 :(得分:0)

我建议只预先计算地图中所有点对之间的距离。这需要n ^ 2/2空间,其中地图中有n个可遍历点。根据{{​​3}},板上有240个颗粒,这意味着有大约57k个点的组合,您可以查询它们之间的距离。这非常小,可以压缩(this link)以减少占用空间。

然后,在运行时,除了查看可能的移动和到达该位置的距离之外,您不必进行任何实际计算。