A*寻路

最近做东西可能会用到寻路的功能,就先用Javascript写个A*扔这里吧。

关于A*算法,有兴趣的同学可参考:http://www.policyalmanac.org/games/aStarTutorial.htm 

中文版:http://blog.vckbase.com/panic/archive/2005/03/20/3778.html
不过个人觉得A*算法的性能确实不太高,还有需要优化的地方

OK,这里是JS版的AStar:

            /**
             * A*类
             * @param {Array} range 查寻范围
             * @param {Number} scale 比例
             * @param {Array} blockList 障碍物列表
             * @param {Array} src 起始点
             * @param {Array} des 目标点
             
*/
            function AStar(range,scale,blockList,src,des){
                var srcNode={
                    parent:null,
                    G:0,
                    H:0,
                    coord:src || [10,10]
                };
                var desNode={
                    parent:null,
                    G:0,
                    H:0,
                    coord:des || [90,90]
                };
                
                var closedList=[];
                var openList=[srcNode];
                
                
                
                function init(){
                    range=range || [[0,0],[100,100]];
                    scale=scale || 10;
                }
                
                /**
                 * 检测障碍物
                 * @param {Array} p
                 
*/
                function checkBlock(p){
                    var i=blockList.length;
                    
                    while(i--){
                        if(blockList[i][0]===p[0] && blockList[i][1]===p[1]){
                            return true;
                        }
                    }
                    
                    return false;
                }
                
                /**
                 * 从列表中移除节点
                 * @param {Object} p
                 * @param {Array} list
                 
*/
                function removeFromList(p,list){
                    var i=list.length;
                    while(i--){
                        if(list[i]===p){
                            list.splice(i,1);
                        }
                    }
                }
                
                /**
                 * 从列表中获取节点
                 * @param {Object} p
                 * @param {Object} list
                 
*/
                function getFromList(p,list){
                    var i=list.length;
                    var ret;
                    
                    while(i--){
                        if(list[i].coord[0]===p[0] && list[i].coord[1]===p[1]){
                            ret=list[i];
                            break;
                        }
                    }
                    
                    return ret;
                }
                
                /**
                 * 获取节点的H值
                 * @param {Array} crd1
                 * @param {Array} crd2
                 
*/
                function getH(crd1,crd2){
                    return Math.abs(crd2[0]-crd1[0]) + Math.abs(crd2[1]-crd1[1])*scale;
                }
                
                /**
                 * 获取节点的G值
                 * @param {Array} crd
                 * @param {Object} p
                 
*/
                function getG(crd,p){
                    var crd2=p.coord;
                    return Math.floor(Math.sqrt(Math.pow(crd[0]-crd2[0],2)+Math.pow(crd[1]-crd2[1],2))*scale) + p.G;
                }
                
                /**
                 * 根据指定节点获取其相邻的节点集合
                 * @param {Object} p
                 
*/
                function getNearPoints(p){
                    var i=3;
                    var j;
                    var points=[];
                    var x;
                    var y;
                    var cp;
                    var otp;
                    
                    while(i--){
                        x=p.coord[0] + (1-i);
                        j=3;
                        
                        while(j--){
                            y=p.coord[1] + (1-j);
                            
                            if ((x !== p.coord[0] || y !== p.coord[1])
                            && !checkBlock([x,y])
                            && (x > range[0][0] && x < range[1][0])
                            && (y > range[0][1] && y < range[1][1])
                            && !getFromList([x,y],closedList)
                            ){
                                cp={
                                    parent:null,
                                    coord: [x, y],
                                    G: 0,
                                    H: getH([x, y], desNode.coord)
                                };
                                points.push(cp);
                            }
                        }
                    }
                    return points;
                }
                
                /**
                 * 从open列表中获取当前离目标点最近的节点
                 * @param {Array} openList
                 
*/
                function getCurrentPoint(openList){
                    var ol=openList;
                    var i=ol.length;
                    var minF=openList[0].G + openList[0].H;
                    var F;
                    var ret;
                    
                    while(i--){
                        F=ol[i].G + ol[i].H;
                        if(F <= minF){
                            minF=F;
                            ret=ol[i];
                        }
                    }
                    
                    return ret;
                }
                
                /**
                 * 检查节点的父节点是否需要更新为更短路径
                 * @param {Object} p
                 * @param {Object} crtP
                 
*/
                function checkParent(p,crtP){
                    var crd1=p.coord;
                    var crd2=crtP.coord;
                    var crtD=Math.floor(Math.sqrt(Math.pow(crd1[0]-crd2[0],2)+Math.pow(crd1[1]-crd2[1],2))*scale) + crtP.G;
                    
                    if(crtD < p.G){
                        p.G=crtD;
                        p.parent=crtP;
                    }
                }
                
                /**
                 * 搜寻路径
                 
*/
                function search(){
                    var p;
                    var np;
                    var nearPoints=[];
                    var currentPoint;
                    var i;
                    var ret;
    
                    do {
                        currentPoint=getCurrentPoint(openList);
                        closedList.push(currentPoint);
                        removeFromList(currentPoint,openList);
                        
                        if(getFromList(desNode.coord,closedList)){
                            ret=closedList;
                            break;
                        }
                        
                        nearPoints=getNearPoints(currentPoint);
                        i=nearPoints.length;
                        while(i--){
                            np=nearPoints[i];
                            if(!getFromList(np.coord,openList)){
                                np.parent=currentPoint;
                                np.G=getG(np.coord,currentPoint);
                                openList.push(np);
                            }
                            checkParent(np,currentPoint);
                        }
                        
                    }while (openList.length);
                    
                    return ret;
                }
                
                
                
                var me={
                    
                    /**
                     * 获取找寻到的路径
                     * @param {Array} src
                     * @param {Array} des
                     
*/
                    getPath:function(src,des){
                        var path=[];
                        var list;
                        var node;
                        
                        if (src) {
                            srcNode.coord=src;
                            openList = [srcNode];
                        }
                        des && (desNode.coord=des);
            
                        list=search();
                        
                        if(list){
                            node=closedList[closedList.length-1];
                            path.push(node);
                            
                            do{
                                node=node.parent;
                                path.push(node);
                            }while(node!==srcNode);
                        }
                        
                        return path;
                    }
                };
                
                init();
                
                return me;
            }

完整版示例(其中绿色为范围,黑色为障碍物,蓝色为起始点,红色为目标点,白色为寻找到的路径): 

原文地址:https://www.cnblogs.com/Random/p/2709433.html