吃豆子:眼睛如何回到怪物的洞中?


321

我在《吃豆人》中找到了很多有关鬼魂AI的参考文献,但没有人提到吃豆子吃掉鬼魂后眼睛如何回到中央鬼洞。

在我的实现中,我实现了一个简单但糟糕的解决方案。我只是在每个角落都硬编码了应该采取的方向。

有没有更好的解决方案?也许是一种适用于不同级别设计的通用产品?


11
您确定拐角处的硬编码足够好吗?这不能保证最佳路线。想象一下,幽灵面对着长长的狭窄通道。按照您的算法,他将必须沿着整个通道走下去,到达一个角落,然后走最快的路线。如果您在每个方格上硬编码要走的方向,他可能会知道先转身。
Mark Peters 2010年

3
@Mark,取决于您在拐角处的定义。即使是T型连接,即使您直接在最上面一行走也可以。
托尔比约恩Ravn的安德森

1
@Thorbjørn:我什至没有在谈论交叉路口。看一下此板:en.wikipedia.org/wiki/File : Pac-man.png。如果幽灵向右移动并位于左下角的第二个点,那么它暂时不会遇到任何相交处。这将使其比向后(左)走并走过最短路径的距离再走10格。
Mark Peters 2010年

6
您的解决方案利用了航路点(或面包屑),我认为这是加速路径查找算法的常用技术。
尼克·丹杜拉基斯

1
感谢所有的答案!我只是坚持以前的解决方案,并对每个角落的方向进行了硬编码。为了使它通用,要求关卡设计器/关卡文件还在关卡定义中定义此信息。
RoflcoptrException 2010年

Answers:


152

实际上,我想说您的方法是一个很棒的解决方案,与任何寻路方法相比,运行时间成本几乎为零。

如果您需要将其推广到任意地图,则可以使用任何寻路算法-例如,广度优先搜索易于实现-并在运行游戏之前使用该算法来计算在每个角上要编码的方向。

编辑(2010年8月11日):我刚刚被引到有关Pacman系统的一个非常详细的页面:Pac-Man Dossier,并且由于我在这里有公认的答案,因此我觉得我应该对其进行更新。这篇文章似乎没有明确介绍返回怪物屋的行为,但指出吃豆人中的直接寻路是以下情况:

  • 继续朝下一个交叉路口行驶(尽管这实际上是“在有选择的情况下,选择不涉及反转方向的方向的特殊情况,如下一步所示);”
  • 在相交处,查看相邻的出口正方形,除了您刚来自的出口正方形。
  • 选择最接近目标的一个。如果多个目标同样接近目标,请按以下顺序选择第一个有效方向:上,左,下,右。

16
我认为他的意思是您可以在运行时(加载关卡但开始播放之前)进行计算,而只需一次。 这并不难维护。
Mark Peters 2010年

3
是的,或者是否有创建地图的工具。
Kylotan 2010年

6
预计算返回路径没有错。您正在为实现运行时性能而交换存储(路径)。
郭富城

6
谢谢。我认为我会坚持这种解决方案。有人知道原始吃豆人是怎么做的吗?
RoflcoptrException

4
不,我不知道 最初的问题使用该术语,但并不完全具有法律约束力。
Kylotan

85

我已经通过以下方式解决了通用关卡的这个问题:在关卡开始之前,我从怪物洞中进行了某种“洪水填充”;迷宫中每块不是墙的瓷砖都会得到一个数字,说明它离孔有多远。因此,当眼睛在距离为68的图块上时,他们会看哪个相邻的图块之间的距离为67;那就是要走的路。


15
是。在世界不太大而无法生存的情况下,Floodfill非常适合寻路。我认为通过强加一个预先计算连通性的粗网格,甚至可以在大世界中使用它。它将使事情变得有些混乱,但这将比我在此类游戏中看到的交通拥堵更好。
罗伦·佩希特尔

1
为了节省空间(用于较大的世界或受约束的系统),可以保存在每个交叉点的行进方向,而不是为每个图块保存值。这实质上是OP所建议的。
BlueRaja-Danny Pflughoeft 2011年

BlueRaja:可以,但是这样做比较复杂,结果也不是那么理想-幽灵在两个路口之间被吞噬,因此他可能会在一段时间内遇到错误的方向。我的解决方案在en.wikipedia.org/wiki/HP_200LX上运行良好,那么还能得到多少约束呢?
Erich Kitzmueller 2011年

5
(我来晚了...)是的,填充洪水是好的,但是您实际上不需要整数,只需每个正方形的一个方向(两位)指向下一个正方形即可使用。
Matthieu M. 2012年

Matthieu:是的,这可能是一种优化。
Erich Kitzmueller 2012年

42

对于更传统的寻路算法的替代方法,您可以看一下(适当命名的!)Pac-Man Scent Antiobject模式

您可以在启动时在迷宫周围散布怪异的气味,并让眼睛跟随它。

气味一旦建立,运行时间成本将非常低。


编辑:可悲的是维基百科的文章已被删除,所以WayBack Machine营救 ...


2
这将是我的答案。它与ammoQ基本相同,但我一直记得吃豆子的味道:)
卢克·谢弗

维基百科的文章似乎已被删除。谷歌的最高结果是这个线程,但我认为接近。
大卫

2
我一秒钟感到困惑,但随后立即理解了“气味”的含义。这是描述这些标量场事物的好方法!
史蒂文·卢


18

任何可行的简单解决方案都是可维护,可靠且性能良好的解决方案。在我看来,您已经找到了一个很好的解决方案...

寻路解决方案可能比您当前的解决方案更为复杂,因此更可能需要调试。可能还会变慢。

IMO,如果它没有损坏,请不要修复它。

编辑

IMO,如果迷宫是固定的,那么您当前的解决方案就是好的/优雅的代码。不要把“好”或“优雅”等同于“聪明”。简单的代码也可以是“好”和“优雅”的。

如果您具有可配置的迷宫等级,那么也许您应该在最初配置迷宫时进行寻路。最简单的方法就是让迷宫设计师手工完成。如果您有成千上万的迷宫,或者用户可以设计它们,我只会自动进行此操作。

(此外:如果通过手动配置路线,迷宫设计者可以通过使用次优路线来使关卡更加有趣...)


是的,它正在工作。但是我想写好的代码,而不仅仅是代码。另外,我在问题中添加了最后一句话,因此,如果可能,该算法不仅应针对一个迷宫,而且应针对多个迷宫。
RoflcoptrException 2010年

迷宫也可以生成(我有一个算法可以生成漂亮的
吃豆人

“ ...或用户可以设计它们。” 在这种情况下,您确实有一个惊人的迷宫。
phuzion

@phuzion-我知道。但是,这两种情况是有区别的。如果是OP创建了一个迷宫般的迷宫,那么必须手动创建路由是一种不便。如果它是最终用户……这意味着OP必须编写文档,对最终用户的迷宫进行无尽的故障排除,就其不友好程度进行无休止的投诉等等。换句话说,实现自动路由生成的原因不同的
Stephen C

14

在原始的《吃豆人》中,鬼魂通过“气味”找到了吃黄色药丸的人,他会在地图上留下痕迹,鬼魂会随机游荡直到找到气味,然后他们便沿着气味路径直接将它们引向玩家;选手。每次Pacman移动时,“气味值”都会减少1。

现在,一种简单的逆转整个过程的方法是使用“幽灵金字塔”,其最高点位于地图的中心,然后幽灵便朝着这种气味的方向移动。


我真的很喜欢这种方法,我还将尝试这种方法
RoflcoptrException 2010年

5
这是不对的。如果他们都遵循这种算法,他们最终将追逐他一个文件。每个鬼的行为是不同的。您可以在Wikipedia文章上找到更多信息。
分频器2012年

5

假设您已经具备了追逐pacman所需的逻辑,为什么不重用它呢?只要改变目标。似乎比使用完全相同的逻辑创建一个全新的例程要少得多。


是的,我有追捕已经实施的pacman的逻辑,但是我也不满意;)
RoflcoptrException 2010年

根据我的经验(我喜欢写pacman版本只是为了好玩),这样做会导致眼睛长时间陷在洞外。那是因为追逐算法通常遵循“如果吃豆人在北方,往北走”的路线,但是迷宫中可能包含“陷阱”,在这里眼睛必须先向南走。由于吃豆子移动,幽灵迟早会逃脱,但该洞是固定的目标。(注意:我是在谈论产生的迷宫)
Erich Kitzmueller 2010年


3

每个正方形到中心的距离值如何?这样,对于每个给定的正方形,您都可以在所有可能的方向上获得相邻邻居正方形的值。您选择具有最低值的正方形,然后移至该正方形。

可以使用任何可用算法预先计算值。


我打算建议这个。从“怪物洞”开始的向外洪水填充。我认为您的回答将从图片中受益。
AjahnCharles

3

这是我可以找到其实际工作方式的最佳信息。

http://gameai.com/wiki/index.php?title=Pac-Man#Respawn 当幽灵被杀死时,他们虚弱的眼睛又回到了起始位置。只需将鬼影的目标图块设置到该位置即可完成。导航使用相同的规则。

这实际上是有道理的。也许这不是世界上最高效的,但是不必担心其他状态或沿这些路线的任何事情的好方法,您只需更改目标即可。

旁注:我没有意识到,那些吃豆人程序员基本上是在很小的空间内以非常有限的内存制作了整个消息系统,这真是太了不起了。


2

我认为您的解决方案比这个简单,更适合解决该问题,是使新版本更“逼真”,鬼魂的眼睛可以穿过墙壁=)


2
要增加更多的真实性,请允许鬼魂自己能够穿过墙壁移动:D
托马斯·爱丁

3
这些是鬼的不透明墙,但是二阶鬼(鬼的鬼)更加透明。(你可以找到很多的bug的用户手册中的功能转换)
埃尔南Eche

1
+1为“第二阶幽灵”-哦,是的,幽灵的派生必须肯定超越诸如墙壁之类的一阶物体……:)
Assad Ebrahim 2012年

2

这是ammoQ的洪水填充想法的模拟和伪代码。

queue q
enqueue q, ghost_origin
set visited

while q has squares
   p <= dequeue q
   for each square s adjacent to p
      if ( s not in visited ) then
         add s to visited
         s.returndirection <= direction from s to p
         enqueue q, s
      end if
   next
 next

其想法是,这是广度优先的搜索,因此,每次遇到新的相邻平方s时,最佳路径是通过p。我确实相信是O(N)。


2

对于您如何实现游戏我不太了解,但是您可以执行以下操作:

  1. 确定眼睛位置与门的相对位置。即在上面吗?就在下面?
  2. 然后将眼睛朝两个方向之一移动(例如,如果它在大门的右侧,则使其向左移动,而在大门下方),并检查是否有墙壁和墙壁阻止您这样做。
  3. 如果有阻止您这样做的墙壁,则使其朝相反的方向移动(例如,如果眼睛相对于图钉的坐标位于右北,并且当前正在向左移动,但有一个阻碍该方向的墙壁向南移动。
  4. 记住每次移动时都要保持检查,以保持眼睛相对于门的位置,并检查何时没有纬度坐标。即它仅在大门上方。
  5. 在只有门的情况下,如果有一堵墙,则向下移动,向左或向右移动,并继续执行此编号1-4,直到眼睛进入窝点为止。
  6. 我从没在吃豆人中见过死胡同,此代码无法解释死胡同。
  7. 另外,我提供了一种解决方案,以解决眼睛何时在我的伪代码中跨越原点的墙之间“摆动”的问题。

一些伪代码:

   x = getRelativeOppositeLatitudinalCoord()
   y
   origX = x
    while(eyesNotInPen())
       x = getRelativeOppositeLatitudinalCoordofGate()
       y = getRelativeOppositeLongitudinalCoordofGate()
       if (getRelativeOppositeLatitudinalCoordofGate() == 0 && move(y) == false/*assume zero is neither left or right of the the gate and false means wall is in the way */)
            while (move(y) == false)
                 move(origX)
                 x = getRelativeOppositeLatitudinalCoordofGate()
        else if (move(x) == false) {
            move(y)
    endWhile

2

dtb23的建议是在每个角上随机选择一个方向,最终您会发现怪异孔的声音非常低效。

但是,您可以利用其效率低下的归位算法,通过在游戏难度中引入更多变化来使游戏更加有趣。您可以通过应用上述方法之一(例如,航路点或洪水填充)来做到这一点,但不能确定地这样做。因此,您可以在每个角落生成一个随机数,以决定采用最佳方式还是随机方向。

随着玩家等级的提高,您会降低采取随机方向的可能性。除了级别速度,幻影速度,吃药暂停(等)之外,这将在总体难度级别上增加另一个杠杆。当幽灵只是无害的眼睛时,您有更多的时间放松,但是随着您的前进,时间会越来越短。


2

简短的回答,不是很好。:)如果您改变吃豆人的迷宫,眼睛不一定会回来。一些随处可见的黑客都遇到了这个问题。因此,这取决于拥有合作迷宫。


2

我建议幽灵存储他从洞到吃豆人的路线。因此,只要幽灵死了,他就可以沿相反的方向跟随这条存储的路径。


2
那条路很可能会太长
Ahmad Y. Saleh

每当您重新访问节点时,都可以从历史记录中消除循环。这将使其更加直接。可能比始终遵循相同的直接路径更有趣,但是通常它会包含一些相当愚蠢的几乎是环形的(例如,正方形的3个边)。
AjahnCharles

1

知道pacman路径是非随机的(即,每个特定级别0-255,漆黑,闪烁,小指和克莱德都将为该级别使用完全相同的路径)。

我会考虑这一点,然后猜测有一些主路径将整个迷宫包裹起来,作为“返回路径”,当pac人吃掉鬼魂时,眼球对象将挂起该路径。


1

吃豆人中的幽灵遵循或多或少可预测的模式,试图首先匹配X或Y,直到达到目标为止。我一直认为,对于返回的眼睛来说,这是完全相同的。


1
  1. 游戏开始之前,将节点(交叉点)保存在地图上
  2. 当怪物死亡时,取点(坐标)并在节点列表中找到最近的节点
  3. 计算从该节点到孔的所有路径
  4. 按长度走最短路径
  5. 添加点和最近节点之间的空间长度
  6. 在路径上绘制并移动

请享用!


1

我的方法需要占用大量内存(从吃豆子时代的角度来看),但是您只需要计算一次即可,并且适用于任何关卡设计(包括跳转)。

一次标记节点

首次加载关卡时,将所有怪物巢穴节点标记为0(代表到巢穴的距离)。继续向外标记连接的节点1,连接到节点2的节点,依此类推,直到标记所有节点。(注意:如果巢穴有多个入口,这甚至可以工作)

我假设您已经具有代表每个节点及其邻居的连接的对象。伪代码可能看起来像这样:

public void fillMap(List<Node> nodes) { // call passing lairNodes
    int i = 0;

    while(nodes.count > 0) {
        // Label with distance from lair
        nodes.labelAll(i++);

        // Find connected unlabelled nodes
        nodes = nodes
            .flatMap(n -> n.neighbours)
            .filter(!n.isDistanceAssigned());
    }
}

从巢穴充水

眼睛移动到具有最小距离标签的邻居

一旦所有节点都被标记,路由眼睛就变得微不足道了……只需选择具有最低距离标签的相邻节点即可(注意:如果多个节点的距离相等,则选择哪个节点都没有关系)。伪代码:

public Node moveEyes(final Node current) {
    return current.neighbours.min((n1, n2) -> n1.distance - n2.distance);
}

完全标记的示例

完整地图


0

对于我的PacMan游戏,我制定了一种“ shortest multiple path home”算法,该算法适用于我所提供的迷宫(在我的规则范围内)。它也适用于它们的隧道。

加载关卡时,所有的path home data in every crossroad物体都是空的(默认),并且一旦鬼魂开始探索迷宫,crossroad path home information每次进入“新”十字路口或从另一条道路跌落到已知十字路口时,它们都会不断更新。


-2

最初的吃豆人没有使用寻路或花哨的AI。它只是让游戏玩家相信它比实际深度更深,但实际上它是随机的。正如《游戏人工智能》 /伊恩·米林顿(Ian Millington),约翰·冯格(John Funge)所述。

不知道这是不是真的,但这对我来说很有意义。老实说,我没有看到人们在谈论这些行为。正如他们所说,红色/闪烁的ex一直没有跟随玩家。似乎没有人会故意跟随玩家。在我看来,他们追随您的机会是随机的。而且,很容易看到随机行为,特别是在很小的空间内被四个敌人和非常有限的转身选择时,被追赶的机会非常高。至少在最初的实施中,游戏非常简单。查看本书,它在第一章中。


是的,它确实使用了一些AI。没错的Blinky如下吃豆子时,他在追逐模式(不时地切换到它),所以它的AI没事
让·弗朗索瓦·法布尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.