基于六边形地图的A*寻路算法实现

和四边形地图的A*规则相同,主要是H值的计算,简化为等边三角形和平行四边形

1.  起始点放入open列表

    // A*算法计算最短路径
    // G是从开始点到达当前方块的移动量
    // H值是从当前方块到终点的移动量估算值
    // 重复以下步骤来找到最短路径:
    // 将方块添加到open列表中,该列表有最小的和值F(F=G+H)。且将这个方块称为S吧。
    // 将S从open列表移除,然后添加S到closed列表中。
    // 对于与S相邻的每一块可通行的方块T:
    // 如果T在closed列表中:不管它。
    // 如果T不在open列表中:添加它然后计算出它的和值。
    // 如果T已经在open列表中:当我们使用当前生成的路径到达那里时,检查F 和值是否更小。如果是,更新它的和值和它的前继。
    // http://www.cnblogs.com/zhoug2020/p/3468167.html
    getAStarShortestPath: function() {
        this._AStarOpenSize = 0;
        this._AStarOpenList = {};
        this._AStarCloseList = {};
        this._AStarPath = [];
        this._boatLineList = [];

        // 0. 起始点放入open列表
        var HValue = this.calculateAStarHValueByPos(this._AStarStartPos);
        this._AStarOpenList[this.X_LARGE*this._AStarStartPos.x + this._AStarStartPos.y] = {x:this._AStarStartPos.x, y:this._AStarStartPos.y, ex:this.B_LARGE, G:0, H:HValue, F:HValue, i:this._AStarOpenSize};
        var astarResult = this.circleUpdateTheCloseList();

        if (astarResult) {
            for (var tagid in this._AStarCloseList) {
                cc.log("the close list :"+JSON.stringify(this._AStarCloseList[tagid]));
            } 
            // 从Close列表中通过终点逆推找出最短路径并排序
            this._AStarPath.unshift(this._AStarEndPos);
            var temp = this;
            var sortShorestPath = null;
            sortShorestPath = function() {
                var ex = temp._AStarCloseList[temp.X_LARGE*temp._AStarPath[0].x + temp._AStarPath[0].y].ex;
                if (ex == temp.B_LARGE) {
                    return;
                }
                temp._AStarPath.unshift({x:temp._AStarCloseList[ex].x, y:temp._AStarCloseList[ex].y});
                sortShorestPath();
            };
            sortShorestPath();
        }
    },

2. 递归open列表取出最小F值放入close列表并取其临近坐标

    // 递归计算最小和值更新open和close列表,直到终点在close列表中
    circleUpdateTheCloseList: function() {
        // 1. 对open列表中取最小和值F的坐标S进行操作
        var minF = 100000000;
        var minFPosTag = -1;
        for (var tagid in this._AStarOpenList) {
            // 最简单(快速)的方法是一直跟着最近被添加到open列表中的方块
            if (this._AStarOpenList[tagid].F - 0.0001*this._AStarOpenList[tagid].i < minF) {
                minF = this._AStarOpenList[tagid].F - 0.0001*this._AStarOpenList[tagid].i;
                minFPosTag = tagid;
            }
        }
        if (minFPosTag != -1) {
            var minFPosData = this._AStarOpenList[minFPosTag];
            delete this._AStarOpenList[minFPosTag];
            this._AStarCloseList[minFPosTag] = minFPosData;
            // final. 如果是终点,结束判断
            if (minFPosData.x == this._AStarEndPos.x && minFPosData.y == this._AStarEndPos.y) {
                cc.log("find the final pos");
                return 1;
            }
            cc.log("find the minF pos ("+minFPosData.x+","+minFPosData.y+")");
            // 2. 对S相邻点T进行操作,更新F,G,H的值(F=G+H)和father(ex)和插入顺序(i)
            var exPos = minFPosData;
            var nearList = this.getNeighborListByPos(exPos);
            for (var i = 0; i < nearList.length; i++) {
                var pos = nearList[i];
                if (this._AStarCloseList[this.X_LARGE*pos.x + pos.y]) {
                    // ignore
                } else {
                    var GValue = exPos.G + 1;
                    var openExist = this._AStarOpenList[this.X_LARGE*pos.x + pos.y];
                    if (openExist == null) this._AStarOpenSize += 1;
                    if ((openExist && openExist.G > GValue) || openExist == null) {
                        var HValue = this.calculateAStarHValueByPos(pos);
                        this._AStarOpenList[this.X_LARGE*pos.x + pos.y] = {x:pos.x, y:pos.y, ex:this.X_LARGE*exPos.x+exPos.y, G:GValue, H:HValue, F:HValue+GValue, i:this._AStarOpenSize};
                        cc.log((openExist ? "update" : "add")+" the open pos "+JSON.stringify(this._AStarOpenList[this.X_LARGE*pos.x + pos.y]));
                    }
                }
            }
            return this.circleUpdateTheCloseList();
        } else {
            cc.log("not found cloest A* path");
            return 0;
        }
    },

3.  六边形计算H值,通过简化等边三角形和平行四边形计算曼哈顿距离

    // 计算坐标点距离目标点的移动量估算值H
    calculateAStarHValueByPos: function(pos) {
        var x = pos.x;
        var y = pos.y;
        var endx = this._AStarEndPos.x;
        var endy = this._AStarEndPos.y;
        var gapx = Math.abs(endx-x);
        if (gapx%2 == 0) {
            // 距离坐标点对应等边三角形的边上任意点距离相同,为y轴增量,剩下的距离为平行四边形计算
            if (endy >= y-gapx/2 && endy <= y+gapx/2) {
                return gapx;
            } else if (endy < y-gapx/2) {
                return gapx + Math.abs(endy-y+gapx/2);
            } else if (endy > y+gapx/2) {
                return gapx + Math.abs(endy-y-gapx/2);
            }
        } else {
            // 寻找坐标点对应等边三角形,三角形另外两个坐标点x根据所在列进行计算,剩下的距离为平行四边形计算
            if (Math.abs(x)%2 == 0) {
                if (endy >= y-gapx/2+0.5 && endy <= y+gapx/2+0.5) {
                    return gapx;
                } else if (endy < y-gapx/2+0.5) {
                    return gapx + Math.abs(endy-y+gapx/2-0.5);
                } else if (endy > y+gapx/2+0.5) {
                    return gapx + Math.abs(endy-y-gapx/2-0.5);
                }
            } else {
                if (endy >= y-gapx/2-0.5 && endy <= y+gapx/2-0.5) {
                    return gapx;
                } else if (endy < y-gapx/2-0.5) {
                    return gapx + Math.abs(endy-y+gapx/2+0.5);
                } else if (endy > y+gapx/2-0.5) {
                    return gapx + Math.abs(endy-y-gapx/2+0.5);
                }
            }
        }
        cc.log("A* H value calculate error");
    },

4.  相邻坐标的计算根据坐标命名规则进行计算



你可能感兴趣的:(算法)