关于A*算法的一些研究

最近工作比较清闲,心中残存的一些旧账又被我翻出来算了一遍,发现自己对算法的理解和参悟都不是很透彻,可能以前没那么多时间研究,都是随手拿过来改改就用了,出于对学习严谨的态度,我决定回过头来重新剖析一下算法中的几个疑惑,如果你有幸看到并且给你带来一些想法上的帮助,荣幸之至,如有纰漏,也请指正,不胜感激,废话到此为止。

公式:F = G + H 代价计算,寻路代价最小的就是我们要找的

G 表示从起点 A 移动到网格上指定方格的移动耗费 (可沿斜方向移动).
H 表示从指定的方格移动到终点 B 的预计耗费 (H 有很多计算方法, 这里我们设定只可以上下左右移动)

下面拿个例子说明一下

原文参考 http://www.cnblogs.com/technology/archive/2011/05/26/2058842.html

假如从A寻路到B
1

寻路步骤
1. 从起点A开始, 把它作为待处理的方格存入一个”开启列表”(openlist), 开启列表就是一个等待检查方格的列表.
这里写图片描述
2. 寻找起点A周围可以到达的方格, 将它们放入”开启列表”, 并设置它们的”父方格“为A.
3. 从”开启列表”中删除起点 A, 并将起点 A 加入”关闭列表”, “关闭列表”(closelist)中存放的都是不需要再次检查的方格
这里写图片描述

接下来我们就可以构建一个循环 去寻找消耗最小的点了 , A为起点我们发现C的代价是最小的 F = G+H = 40 ,第二轮循环开始前我们需要从开启列表中(F由低到高排序)openlist.shift()出一个作为当前结点, 为了构建循环,我们在第一轮结束的时候从开启列表中拿出第一个node作为当前结点 ,这样的循环就可以写成下面这样

伪代码:

curNode = startNode;
while(curNode!= endNode)
{
//1,寻找周围8个格子,更新F,G, H 和parent 并放入openlist
//2.将curNode 放入 关闭列表closelist
//3.对openlist进行排序,找出下一个节点curNode = openlist.shift();
}
//找到最有一个节点后,构建路径

        _path = new Array();
        var node : Node = endNode;
        _path.push(node);
        while(node != startNode) {
            node = node.parent;
            _path.unshift(node);
        }

这里一定要明确一点:我们构建的路径是从node.parent构建的链表中获得的,而不是closelist中的
你会发现,node.parent链表构建的路径要不closelist代价更小,也就是我们找的最优路径。

这里写图片描述

当curNode从绿色的格子移动到C时,接下来要检测C周围的8个格子了,右边三个蓝色的是障碍物,在上面的while循环中的第一步里,要进行条件过滤
1.障碍物不加入openlist(右边蓝色格子)
2.在closelist的不需要检测的也不需要加入openlist(左边绿色的格子)
对之前在开启列表的格子 要重新计算G值 ,H值是不变的,所以为了比较F=G+H,算一下G值就好了
注意: D之前的G = 14,如果从C点过来计算出来的G0 = (C点的G = 10) + 10 = 20; G0>G ,代价明显要付出的更多了,所以对于D点的parent我们不能更新为C,还是绿色的格子A,这样下一个最优点就是D了,这里要理解好

下面我列出寻路的代码 和最终效果

“`
public function search() : Boolean {
var node : Node = _startNode;
while(node != _endNode) {
//避免越界
var startX : int = Math.max(0, node.x - 1);
var endX : int = Math.min(_grid.numRows - 1, node.x + 1);
var startY : int = Math.max(0, node.y - 1);
var endY : int = Math.min(_grid.numCols - 1, node.y + 1);
//8个方向 还有自己 一共9个点
for(var i : int = startX;i <= endX;i++) {
for(var j : int = startY;j <= endY;j++) {
var test : Node = _grid.getNode(i, j);
var clearance : int = clearance(test);
if(test == node //节点不用管
|| !test.walkable //不能走
//不能走斜线的意思
|| !_grid.getNode(node.x, test.y).walkable //节点上下不能走
|| !_grid.getNode(test.x, node.y).walkable//节点左右不能走
) {
continue;
}

                    var cost : Number = _straightCost;
                    if(!((node.x == test.x) || (node.y == test.y))) {//斜角的
                        cost = _diagCost;
                    }
                    var g : Number = node.g + cost * test.costMultiplier;
                    var h : Number = _heuristic(test);
                    var f : Number = g + h;
                    if(isOpen(test) || isClosed(test)) {
                        if(test.f > f) {//如果被检查的节点已经在开启列表了,
                            test.f = f;
                            test.g = g;
                            test.h = h;
                            test.parent = node;
                        }//如果新的值还没有原来的小,我们就什么也不做,parent还是之前那个,肯定是最小的f,这里是关键,也是不好理解的地方,
                    } else if(clearance >_square-1){//物体尺寸过滤
                        test.f = f;
                        test.g = g;
                        test.h = h;
                        test.parent = node;
                        _open.push(test);
                    } else{
                        continue;
                    }
                }
            }
            _closed.push(node);
            if(_open.length == 0) {
                trace("no path found");
                return false;
            }
            _open.sortOn("f", Array.NUMERIC);
            node = _open.shift() as Node;
        }
        buildPath();
        return true;
    }

“`效果一:
这里写图片描述

效果2

这里写图片描述

源码请联系作者

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值