window.AStar = {}; var Constants = require('Constants'); var startMap = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]]; //全局变量用来调整的算法 //不必要的实时使用 var map, ctx, allowDiagonals, diagonalCost, dotTiebreaker, badSorting, nodesSearched, start, nextDraw = []; //初始化节点地图 AStar.Init = function init() { map = new Array; for (var i = 0; i < Constants.TileMapWith; i++) { map[i] = new Array; for (var j = 0; j < Constants.TileMapWith; j++) { //第三个参数 startMap[i][j] map[i][j] = new Node(i, j, 1); } } nodesSearched = 0; // cc.log('map', map); } AStar.setMapSolid = function (x, y, isSolid) { map[x][y].solid = isSolid; // if (x!==29&&x!==30&&isSolid == 0) // console.log(x, y, isSolid); } AStar.getMap = function () { return map; } AStar.setStart = function (value) { start = value; } // 插入排序以获得更好的优先级队列性能 Array.prototype.insertSorted = function (v, sortFn) { if (this.length < 1 || sortFn(v, this[this.length - 1]) >= 0) { this.push(v); return this; } for (var i = this.length - 2; i >= 0; --i) { if (sortFn(v, this[i]) >= 0) { this.splice(i + 1, 0, v); return this; } } this.splice(0, 0, v); return this; } // for comparison this insert sort uses > not >= thus inserting new nodes nearer the back // this provides much worse searching Array.prototype.insertSorted2 = function (v, sortFn) { if (this.length < 1 || sortFn(v, this[this.length - 1]) > 0) { this.push(v); return this; } for (var i = this.length - 2; i >= 0; --i) { if (sortFn(v, this[i]) > 0) { this.splice(i + 1, 0, v); return this; } } this.splice(0, 0, v); return this; } //初始化信息 // allowDiagonals true 是开启八方向,false 是开启四方向 // diagonalCost true 是对角线,false是关闭 // dotTiebreaker // badSorting 添加新节点或重新插入旧节点 AStar.setInitInfo = function setInfo(tallowDiagonals, tdiagonalCost, tdotTiebreaker, tbadSorting) { //允许对角线 allowDiagonals = tallowDiagonals; //调整对角线成本 diagonalCost = tdiagonalCost; //点积短路器 dotTiebreaker = tdotTiebreaker; //Prefer new nodes //首选新节点? badSorting = tbadSorting; // cc.log('this.allowDiagonals=', allowDiagonals, // 'this.diagonalCost=', diagonalCost, // 'this.dotTiebreaker=', dotTiebreaker, // 'this.badSorting=', badSorting) } //算法里面的节点 function Node(x, y, t) { this.x = x; this.y = y; this.solid = t; this.coord = x + ":" + y; this.neighbours = function (goal) { var n = []; var dir = [[0, 1], [0, -1], [1, 0], [-1, 0], [1, 1], [-1, 1], [1, -1], [-1, -1]]; for (var i = 0; i < (allowDiagonals ? 8 : 4); ++i) { //判断是否在边界外 if (this.x + dir[i][0] < 0 || this.x + dir[i][0] > Constants.TileMapWith - 1) continue; if (this.y + dir[i][1] < 0 || this.y + dir[i][1] > Constants.TileMapWith - 1) continue; var p = map[this.x + dir[i][0]][this.y + dir[i][1]]; if (p.solid && p != goal) continue; n.push(p); } // console.log('neighbours', n); return n; } } function h(a, b) { var cross = 0; if (dotTiebreaker) { var dx1 = a.x - b.x var dy1 = a.y - b.y var dx2 = start.x - b.x var dy2 = start.y - b.y var cross = Math.abs(dx1 * dy2 - dx2 * dy1) } if (allowDiagonals) { var straight = Math.abs(Math.abs(a.x - b.x) - Math.abs(a.y - b.y)); var diagonal = Math.max(Math.abs(a.x - b.x), Math.abs(a.y - b.y)) - straight; return straight + diagonalCost * diagonal + cross * 0.001; //return Math.max(Math.abs(a.x-b.x), Math.abs(a.y-b.y)); simple version } return Math.abs(a.x - b.x) + Math.abs(a.y - b.y) + cross * 0.001; } AStar.setGraphics = function (graphics) { ctx = graphics; }, AStar.pathFind = function pathFind(x, y, x2, y2) { nextDraw = []; var start = map[x][y]; var goal = map[x2][y2]; var closed = {}; var open = [start]; var g_score = {}; // 从最优路径出发的距离 var f_score = {}; // 通过节点估计从目标到目标的距离 g_score[start.coord] = 0; f_score[start.coord] = h(start, goal); var cameFrom = {}; var sortFn = function (b, a) { return f_score[a.coord] - f_score[b.coord]; }; while (open.length > 0) { var node = open.pop(); //F值最低的节点 // cc.log('node==',node); if (node == goal) { var path = [goal]; while (cameFrom[path[path.length - 1].coord]) { path.push(cameFrom[path[path.length - 1].coord]) } return path; } closed[node.coord] = true; var neighbours = node.neighbours(goal); for (var i = 0, c = neighbours.length; i < c; ++i) { var next = neighbours[i]; if (closed[next.coord]) continue; var diagonal = next.x != node.x && next.y != node.y; var temp_g_score = g_score[node.coord] + (diagonal ? diagonalCost : 1); // cc.log('temp_g_score',temp_g_score); var isBetter = false; var idx = open.indexOf(next); if (idx < 0) { isBetter = true; nodesSearched++; } else if (temp_g_score < g_score[next.coord]) { open.splice(idx, 1); // remove old node isBetter = true; } if (isBetter) { cameFrom[next.coord] = node; g_score[next.coord] = temp_g_score; f_score[next.coord] = g_score[next.coord] + h(next, goal); // add the new node or reinsert the old node if (badSorting) open.insertSorted2(next, sortFn); else open.insertSorted(next, sortFn); // drawing if (ctx) { var s = Math.floor(g_score[next.coord] * 4); ctx.fillColor = new cc.Color(255 - s, 255, s, 255); ctx.rect(next.x * 10, next.y * 10, 10, 10); ctx.stroke(); ctx.fill(); } } } } // fail return []; } function setIndex(next) { let index = 50 * next.y + next.x; nextDraw.push(index); } function isHasIndex(next) { let index = 50 * next.y + next.x; let ishas = false; for (let i = 0; i < nextDraw.length; i++) { if (index == nextDraw[i]) { ishas = true; break; } } return ishas; } AStar.Init();