在学习本篇教程之前,如果你有cocos2d-x的开发经验,将会有所帮助。如果没有也没关系,因为你可以将这里讲解的例子迁移到其他的语言或者框架中。
找到到达你键盘的最短路径,开始吧!
Maze猫
首先介绍下我们将要在本篇教程中开发的简单游戏。
前往下载本篇教程的 工程代码 。编译运行工程,你将看到以下画面。
在这款游戏中,你扮演着一只小偷猫,在一个由危险的狗守护着的地牢里小心穿行。如果你试图穿过一只狗,他会把你吃掉 – 除非你可以用骨头去贿赂它!
所以在这款游戏中,你的任务是尝试以正确的顺序捡起骨头,然后 寻找路线 穿过狗逃离。
注意到猫只能水平或者垂直的移动(例如不能斜线移动),并且会从一个方块的中心点移动到另一个中心点。每个方块既可以是可通行的也可以是不可通行的。
尝试下这款游戏,看看你能否找到出路!建议你阅读代码以熟悉它的原理。这是一款相当普通的方块-地图式游戏,我们会在接下来的教程中修改它并使用上A星寻路算法。
Maze猫和A星概览
正如你所看到的,当你点击地图某处时,猫会沿着你点击的方向跳到相邻的方块上。
我们想对程序做修改,让猫持续的往你点击的方块方向前进,就像许多RPGs或者point-and-click冒险类游戏。
让我们看下控制触摸事件代码的工作原理。如果你打开HelloWorldScene.cpp文件,你将看到像下面这样去实现触摸操作:
你可以看到这里只是对猫精灵调用了一个方法,让猫在方块地图上往你点击的地方移动。
我们现在要做的是修改在CatSprite.m文件中的以下方法,寻找到达该点的最短路径,并且开始前进:
创建ShortestPathStep类
我们开始创建一个内部类,代表路径上的一步操作。在这种情况下,它是一个方块和由A星算法计算出来的的F,G和H scores。
现在添加以下代码到CatSprite.cpp文件的顶部。
正如所见,这是一个很简单的类,记录了以下内容:
- 方块的坐标
- G值(记住,这是开始点到当前点的方块数量)
- H值(记住,这是当前点到目标点的方块估算数量)
- Parent是它的上一步操作
- F值,这是方块的和值(它是G+H的值)
这里定义了getDescription方法,以方便调试。创建了isEquals方法,当且仅当两个ShortestPathSteps的方块坐标相同时,它们相等(例如它们代表着相同的方块)。
创建Open和Closed列表
打开CatSprite.h文件,添加如下代码:
检查开始和结束点
重新实现moveToward方法,获取当前方块坐标和目标方块坐标,然后检查是否需要计算一条路径,最后测试目标方块坐标是否可行走的(在这里只有墙壁是不可行走的)。打开CatSprite.cpp文件,修改moveToward方法,为如下:
编译运行,在地图上进行点击,如果不是点击到墙壁的话,可以在控制台看到如下信息:
其中 **From** 就是猫的方块坐标,**To**就是所点击的方块坐标。
实现A星算法
根据算法,第一步是添加当前坐标到open列表。还需要三个辅助方法:
- 一个方法用来插入一个ShortestPathStep对象到适当的位置(有序的F值)
- 一个方法用来计算从一个方块到相邻方块的移动数值
- 一个方法是根据"曼哈顿距离"算法,计算方块的H值
打开CatSprite.cpp文件,添加如下方法:
接下来,需要一个方法去获取给定方块的所有相邻可行走方块。因为在这个游戏中,HelloWorld管理着地图,所以在那里添加方法。打开HelloWorldScene.cpp文件,添加如下方法:
可以继续CatSprite.cpp中的moveToward方法了,在moveToward方法的后面,添加如下代码:
添加以下方法:
编译运行,在地图上进行点击,如下图所示:
注意该路径是从后面建立的,所以必须从下往上看猫选择了哪条路径。
跟随路径前进
现在已经找到了路径,只需让猫跟随前进即可。需要创建一个数组去存储路径,打开CatSprite.h文件,添加如下代码:
打开CatSprite.cpp文件,更改moveToward方法,注释掉语句**bool pathFound = false**;,如下:
替换语句**pathFound = true;**为如下:
并且注释掉下方的调试语句:
替换语句**if (!pathFound)**为如下:
现在创建一个方法,用来存储整个路径,并且负责动画的播放。添加方法如下:
编译运行,点击,就可以在控制台看到如下信息:
这些信息跟之前的很类似,除了它是从开始到结束,而不是相反的,并且步骤都被很好的存储在数组中以供使用。最后要做的是遍历shortestPath数组,让猫沿着路径动画前进。为了实现这一点,创建一个方法,从数组中获取步骤,让猫移动到那个位置,然后添加一个回调函数去重复调用这个方法直到路径完成。添加方法如下:
在constructPathAndStartAnimationFromStep方法里的最下面添加如下代码:
编译运行,点击地面,可以看到猫自动移动到所点击的位置了。如下图所示:
然而,会发现到以下问题:
- 猫看起来有点僵硬
- 猫没有带走骨头
- 猫可以穿过狗(没有带着骨头),而不被吃掉
- 当在猫走完路径之前,点击了一个新的路径的话,猫会有奇怪的行为
因此,为了解决猫的僵硬行为,还有游戏逻辑(胜利/失败,狗,骨头,等等......),必须加上之前实现的旧游戏逻辑。
重新添加游戏逻辑
为了修复这些问题,替换popStepAndAnimate方法为如下:
这里只是对原来的代码进行重构。接着在moveToward方法里面的最上面添加如下代码:
编译运行,可以看到一切正常了,如下图所示:
如何实现对角线移动
在A星算法中实现对角线移动十分简单,只需要更改以下两个方法:
- walkableAdjacentTilesCoordForTileCoord:更改以便包括对角线方块
- costToMoveFromStepToAdjacentStep:更改以让对角线移动跟水平/垂直移动有不一样的成本
如何计算出在对角线方向上的成本值?使用简单的数学即可。猫从一个方块的中心移动到另一个方块的中心,并且因为方块是正方形,A、B和C形成了一个三角形,如下图所示:
所以对角线的移动成本等于1.41,这低于向左移动再向上移动的成本值2(1+1)。正如所知的,使用整型计算远比浮点型更高效,所以不是使用浮点型来标示对角线移动的成本值,而是简单地对成本值乘以10,然后四舍五入,所以水平/垂直移动的成本值为10,而对角线移动的成本值为14。更改costToMoveFromStepToAdjacentStep方法为如下:
更改walkableAdjacentTilesCoordForTileCoord方法为如下:
重要提示:添加对角线方块的代码和添加水平/垂直方块的代码有些不同。事实上,例如,只有当顶部和左侧的方块被添加时,左上对角线才能够被添加。这是为了防止猫穿过墙壁的角落。以下是所有的详细情况处理:
- O = Origin
- T = Top
- B = Bottom
- L = Left
- R = Right
- TL = Top – Left
- …
就拿上面图像的左上部分来进行举例。猫想要从原始点(O)到左下对角线方块(BL)。如果在左侧或者底部(或者都有)有一面墙,然后尝试走对角线,算法将会封掉墙壁的角落(或者两面墙壁的角落)。所以只有当左侧和底部没有墙壁时,左下对角线方块才可行走。如下图所示:
完整源码请下载 CatMazeStarter 。
引用:
本文改编自iOS Tutorial Team的成员 Johann Fradj 的文章 如何使用coocs2d-x 3.x中实现A*寻路算法 。以及博主 无幻 的部分资源。
找到到达你键盘的最短路径,开始吧!
Maze猫
首先介绍下我们将要在本篇教程中开发的简单游戏。
前往下载本篇教程的 工程代码 。编译运行工程,你将看到以下画面。

在这款游戏中,你扮演着一只小偷猫,在一个由危险的狗守护着的地牢里小心穿行。如果你试图穿过一只狗,他会把你吃掉 – 除非你可以用骨头去贿赂它!
所以在这款游戏中,你的任务是尝试以正确的顺序捡起骨头,然后 寻找路线 穿过狗逃离。
注意到猫只能水平或者垂直的移动(例如不能斜线移动),并且会从一个方块的中心点移动到另一个中心点。每个方块既可以是可通行的也可以是不可通行的。
尝试下这款游戏,看看你能否找到出路!建议你阅读代码以熟悉它的原理。这是一款相当普通的方块-地图式游戏,我们会在接下来的教程中修改它并使用上A星寻路算法。
Maze猫和A星概览
正如你所看到的,当你点击地图某处时,猫会沿着你点击的方向跳到相邻的方块上。
我们想对程序做修改,让猫持续的往你点击的方块方向前进,就像许多RPGs或者point-and-click冒险类游戏。
让我们看下控制触摸事件代码的工作原理。如果你打开HelloWorldScene.cpp文件,你将看到像下面这样去实现触摸操作:
复制代码
|
你可以看到这里只是对猫精灵调用了一个方法,让猫在方块地图上往你点击的地方移动。
我们现在要做的是修改在CatSprite.m文件中的以下方法,寻找到达该点的最短路径,并且开始前进:
复制代码
|
创建ShortestPathStep类
我们开始创建一个内部类,代表路径上的一步操作。在这种情况下,它是一个方块和由A星算法计算出来的的F,G和H scores。
复制代码
|
现在添加以下代码到CatSprite.cpp文件的顶部。
复制代码
|
正如所见,这是一个很简单的类,记录了以下内容:
- 方块的坐标
- G值(记住,这是开始点到当前点的方块数量)
- H值(记住,这是当前点到目标点的方块估算数量)
- Parent是它的上一步操作
- F值,这是方块的和值(它是G+H的值)
这里定义了getDescription方法,以方便调试。创建了isEquals方法,当且仅当两个ShortestPathSteps的方块坐标相同时,它们相等(例如它们代表着相同的方块)。
创建Open和Closed列表
打开CatSprite.h文件,添加如下代码:
复制代码
|
检查开始和结束点
重新实现moveToward方法,获取当前方块坐标和目标方块坐标,然后检查是否需要计算一条路径,最后测试目标方块坐标是否可行走的(在这里只有墙壁是不可行走的)。打开CatSprite.cpp文件,修改moveToward方法,为如下:
复制代码
|
编译运行,在地图上进行点击,如果不是点击到墙壁的话,可以在控制台看到如下信息:
复制代码
|
其中 **From** 就是猫的方块坐标,**To**就是所点击的方块坐标。
实现A星算法
根据算法,第一步是添加当前坐标到open列表。还需要三个辅助方法:
- 一个方法用来插入一个ShortestPathStep对象到适当的位置(有序的F值)
- 一个方法用来计算从一个方块到相邻方块的移动数值
- 一个方法是根据"曼哈顿距离"算法,计算方块的H值
打开CatSprite.cpp文件,添加如下方法:
复制代码
|
接下来,需要一个方法去获取给定方块的所有相邻可行走方块。因为在这个游戏中,HelloWorld管理着地图,所以在那里添加方法。打开HelloWorldScene.cpp文件,添加如下方法:
复制代码
|
可以继续CatSprite.cpp中的moveToward方法了,在moveToward方法的后面,添加如下代码:
复制代码
|
添加以下方法:
复制代码
|
编译运行,在地图上进行点击,如下图所示:

复制代码
|
注意该路径是从后面建立的,所以必须从下往上看猫选择了哪条路径。
跟随路径前进
现在已经找到了路径,只需让猫跟随前进即可。需要创建一个数组去存储路径,打开CatSprite.h文件,添加如下代码:
复制代码
|
打开CatSprite.cpp文件,更改moveToward方法,注释掉语句**bool pathFound = false**;,如下:
复制代码
|
替换语句**pathFound = true;**为如下:
复制代码
|
并且注释掉下方的调试语句:
复制代码
|
替换语句**if (!pathFound)**为如下:
复制代码
|
现在创建一个方法,用来存储整个路径,并且负责动画的播放。添加方法如下:
复制代码
|
编译运行,点击,就可以在控制台看到如下信息:
复制代码
|
这些信息跟之前的很类似,除了它是从开始到结束,而不是相反的,并且步骤都被很好的存储在数组中以供使用。最后要做的是遍历shortestPath数组,让猫沿着路径动画前进。为了实现这一点,创建一个方法,从数组中获取步骤,让猫移动到那个位置,然后添加一个回调函数去重复调用这个方法直到路径完成。添加方法如下:
复制代码
|
在constructPathAndStartAnimationFromStep方法里的最下面添加如下代码:
复制代码
|
编译运行,点击地面,可以看到猫自动移动到所点击的位置了。如下图所示:

然而,会发现到以下问题:
- 猫看起来有点僵硬
- 猫没有带走骨头
- 猫可以穿过狗(没有带着骨头),而不被吃掉
- 当在猫走完路径之前,点击了一个新的路径的话,猫会有奇怪的行为
因此,为了解决猫的僵硬行为,还有游戏逻辑(胜利/失败,狗,骨头,等等......),必须加上之前实现的旧游戏逻辑。
重新添加游戏逻辑
为了修复这些问题,替换popStepAndAnimate方法为如下:
复制代码
|
这里只是对原来的代码进行重构。接着在moveToward方法里面的最上面添加如下代码:
复制代码
|
编译运行,可以看到一切正常了,如下图所示:

如何实现对角线移动
在A星算法中实现对角线移动十分简单,只需要更改以下两个方法:
- walkableAdjacentTilesCoordForTileCoord:更改以便包括对角线方块
- costToMoveFromStepToAdjacentStep:更改以让对角线移动跟水平/垂直移动有不一样的成本
如何计算出在对角线方向上的成本值?使用简单的数学即可。猫从一个方块的中心移动到另一个方块的中心,并且因为方块是正方形,A、B和C形成了一个三角形,如下图所示:


所以对角线的移动成本等于1.41,这低于向左移动再向上移动的成本值2(1+1)。正如所知的,使用整型计算远比浮点型更高效,所以不是使用浮点型来标示对角线移动的成本值,而是简单地对成本值乘以10,然后四舍五入,所以水平/垂直移动的成本值为10,而对角线移动的成本值为14。更改costToMoveFromStepToAdjacentStep方法为如下:
复制代码
|
更改walkableAdjacentTilesCoordForTileCoord方法为如下:
复制代码
|
重要提示:添加对角线方块的代码和添加水平/垂直方块的代码有些不同。事实上,例如,只有当顶部和左侧的方块被添加时,左上对角线才能够被添加。这是为了防止猫穿过墙壁的角落。以下是所有的详细情况处理:
- O = Origin
- T = Top
- B = Bottom
- L = Left
- R = Right
- TL = Top – Left
- …

就拿上面图像的左上部分来进行举例。猫想要从原始点(O)到左下对角线方块(BL)。如果在左侧或者底部(或者都有)有一面墙,然后尝试走对角线,算法将会封掉墙壁的角落(或者两面墙壁的角落)。所以只有当左侧和底部没有墙壁时,左下对角线方块才可行走。如下图所示:

完整源码请下载 CatMazeStarter 。
引用:
本文改编自iOS Tutorial Team的成员 Johann Fradj 的文章 如何使用coocs2d-x 3.x中实现A*寻路算法 。以及博主 无幻 的部分资源。
[ 此帖被ivenyang在2014-04-30 11:46重新编辑 ]
http://www.cocoachina.com/bbs/read.php?tid=199994