A*寻路算法是一个求两点之间的最短路径的方法

算法详情如下:

准备工作:

两个容器:   open容器和close容器

价值估算公式:    F = G + H

G:从起点移动到指定方格的移动代价;

(在实际运算时,对于G的计算在算法一开始是比较好理解的,因为你一开始获取的当前点就是起点,直接计算当前点到你相邻点的“距离”,这个距离没有特别的限制,你可以定为1,也可以定为两个点之间的H:实际距离;计算到后面,当前点不在是起点了,要计算G也很简单,直接用当前点的G值加上当前点到相邻点的“距离”即可)

H:从指定的方格移动到终点的估算成本;

(这是一个估算的距离,实际上我们并不能知道实际距离是多少,因为我们并不知道我们在前进的时候会遇到哪些阻碍物,所以可以大概的猜一个值,一般都是用这个点到终点的直线距离来代替;需要注意的是,H值和G值的差异不要太大,虽然都可以得到路径,但是差异大的话可能得到的不是最优解。比如你的G值设相邻点距离为1,H值为两个点的实际距离,这样就可能得到不是最优解的解,最好H也是以1位单位加起来的距离)

算法开始运行:

1.把起点加入open容器中。

2.重复如下过程:

  • 遍历 open 容器 ,查找 F 值最小的节点,把它作为当前要处理的节点。
  • 把这个节点加入 close 容器中。
  • 从 open 容器中移除这个节点。
  • 判断当前点是否是终点,如果是,找出路径;如果不是,执行下一步。
  • 找出当前点的相邻点,对每个相邻点做如下处理:
    • 如果它是不可抵达的或者它在 close 容器中,忽略它。否则,做如下操作。
    • 如果它不在 open 容器中,把它加入 open 容器,并且把当前方格设置为它的父亲,计算并记录该方格的 F ,G 和 H 值。
    • 如果它已经在 open 容器 中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更好,用 G 值作参考。更小的 G 值表示这是更好的路径。如果是这样,把它的父亲设置为当前方格,并重新计算它的 G 和 F 值。如果你的 open 容器是按 F 值排序的话,改变后你可能需要重新排序。
  • 停止,当 open 容器为空时,结束循环。(如果循环结束还没找到路径。说明该终点无法到达)

3.保存路径。从终点开始,每个方格沿着父节点移动直至起点,这就是你的路径。

注意:可能有人会以为 close 容器中的点就是路径,其实两个容器和路径没有关系。我们在算法运行中,会给每个节点设置父节点,这个是我们寻找路径的依据;当找到终点时,我们从终点开始,根据其父节点一步一步寻找,直到找到起点,那么寻找出的这条路径就是我们需要的最短路径。

以下是我在项目中写的一个A*寻路算法的代码(cocos2d-x,容器都是CCDictionary):

void TacticalSecondMatchLayer::startFindWay(int startId, int endId)
{
routeArr->removeAllObjects(); //用来保存路径的
openDic->removeAllObjects();
closeDic->removeAllObjects();
TacticalSecondMapBlock* startBlock = (TacticalSecondMapBlock*)allBlockDic->objectForKey(startId);
if (startBlock)
{
openDic->setObject(startBlock, startId);
}
do
{
int currentTag = findMinFInOpen(); //寻找open容器中F值最小的点
TacticalSecondMapBlock* currentBlock = (TacticalSecondMapBlock*)allBlockDic->objectForKey(currentTag);
closeDic->setObject(currentBlock, currentTag);
openDic->removeObjectForKey(currentTag);
if (currentTag == endId)
{
constructPathFromStep(currentBlock, startId);
clearBlockParent();
CCLOG("find way OK");
break;
}
findAdjoinBlock(currentTag, ); //寻找相邻点
CCDictElement* el = NULL;
CCDICT_FOREACH(adjoinDic, el)
{
CCInteger* adjoinPos = (CCInteger*)el->getObject();
//判断是否存在closeDic中
if (closeDic->objectForKey(adjoinPos->getValue()))
{
continue;
}
//判断是否存在openDic中
if (openDic->objectForKey(adjoinPos->getValue()))
{
TacticalSecondMapBlock* tempBlock = (TacticalSecondMapBlock*)openDic->objectForKey(adjoinPos->getValue());
if (tempBlock)
{
if (currentBlock->getBlockG() + AdjoinDistance < tempBlock->getBlockG())
{
tempBlock->setBlockG(currentBlock->getBlockG() + AdjoinDistance);
tempBlock->setParentTag(currentTag);
}
}
}
else
{
TacticalSecondMapBlock* tempBlock = (TacticalSecondMapBlock*)allBlockDic->objectForKey(adjoinPos->getValue());
if (tempBlock)
{
            //这些判断条件总的来说就是这个点是可以通过的
if ((tempBlock->getBlockType() == Block_PassType && (tempBlock->getBlockVo()->getBlockType() == Event_Type_NULL || tempBlock->getBlockVo()->getBlockType() == Event_Type_StartPoint)) || adjoinPos->getValue() == endId)
{
tempBlock->setParentTag(currentTag);
tempBlock->setBlockG(currentBlock->getBlockG() + AdjoinDistance);
tempBlock->setBlockH(computeHScore(adjoinPos->getValue(), endId));
openDic->setObject(tempBlock, adjoinPos->getValue());
}
}
}
}
} while (openDic->count() > ); if (routeArr->count() <= )
{
CCLOG("no path found");
}
}
int TacticalSecondMatchLayer::findMinFInOpen()
{
int minId = ;
TacticalSecondMapBlock* minBlock = NULL;
CCDictElement* el = NULL;
CCDICT_FOREACH(openDic, el)
{
TacticalSecondMapBlock* _block = (TacticalSecondMapBlock*)el->getObject();
if (minBlock)
{
if (minBlock->getBlockF() > _block->getBlockF())
{
minBlock = _block;
minId = el->getIntKey();
}
}
else
{
minBlock = _block;
minId = el->getIntKey();
}
} return minId;
}
int TacticalSecondMatchLayer::computeHScore(int startId, int endId)
{
return sqrt((posArr[endId].x - posArr[startId].x)*(posArr[endId].x - posArr[startId].x) + (posArr[endId].y - posArr[startId].y) * (posArr[endId].y - posArr[startId].y));
}
//寻找路径
void TacticalSecondMatchLayer::constructPathFromStep(TacticalSecondMapBlock* block, int startId)
{
TacticalSecondMapBlock* tempBlock = block;
if (tempBlock->getBlockType() == Block_PassType && (tempBlock->getBlockVo()->getBlockType() == Event_Type_NULL || tempBlock->getBlockVo()->getBlockType() == Event_Type_StartPoint))
{
routeArr->addObject(tempBlock);
} do {
TacticalSecondMapBlock* _block = (TacticalSecondMapBlock*)allBlockDic->objectForKey(tempBlock->getParentTag());
if (_block)
{
if (tempBlock->getParentTag() == startId)
{
tempBlock = NULL;
}
else
{
routeArr->addObject(_block);
tempBlock = _block;
}
}
else
{
break;
}
} while (tempBlock != NULL);
}

A*寻路算法的个人理解的更多相关文章

  1. A星寻路算法介绍

    你是否在做一款游戏的时候想创造一些怪兽或者游戏主角,让它们移动到特定的位置,避开墙壁和障碍物呢? 如果是的话,请看这篇教程,我们会展示如何使用A星寻路算法来实现它! 在网上已经有很多篇关于A星寻路算法 ...

  2. A*寻路算法

    对于初学者而言,A*寻路已经是个比较复杂的算法了,为了便于理解,本文降低了A*算法的难度,规定只能横竖(四方向)寻路,而无法直接走对角线,使得整个算法更好理解. 简而言之,A*寻路就是计算从起点经过该 ...

  3. js实现A*寻路算法

    这两天在做百度前端技术学院的题目,其中有涉及到寻路相关的,于是就找来相关博客进行阅读. 看了Create Chen写的理解A*寻路算法具体过程之后,我很快就理解A*算法的原理.不得不说作者写的很好,通 ...

  4. 用简单直白的方式讲解A星寻路算法原理

    很多游戏特别是rts,rpg类游戏,都需要用到寻路.寻路算法有深度优先搜索(DFS),广度优先搜索(BFS),A星算法等,而A星算法是一种具备启发性策略的算法,效率是几种算法中最高的,因此也成为游戏中 ...

  5. 关于A*寻路算法的认识

    最近要参加学校的APP比赛,我们组做的是一个3D迷宫的小APP,我负责的是迷宫的生成与寻路. 寻路算法选择的是A*寻路算法,具体参考的是下面的这篇博客. 本文主要是谈谈自己对A*算法的理解,具体细节, ...

  6. A*寻路算法的探寻与改良(二)

    A*寻路算法的探寻与改良(二) by:田宇轩                                                     第二部分:这部分内容主要是使用C语言编程实现A*, ...

  7. A*寻路算法的探寻与改良(一)

    A*寻路算法的探寻与改良(一) by:田宇轩                                                                    第一部分:这里我们主 ...

  8. A*寻路算法lua实现

    前言:并在相当长的时间没有写blog该,我觉得有点"颓废"该,最近认识到各种同行,也刚刚大学毕业,我认为他们是优秀的.认识到与自己的间隙,有点自愧不如.我没有写blog当然,部分原 ...

  9. [笔记]A*寻路算法初探

    写在开始之前 最近突然对各路游戏的寻路算法很感兴趣,于是去学习了下游戏里的AI们是如何寻路的.网上相关内容很多,但同时有些说法也不一,制作自己的A* 算法时也有因不同的说法而困惑.整理多方资料并自己实 ...

随机推荐

  1. 2018-8-10-win10-uwp-获得元素绝对坐标

    title author date CreateTime categories win10 uwp 获得元素绝对坐标 lindexi 2018-08-10 19:16:51 +0800 2018-2- ...

  2. 【BZOJ 1004】 [HNOI2008]Cards

    [题目链接]:http://www.lydsy.com/JudgeOnline/problem.php?id=1004 [题意] 给你sr+sb+sg张牌,(令n=sr+sb+sg),让你把这n张牌染 ...

  3. BZOJ 4236 "JOIOJI"(前缀和+map+pair)

    传送门: [1]:BZOJ [2]:洛谷 •题解 定义数组 a,b,c 分别表示 'J' , 'O' , 'I' 的前缀和: 要想使区间 (L,R] 满足条件当且仅当 a[R]-a[L] = b[R] ...

  4. 2018-2-13-C#-通配符转正则

    title author date CreateTime categories C# 通配符转正则 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17:23:3 ...

  5. vue-learning:31 - component - 组件间通信的6种方法

    vue组件间通信的6种方法 父子组件通信 prop / $emit 嵌套组件 $attrs / $liteners 后代组件通信 provide / inject 组件实例引用 $root / $pa ...

  6. CSS---文本相关属性

    text-transform 检索或设置对象中的文本的大小写. 属性值 none:无转换 capitalize:将每个单词的第一个字母转换成大写 uppercase:将每个单词转换成大写 lowerc ...

  7. dotnet core 隐藏控制台

    如果写一个控制台程序,需要隐藏这个控制台程序,可以使用本文的方法 如果是在 Windows 下运行, 可以使用一些系统提供的方法隐藏控制台.如果是 Linux 下,都是控制台,就不用隐藏了 复制下面的 ...

  8. Kakuro Extension HDU - 3338 (Dinic)

    Kakuro puzzle is played on a grid of "black" and "white" cells. Apart from the t ...

  9. CodeForces 906D (欧拉降幂)

    Power Tower •题意 求$w_{l}^{w_{l+1}^{w_{l+2}^{w_{l+3}^{w_{l+4}^{w_{l+5}^{...^{w_{r}}}}}}}}$ 对m取模的值 •思路 ...

  10. 常用数据库连接池 (DBCP、c3p0、Druid) 配置说明(转)

    1. 引言 1.1 定义 数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出.对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标.数据库 ...