【cocos creator】AStar算法实现自动寻路(JS)

寒假想用cocos creator做一个简单的小游戏,需要用到自动寻路,网上找了很久,目前最流行的使用A星(A*)算法实现,所以简单记录一下。如有错误,请指正。

目录

A*算法原理

网上A*算法原理有很多,这一篇写的很好,可以学习一下AStar

实现

理解A*算法的原理之后,开始着手进行实现,我用的引擎是cocos creator,所以使用Js语言完成。

地图的生成

Astar算法实现的原理就是根据点与点之间的距离,通过比较优先级来选择最佳路径。所以首先将地图和障碍物转化为容易区分的二维数组,选择二维数组的原因是:坐标可以用来计算,值可以反应该点是否为障碍物。为了使算法运行更快,将地图和障碍物的宽高各缩小10倍。

实现的代码:

getMapNavMesh(){
    
    
        var width = (this.map.node.width);   //地图的宽高
        var height = (this.map.node.height);
        var map = new Array();
        for(i=0;i<96;i++){
    
    
            map[i]=new Array();
            for(j=0;j<64;j++){
    
    
                map[i].push(0);
            };
        };
        //更改将障碍物所在的值
        for(i = 0;i<this.obstacles.length;i++){
    
    
            var x = parseInt((this.obstacles[i].node.x)+(width/2));
            var y = parseInt((this.obstacles[i].node.y)+(height/2));
            var obsWidth=parseInt(this.obstacles[i].node.width);
            var obsHeight =parseInt(this.obstacles[i].node.height);
            realX=parseInt((x+obsWidth)/width*96);
            realY=parseInt((y+obsHeight)/height*64);
            console.log(x,y);
            for(m=parseInt((x)/width*96);m<realX;m++){
    
    
                for(n=parseInt((y)/height*64);n<realY;n++){
    
    
                    map[m][n]=1;
                };
            }
        };
        return map;
    },

上述代码就是将地图上障碍物所在坐标的值变为1,没有障碍物的坐标值为0.

A*算法前的准备

A*算法主要是比较点之间的距离,所以自定义Point类

    //点
    Point(x, y) {
    
    
        return {
    
    
            x: x,
            y: y,
            eq: function (other) {
    
    
                return this.x == other.x && this.y == other.y;
            }
        }
    },

A*算法

AStar(map2d, startPoint, endPoint, passTag) {
    
    
        var tag = passTag || 0;
        self = this;
        var Node = function (point, endPoint, g) {
    
            //描述AStar中的节点
            var tG = g || 0;
            return {
    
    
                point: point,        //节点的坐标
                father: null,        //父节点
                g: tG,               //G值,g值在用到的时候会重新算
                h: (Math.abs(endPoint.x - point.x) + Math.abs(endPoint.y - point.y)) * 10        //计算H值
            }
        };

        return {
    
    
            map2d: map2d,
            startPoint: startPoint,
            endPoint: endPoint,
            passTag: tag,
            openList: [],        //开启表
            closeList: [],       //关闭表

            //获得openList中F值最小的节点
            getMinNode: function () {
    
    
                var currentNode = this.openList[0];
                for (var node of this.openList) {
    
    
                    if (node.g + node.h < currentNode.g + currentNode.h)
                        currentNode = node;
                }
                return currentNode;
            },

            //判断point是否在关闭表中
            pointInCloseList: function (point) {
    
    
                for (var node of this.closeList) {
    
    
                    if (node.point.eq(point))
                        return true;
                }
                return false;
            },

            //判断point是否在开启表中
            pointInOpenList: function (point) {
    
    
                for (var node of this.openList) {
    
    
                    if (node.point.eq(point))
                        return node;
                }
                return null;
            },

            //判断终点是否在关闭表中
            endPointInCloseList: function () {
    
    
                for (var node of this.closeList) {
    
    
                    if (node.point.eq(this.endPoint))
                        return node;
                }
                return null;
            },
            //搜索节点周围的点
            searchNear: function (minF, offsetX, offsetY) {
    
    
                //越界检测
                if (minF.point.x + offsetX < 0 || minF.point.x + offsetX > this.map2d.w - 1 || minF.point.y + offsetY < 0 || minF.point.y + offsetY > this.map2d.h - 1)
                    return null;
                //如果是障碍就忽略
                if (this.map2d.data[minF.point.x + offsetX][minF.point.y + offsetY] !== this.passTag)
                    return null;
                //如果在关闭表中就忽略
                var currentPoint = self.Point(minF.point.x + offsetX, minF.point.y + offsetY);
                if (this.pointInCloseList(currentPoint))
                    return null;
                //设置单位花费
                var step = 0;
                if (offsetX === 0 || offsetY === 0)
                    step = 10;
                else
                    step = 14;
                //如果不在openList中,就把它加入openList
                var currentNode = this.pointInOpenList(currentPoint);
                if (currentNode == null) {
    
    
                    currentNode = Node(currentPoint, this.endPoint, minF.g + step);
                    currentNode.father = minF;
                    this.openList.push(currentNode);
                    return null;
                }
                //如果在openList中,判断minF到当前点的G是否更小
                if (minF.g + step < currentNode.g) {
    
    
                    currentNode.g = minF + step;
                    currentNode.father = minF;
                }

            },

            //开始寻路
            start: function () {
    
    
                //1.将起点放入开启列表
                var startNode = Node(this.startPoint, this.endPoint);
                this.openList.push(startNode);
                //2.主循环逻辑
                while (true) {
    
    
                    //找到F值最小的节点
                    var minF = this.getMinNode();
                    //把这个点加入closeList中,并且在openList中删除它
                    this.closeList.push(minF);
                    var index = this.openList.indexOf(minF);
                    this.openList.splice(index, 1);
                    //搜索这个节点的上下左右节点
                    this.searchNear(minF, 0, -1);
                    this.searchNear(minF, 0, 1);
                    this.searchNear(minF, -1, 0);
                    this.searchNear(minF, 1, 0);
                    // 判断是否终止
                    var point = this.endPointInCloseList();
                    if (point) {
    
      //如果终点在关闭表中,就返回结果
                        var cPoint = point;
                        var pathList = [];
                        while (true) {
    
    
                            if (cPoint.father) {
    
    
                                pathList.push(cPoint.point);
                                cPoint = cPoint.father;
                            } else {
    
    
                                return pathList.reverse();
                            }
                        }
                    }
                    //开启表为空
                    if (this.openList.length === 0)
                        return null;
                }
            }
        }
    },

最终实现的效果:
A*算法实现的自动寻路

猜你喜欢

转载自blog.csdn.net/weixin_44794443/article/details/112603884