为什么我的小规模a*路径脚本跳过一切



我正在编写一个在7x7瓷砖上设置的游戏脚本,玩家总是在中间(图24(。零作为视觉添加,实际上是一个数组,而不是7x7 2D数组。

[00,01,02,03,04,05,06]
[07,08,09,10,11,12,13]
[14,15,16,17,18,19,20]
[21,22,23,24,25,26,27]
[28,29,30,31,32,33,34]
[35,36,37,38,39,40,41]
[42,43,44,45,46,47,48]

游戏是服务器驱动的,因此玩家使用相对坐标。这意味着,如果玩家移动,瓷砖[0]会改变。这是玩家的简短版本将始终从瓷砖24(即中心瓷砖(移动。网格很难编码,但是如果我公开发布它,我将稍微更改代码。没问题。

该功能应采用目的地并找到从图24到该正方形的好路径,但实际上它返回了"未定义"。

如果我输入24我希望游戏输出这样的数组

[18,12,6]

这是代码:

z = 0;
function pathTo(goal){
    var createPath = function (goal){
        var createNode = function(i){
            this.id = i;
            this.g = Infinity;
            this.f = Infinity;
            this.parent = null;
            this.open = null;
        };
        
        this.nodes = Array(49);
        for(i=0;i<this.nodes.length;i++){
            this.nodes[i] = new createNode(i);
        }
        this.start = this.nodes[24];
        this.start.g = 0;
        this.currentNodeId = 24;
        this.goal = this.nodes[goal];
        this.bestPath = null;
    };//end createPath
    var getBestNeighbor = function(nodeId){
        z++
        if(z>50){throw z}debugger;
        console.log(nodeId);
        var getG = function(parentG){
            //here you can check the map for water, sand, and ruins penalties
            /*
                default = 1
                path = .9
                water = 3
            */
            return (parentG + 1);
        };
        var closeNode = function (node){
            node.open = false;
        };//end closeNode
        var getF = function(startId,endId,g){
            if(g>9){
                throw g;
            }
            var startX = startId % 7;
            var startY = (startId - startX) / 7;
            var endX = endId % 7;
            var endY = (endId - endX) / 7;
            var h = Math.sqrt( Math.pow((startX - endX) , 2 ) + Math.pow(( startY - endY ), 2 ) );
            console.log("Start.id:"+startId+"H:"+h+"  Start.id.g:"+g);
            return (h + g);
        };//end getF
        var tracePath = function(tracedNode){
            path.bestPath = [];
            while(tracedNode != path.start){
                path.bestPath.unshift(tracedNode.id);
                tracedNode = tracedNode.parent;
            }
            return path.bestPath;
        };//end tracePath
        var getNeighborNodeId = function(x,y,currentId){return currentId + (y*7) + x;};//end getNeighborNodeId
        if(path.bestPath === null){
            var neighborNode = {};
            var bestNode = {f: Infinity};
            if(nodeId == path.goal.id){//may need to pass path
                return tracePath(path.nodes[nodeId]);
            }else{
                for(x=-1;x<=1;x++){
                    for(y=-1;y<=1;y++){
                        var nnId = getNeighborNodeId(x,y,nodeId);
                        if(nnId==24){debugger}
                            if( ( (x!=0) && (y!=0) ) ||( (nnId>=0) && (nnId<=48))){
                                var neighborNode = path.nodes[nnId];
                                if(neighborNode.open === null){ neighborNode.open = true; }
                                if(neighborNode.open === true ){//don't check closed neighbors
                                    if(typeof neighborNode === "object"){
                                        neighborNode.parent = path.nodes[nodeId]
                                        debugger;
                                        neighborNode.g = getG(neighborNode.parent.g);
                                        neighborNode.f = getF(neighborNode.id , path.goal.id , neighborNode.g);
                                        if( neighborNode.f < bestNode.f){
                                            bestNode = neighborNode;
                                        }//endif
                                    }//endif
                                }//endif Note: if the node isn't null or true, it's false.
                            }
                    }//endfor
                }//endfor - Note: Here we should have the best neighbor
                if(bestNode.f == Infinity){
                    closeNode(path.nodes[nodeId]);//need escape for no possible path
                    return;
                }else{
                    //bestNode.parent = path.nodes[nodeId];
                    path.currentNodeId = bestNode.id;
                    getBestNeighbor(bestNode.id);
                }//endelse
            }//endelse
        }//endif
    };//end getBestNeighbor
    var path = new createPath(goal);
    while(path.bestPath === null){
        getBestNeighbor(path.currentNodeId);
    }//end while
    return path.bestPath;
}//end pathTo
console.log(pathTo(41));  //testing with 6

和jsfiddle链接:https://jsfiddle.net/jb4xtf3h/

这是我第一次到处都拍打全球,所以它可能有一个我不熟悉的范围问题。

我的问题很可能是在GetNeighborid功能中;我认为我没有任何声明一个好节点的父母。

问题在于它在三次而不是NE上进行三次。这可能意味着我在getBestneighbor函数中有一个错误

我也认为我无法正确逃脱递归功能。

出于某种原因,当我投入41时,它真的很困惑。这要么与我设置的G和H相关,后者在A*中经常使用以记录在此路径上行进的距离和剩余的估计距离。特别是g数是错误的,因为由于某种原因,它正在采取不好的步骤。

这是工作代码。我没有实施墙壁或其他任何东西,但我确实显示了您在哪里做。您需要做的就是关闭所有在开始路径之前墙壁的节点,如果您希望AI知道"知道",则可以分配运动处罚。避免水或沙子。

我实际上不能固定一个问题,但是一个主要问题是说明的方式:

if( ( (x!=0) && (y!=0) ) ||( (nnId>=0) && (nnId<=48))){

已更改为:

if( ( !(x==0 && y==0) && ( nnId>=0 && nnId<=48))){

这一行的目的是防止搜索您站在x,y =(0,0(上的瓷砖,并确保要查看的邻居在网格上(7x7 Grid具有49个正方形编号0-48(

我想说的是"如果x&amp;y都不为零。显然,这实际上与一个或语句相同,因此,如果两个正方形是0,则它跳过了它,并且需要空间有问题,因为有多个指示无法正常工作。

我希望如果某人需要一个不错的简单路径脚本,我真的很努力地使代码可读,而我不是世界上最强大的编码器,而是一个在100行中使用的脚本*,我认为这是公平的。容易遵循。如果您正在阅读本文,并且您不熟悉*路径,那么您可能需要知道的是

h是您的启发式价值,这是对剩余距离形成瓷砖的估计。在此代码中,它在路径对象path.nodes[array#].h

g是您到目前为止移动到该方形path.nodes[array#].g的距离。

f只是为总值添加了H G。Wikipedia上的伪代码帮助我写了它。

var z =  0;
    function pathTo(goal){
        var createPath = function (goal){
            var createNode = function(i){
                this.id = i;
                this.g = Infinity;
                this.f = Infinity;
                this.parent = null;
                this.open = null;
            };
            
            this.nodes = Array(49);
            for(i=0;i<this.nodes.length;i++){
                this.nodes[i] = new createNode(i);
            }
            this.start = this.nodes[24];
            this.start.g = 0;
            this.currentNodeId = 24;
            this.goal = this.nodes[goal];
            this.bestPath = null;
        };//end createPath
        var path = new createPath(goal);
        var getBestNeighbor = function(nodeId){
            var getG = function(parentG){
                //here you can check the map for water, sand, and ruins penalties
                /*
                    default = 1
                    path = .9
                    water = 3
                */
                return (parentG + 1);
            };
            var closeNode = function (node){
                node.open = false;
            };//end closeNode
            var getF = function(startId,endId,g){
                var startX = startId % 7;
                var startY = (startId - startX) / 7;
                var endX = endId % 7;
                var endY = (endId - endX) / 7;
                var h = Math.sqrt( Math.pow((startX - endX) , 2 ) + Math.pow(( startY - endY ), 2 ) );
                return (h + g);
            };//end getF
            var tracePath = function(tracedNode){
                path.bestPath = [];
                while(tracedNode != path.start){
                    path.bestPath.unshift(tracedNode.id);
                    tracedNode = tracedNode.parent;
                }
                return path.bestPath;
            };//end tracePath
            var getNeighborNodeId = function(x,y,currentId){return currentId + (y*7) + x;};//end getNeighborNodeId
            debugger;
            z++
            if(z>50){throw z}
            if(path.bestPath === null){
                var neighborNode = {};
                var bestNode = {f: Infinity};
                if(nodeId == path.goal.id){//may need to pass path
                    return tracePath(path.nodes[nodeId]);
                }else{
                    for(y=-1;y<=1;y++){
                        for(x=-1;x<=1;x++){
                            var nnId = getNeighborNodeId(x,y,nodeId); 
                                if( ( !(x==0 && y==0) && ( nnId>=0 && nnId<=48))){
                                    var neighborNode = path.nodes[nnId];
                                    if(path.nodes[nodeId].parent!=neighborNode){
                                        if(neighborNode.open === null){ neighborNode.open = true; }
                                        if(neighborNode.open === true ){//don't check closed neighbors
                                            if(typeof neighborNode === "object"){
                                                neighborNode.parent = path.nodes[nodeId]
                                                neighborNode.g = getG(neighborNode.parent.g);
                                                neighborNode.f = getF(neighborNode.id , path.goal.id , neighborNode.g);
                                                if( neighborNode.f < bestNode.f){
                                                    bestNode = neighborNode;
                                                }//endif
                                            }//endif
                                        }
                                    }//endif Note: if the node isn't null or true, it's false.
                                }
                        }//endfor
                    }//endfor - Note: Here we should have the best neighbor
                    if(bestNode.f >= 50){
                        closeNode(path.nodes[nodeId]);//need escape for no possible path
                        return;
                    }else{
                        path.currentNodeId = bestNode.id;
                        getBestNeighbor(bestNode.id);
                    }//endelse
                }//endelse
            }//endif
        };//end getBestNeighbor
        while(path.bestPath === null){
            getBestNeighbor(path.currentNodeId);
        }//end while
        return path.bestPath;
    }//end pathTo
    myPath = pathTo(41);  //testing with 6
    console.log("path2:"+myPath);

最新更新